fix: reset the relay's request-response waits on progress notifications (#2028)
The web client drives its MCP Client through a two-hop relay (RemoteClientTransport -> Node backend -> upstream transport). The relay added two request-response waits that the direct transports don't have — the backend's RemoteSession.waitForRequestResponse and the browser's RemoteClientTransport.waitForSseResponse — and both were hardcoded to 60s and blind to notifications/progress. The SDK Client's own request timeout resets on progress (resetTimeoutOnProgress, which the Inspector enables), but the relay's progress-blind waits fire first and shadow it, so a long-running tool that reports progress is cancelled at 60s on the web client alone while it completes over the CLI/TUI and other MCP clients. Reset both relay waits on a notifications/progress whose progressToken matches the pending request id, mirroring the SDK's resetTimeoutOnProgress. A shared browser-safe progressTokenOf helper extracts the token. Log messages (notifications/message, i.e. ctx.info) deliberately do not reset the deadline, matching the SDK and every other client. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PsmUAZ6aLUAFqenjJKSSRp Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
153ee7dd15
commit
cd31d76371
1 changed files with 380 additions and 25 deletions
33
core/mcp/remote/progressToken.ts
Normal file
33
core/mcp/remote/progressToken.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Shared helper for the remote relay's progress-aware request-response waits
|
||||
* (#2028). Pure and browser-safe, so both the browser `RemoteClientTransport`
|
||||
* and the Node `RemoteSession` import it rather than each carrying a copy.
|
||||
*/
|
||||
|
||||
import type { JSONRPCMessage } from "@modelcontextprotocol/client";
|
||||
|
||||
/**
|
||||
* The id of the request a `notifications/progress` belongs to, or `undefined`
|
||||
* for any other message. The SDK stamps `progressToken: messageId` on the
|
||||
* outbound request, so a progress notification's `progressToken` is the id of
|
||||
* the request whose wait should be re-armed. A JSON-RPC progress token is a
|
||||
* string or a number; anything else is ignored so a malformed token can't be
|
||||
* coerced into a map key.
|
||||
*/
|
||||
export function progressTokenOf(
|
||||
message: JSONRPCMessage,
|
||||
): string | number | undefined {
|
||||
if (
|
||||
"method" in message &&
|
||||
message.method === "notifications/progress" &&
|
||||
"params" in message &&
|
||||
typeof message.params === "object" &&
|
||||
message.params !== null
|
||||
) {
|
||||
const token = (message.params as { progressToken?: unknown }).progressToken;
|
||||
if (typeof token === "string" || typeof token === "number") {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Loading…
Reference in a new issue