Files
mcp-tool/sse-client-example.html
nasir@endelospay.com 82d922e8bf fix
2025-07-22 22:11:18 +05:00

348 lines
9.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Laravel Healthcare MCP SSE Client</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
.section {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.response {
background: #f5f5f5;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
}
.log {
background: #e8f4f8;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
max-height: 200px;
overflow-y: auto;
}
button {
padding: 10px 20px;
margin: 5px;
background: #007cba;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: #005a87;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
input,
textarea {
width: 100%;
padding: 8px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 5px;
}
.connected {
background: #d4edda;
color: #155724;
}
.disconnected {
background: #f8d7da;
color: #721c24;
}
.message {
margin: 5px 0;
padding: 5px;
background: #fff;
border-left: 3px solid #007cba;
}
</style>
</head>
<body>
<div class="container">
<h1>🏥 Laravel Healthcare MCP SSE Client</h1>
<div class="section">
<h3>SSE Connection</h3>
<input
type="text"
id="sseUrl"
value="http://localhost:3000/sse"
placeholder="SSE Stream URL"
/>
<input
type="text"
id="messageUrl"
value="http://localhost:3000/sse/message"
placeholder="SSE Message URL"
/>
<button id="connectBtn" onclick="connectSSE()">Connect SSE</button>
<button id="disconnectBtn" onclick="disconnectSSE()" disabled>
Disconnect
</button>
<div id="connectionStatus" class="status disconnected">
Disconnected
</div>
</div>
<div class="section">
<h3>MCP Commands</h3>
<button onclick="sendInitialize()">Initialize</button>
<button onclick="sendListTools()">List Tools</button>
<button onclick="sendPing()">Ping</button>
<br /><br />
<input
type="text"
id="toolName"
placeholder="Tool Name (e.g., public_manage_login)"
value="public_manage_login"
/>
<textarea id="toolArgs" placeholder="Tool Arguments (JSON)" rows="3">
{"email": "test@example.com", "password": "password"}</textarea
>
<button onclick="sendToolCall()">Execute Tool</button>
</div>
<div class="section">
<h3>SSE Events Log</h3>
<button onclick="clearLog()">Clear Log</button>
<div id="sseLog" class="log">SSE events will appear here...</div>
</div>
<div class="section">
<h3>MCP Response</h3>
<div id="mcpResponse" class="response">
MCP responses will appear here...
</div>
</div>
</div>
<script>
let eventSource = null;
let requestId = 1;
function connectSSE() {
const sseUrl = document.getElementById("sseUrl").value;
if (eventSource) {
eventSource.close();
}
logSSEEvent("Connecting", `Attempting to connect to ${sseUrl}`);
eventSource = new EventSource(sseUrl);
eventSource.onopen = function (event) {
updateConnectionStatus(true);
logSSEEvent("Connection opened", {
readyState: eventSource.readyState,
url: sseUrl,
timestamp: new Date().toISOString(),
});
};
eventSource.onmessage = function (event) {
try {
const data = JSON.parse(event.data);
logSSEEvent("Default message", data);
} catch (e) {
logSSEEvent("Raw message", event.data);
}
};
// Handle specific MCP events
eventSource.addEventListener("mcp-initialized", function (event) {
try {
const data = JSON.parse(event.data);
logSSEEvent("MCP Initialized", data);
updateConnectionStatus(true, "MCP Protocol Ready");
} catch (e) {
logSSEEvent("MCP Init (raw)", event.data);
}
});
eventSource.addEventListener("ping", function (event) {
try {
const data = JSON.parse(event.data);
logSSEEvent("Heartbeat", data);
} catch (e) {
logSSEEvent("Ping (raw)", event.data);
}
});
eventSource.addEventListener("method-executed", function (event) {
try {
const data = JSON.parse(event.data);
logSSEEvent("Method Executed", data);
} catch (e) {
logSSEEvent("Method (raw)", event.data);
}
});
eventSource.onerror = function (event) {
logSSEEvent("Connection error", {
readyState: eventSource.readyState,
error: event,
timestamp: new Date().toISOString(),
});
// Only update status to disconnected if connection actually failed
if (eventSource.readyState === EventSource.CLOSED) {
updateConnectionStatus(false, "Connection closed");
} else if (eventSource.readyState === EventSource.CONNECTING) {
updateConnectionStatus(false, "Reconnecting...");
}
};
}
function disconnectSSE() {
if (eventSource) {
eventSource.close();
eventSource = null;
updateConnectionStatus(false);
logSSEEvent("Connection closed", "Manual disconnect");
}
}
function updateConnectionStatus(connected, customMessage = null) {
const statusDiv = document.getElementById("connectionStatus");
const connectBtn = document.getElementById("connectBtn");
const disconnectBtn = document.getElementById("disconnectBtn");
if (connected) {
statusDiv.textContent = customMessage || "Connected to SSE stream";
statusDiv.className = "status connected";
connectBtn.disabled = true;
disconnectBtn.disabled = false;
} else {
statusDiv.textContent = customMessage || "Disconnected from SSE stream";
statusDiv.className = "status disconnected";
connectBtn.disabled = false;
disconnectBtn.disabled = true;
}
}
function logSSEEvent(type, data) {
const logDiv = document.getElementById("sseLog");
const timestamp = new Date().toLocaleTimeString();
const message = document.createElement("div");
message.className = "message";
message.innerHTML = `<strong>[${timestamp}] ${type}:</strong> ${JSON.stringify(
data,
null,
2
)}`;
logDiv.appendChild(message);
logDiv.scrollTop = logDiv.scrollHeight;
}
function clearLog() {
document.getElementById("sseLog").innerHTML =
"SSE events will appear here...";
}
async function sendMCPMessage(method, params = {}) {
const messageUrl = document.getElementById("messageUrl").value;
const request = {
jsonrpc: "2.0",
method: method,
params: params,
id: requestId++,
};
try {
const response = await fetch(messageUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(request),
});
const result = await response.json();
document.getElementById(
"mcpResponse"
).innerHTML = `<pre>${JSON.stringify(result, null, 2)}</pre>`;
logSSEEvent("MCP Response", result);
return result;
} catch (error) {
const errorMsg = `Error: ${error.message}`;
document.getElementById(
"mcpResponse"
).innerHTML = `<div style="color: red;">${errorMsg}</div>`;
logSSEEvent("MCP Error", error.message);
throw error;
}
}
async function sendInitialize() {
await sendMCPMessage("initialize", {
protocolVersion: "2024-11-05",
clientInfo: {
name: "sse-web-client",
version: "1.0.0",
},
});
}
async function sendListTools() {
await sendMCPMessage("tools/list");
}
async function sendPing() {
await sendMCPMessage("ping");
}
async function sendToolCall() {
const toolName = document.getElementById("toolName").value;
const toolArgs = document.getElementById("toolArgs").value;
try {
const args = JSON.parse(toolArgs);
await sendMCPMessage("tools/call", {
name: toolName,
arguments: args,
});
} catch (error) {
document.getElementById(
"mcpResponse"
).innerHTML = `<div style="color: red;">Invalid JSON arguments: ${error.message}</div>`;
}
}
// Auto-connect on page load
window.onload = function () {
// Don't auto-connect, let user choose when to connect
};
// Clean up on page unload
window.onbeforeunload = function () {
if (eventSource) {
eventSource.close();
}
};
</script>
</body>
</html>