Skip to content

Commit 62518f2

Browse files
utkarsh-dixitquuu
andauthored
fix: resolve timeout scoping bug causing ReferenceError in SSE handler (#30)
* fix: resolve timeout scoping bug causing ReferenceError in SSE handler * .changeset/busy-taxes-live.md --------- Co-authored-by: Andrew Qu <[email protected]>
1 parent cf361e0 commit 62518f2

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

.changeset/busy-taxes-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@vercel/mcp-adapter": patch
3+
---
4+
5+
Fix timeout scoping bug causing ReferenceError in SSE Handler

src/next/mcp-api-handler.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -573,17 +573,34 @@ export function initializeMcpApiHandler(
573573
headers: Object.fromEntries(req.headers.entries()),
574574
};
575575

576+
// Declare timeout and response handling state before subscription
577+
let timeout: NodeJS.Timeout;
578+
let hasResponded = false;
579+
580+
// Safe response handler to prevent double res.end()
581+
const sendResponse = (status: number, body: string) => {
582+
if (!hasResponded) {
583+
hasResponded = true;
584+
clearTimeout(timeout);
585+
res.statusCode = status;
586+
res.end(body);
587+
}
588+
};
589+
576590
// Handles responses from the /sse endpoint.
577591
await redis.subscribe(
578592
`responses:${sessionId}:${requestId}`,
579593
(message) => {
580-
clearTimeout(timeout);
581-
const response = JSON.parse(message) as {
582-
status: number;
583-
body: string;
584-
};
585-
res.statusCode = response.status;
586-
res.end(response.body);
594+
try {
595+
const response = JSON.parse(message) as {
596+
status: number;
597+
body: string;
598+
};
599+
sendResponse(response.status, response.body);
600+
} catch (error) {
601+
logger.error("Failed to parse response message:", error);
602+
sendResponse(500, "Internal server error");
603+
}
587604
}
588605
);
589606

@@ -595,13 +612,14 @@ export function initializeMcpApiHandler(
595612
);
596613
logger.log(`Published requests:${sessionId}`, serializedRequest);
597614

598-
const timeout = setTimeout(async () => {
615+
// Set timeout after subscription is established
616+
timeout = setTimeout(async () => {
599617
await redis.unsubscribe(`responses:${sessionId}:${requestId}`);
600-
res.statusCode = 408;
601-
res.end("Request timed out");
618+
sendResponse(408, "Request timed out");
602619
}, 10 * 1000);
603620

604621
res.on("close", async () => {
622+
hasResponded = true;
605623
clearTimeout(timeout);
606624
await redis.unsubscribe(`responses:${sessionId}:${requestId}`);
607625
});

0 commit comments

Comments
 (0)