Skip to content

Commit 02aacb4

Browse files
committed
Send HTTP/DELETE when disconnecting client
* In server/src/index.ts - add delete handler for /mcp endpoint - gets the server transport for the sessionId - calls terminateSession on it - removes the webapp and server transports for the sessionId from the maps - returns status 200 to the client. * In client/src/lib/hooks/useConnection.ts - import Transport - add useState for clientTransport, type Transport or null initialized to null - in connect() function - move creation of client transport down a ways, just before calling client.connect with it - immendiately efter calling client.connect, call setClientTransport with the connected transport (has to happen after, so that what's saved has the abort controller, etc. otherwise it doesn't work to save it prior. - in disconnect() function - immediately call clientTransport.terminateSession if transportType is "streamable-http" - setClientTransport to null
1 parent d0ba418 commit 02aacb4

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

client/src/lib/hooks/useConnection.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
} from "@/utils/configUtils";
4646
import { getMCPServerRequestTimeout } from "@/utils/configUtils";
4747
import { InspectorConfig } from "../configurationTypes";
48+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
4849

4950
interface UseConnectionOptions {
5051
transportType: "stdio" | "sse" | "streamable-http";
@@ -83,6 +84,9 @@ export function useConnection({
8384
const [serverCapabilities, setServerCapabilities] =
8485
useState<ServerCapabilities | null>(null);
8586
const [mcpClient, setMcpClient] = useState<Client | null>(null);
87+
const [clientTransport, setClientTransport] = useState<Transport | null>(
88+
null,
89+
);
8690
const [requestHistory, setRequestHistory] = useState<
8791
{ request: string; response?: string }[]
8892
>([]);
@@ -377,14 +381,6 @@ export function useConnection({
377381
transportType,
378382
);
379383

380-
const clientTransport =
381-
transportType === "streamable-http"
382-
? new StreamableHTTPClientTransport(mcpProxyServerUrl as URL, {
383-
sessionId: undefined,
384-
...transportOptions,
385-
})
386-
: new SSEClientTransport(mcpProxyServerUrl as URL, transportOptions);
387-
388384
if (onNotification) {
389385
[
390386
CancelledNotificationSchema,
@@ -414,7 +410,20 @@ export function useConnection({
414410

415411
let capabilities;
416412
try {
417-
await client.connect(clientTransport);
413+
const transport =
414+
transportType === "streamable-http"
415+
? new StreamableHTTPClientTransport(mcpProxyServerUrl as URL, {
416+
sessionId: undefined,
417+
...transportOptions,
418+
})
419+
: new SSEClientTransport(
420+
mcpProxyServerUrl as URL,
421+
transportOptions,
422+
);
423+
424+
await client.connect(transport as Transport);
425+
426+
setClientTransport(transport);
418427

419428
capabilities = client.getServerCapabilities();
420429
const initializeRequest = {
@@ -468,10 +477,15 @@ export function useConnection({
468477
};
469478

470479
const disconnect = async () => {
480+
if (transportType === "streamable-http")
481+
await (
482+
clientTransport as StreamableHTTPClientTransport
483+
).terminateSession();
471484
await mcpClient?.close();
472485
const authProvider = new InspectorOAuthClientProvider(sseUrl);
473486
authProvider.clear();
474487
setMcpClient(null);
488+
setClientTransport(null);
475489
setConnectionStatus("disconnected");
476490
setCompletionsSupported(false);
477491
setServerCapabilities(null);

server/src/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,33 @@ app.post("/mcp", async (req, res) => {
226226
}
227227
});
228228

229+
app.delete("/mcp", async (req, res) => {
230+
const sessionId = req.headers["mcp-session-id"] as string | undefined;
231+
console.log(`Received DELETE message for sessionId ${sessionId}`);
232+
let serverTransport: Transport | undefined;
233+
if (sessionId) {
234+
try {
235+
serverTransport = serverTransports.get(
236+
sessionId,
237+
) as StreamableHTTPClientTransport;
238+
if (!serverTransport) {
239+
res.status(404).end("Transport not found for sessionId " + sessionId);
240+
} else {
241+
await (
242+
serverTransport as StreamableHTTPClientTransport
243+
).terminateSession();
244+
webAppTransports.delete(sessionId);
245+
serverTransports.delete(sessionId);
246+
console.log(`Transports removed for sessionId ${sessionId}`);
247+
}
248+
res.status(200).end();
249+
} catch (error) {
250+
console.error("Error in /mcp route:", error);
251+
res.status(500).json(error);
252+
}
253+
}
254+
});
255+
229256
app.get("/stdio", async (req, res) => {
230257
try {
231258
console.log("New connection");

0 commit comments

Comments
 (0)