vercel/ai · error · MCPClientError

Protocol error: Received a response for an unknown message I

Error message

Protocol error: Received a response for an unknown message ID: ${JSON.stringify(response)}

What it means

The transport received a JSON-RPC response whose id has no registered pending handler in this.responseHandlers. This breaks the JSON-RPC request/response correlation, so DefaultMCPClient throws MCPClientError. It almost always means the response came from a different/previous connection, the client reconnected (losing pending handlers), or the server sent a malformed or duplicate response.

Source

Thrown at packages/mcp/src/tool/mcp-client.ts:1523

  }

  private onResponse(response: JSONRPCResponse | JSONRPCError): void {
    if (response.id == null) {
      this.onError(
        new MCPClientError({
          message: `Protocol error: Received a response without a message ID: ${JSON.stringify(
            response,
          )}`,
        }),
      );
      return;
    }

    const messageId = Number(response.id);
    const handler = this.responseHandlers.get(messageId);

    if (handler === undefined) {
      throw new MCPClientError({
        message: `Protocol error: Received a response for an unknown message ID: ${JSON.stringify(
          response,
        )}`,
      });
    }

    this.responseHandlers.delete(messageId);

    handler(
      'result' in response
        ? response
        : new MCPClientError({
            message: response.error.message,
            code: response.error.code,
            data: response.error.data,
            cause: response.error,
          }),
    );

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Ensure a single connection per client: recreate the MCPClient (or call connect again) after any disconnect instead of reusing a stale transport
  2. Verify no proxy or middleware rewrites or duplicates JSON-RPC message ids; log raw messages to confirm the id actually was requested
  3. Check that request timeouts/reconnect logic tears down pending handlers together with the connection, so stale responses can't be matched to a fresh session
  4. Update the MCP server/SDK if it is known to send malformed ids (e.g. string ids that don't parse to the same number)

Example fix

// before
const client = await createMCPClient({ transport }); // reused after reconnect
// after
client.close();
const client = await createMCPClient({ transport: freshTransport }); // new session per connect
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure exactly one active client per server session before issuing requests
if (activeClient && activeClientClosed) { activeClient = await createMCPClient({ transport: newTransport() }); }

Type guard

function isUnknownMessageIdError(e: unknown): boolean {
  return MCPClientError.isInstance(e) && e.message.includes('unknown message ID');
}

Try / catch

try {
  result = await client.callTool(args);
} catch (error) {
  if (isUnknownMessageIdError(error)) {
    await client.close();
    client = await createMCPClient({ transport: newTransport() }); // fresh session, then retry once
  } else throw error;
}

Prevention

When it happens

Trigger: Server sends a response with an id never requested (duplicate/replayed message), the client's transport reconnected and cleared responseHandlers while the server still replies to old ids, an id type mismatch (e.g. string vs number id such that Number(response.id) doesn't match the registered key), or responses interleave across two connections to the same server.

Common situations: Proxy/load-balanced MCP endpoints routing responses from a different session; server restarts mid-request; custom transports or middleware rewriting message ids; long-running requests outliving a reconnect after a network blip.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/d5b278e13d479855. Report an issue: GitHub.