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>
33 lines
1.2 KiB
TypeScript
33 lines
1.2 KiB
TypeScript
/**
|
|
* 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;
|
|
}
|