Skip to content

MCP accepts duplicate post-handshake responses for one request #330

Description

@Calmingstorm

Failure sequence

  1. Connect to a legacy MCP server negotiated at 2025-03-26, where receive-side JSON-RPC batches are allowed.
  2. Odin sends a post-handshake request such as tools/list with ID 7.
  3. The server returns one legal batch frame containing two response objects with ID 7, for example one result with marker: \"first\" and a second with marker: \"second\".
  4. On stdio, the first response resolves the pending future and the second is logged as late/unknown. On HTTP, _match_response() selects the first matching object and the remaining matching response is dispatched without triggering a protocol failure. The request completes using marker: \"first\" instead of rejecting the duplicate response sequence.

The same defect also applies to duplicate matching response events in an HTTP SSE stream: the callback overwrites the previously collected response and accepts one after the stream closes.

A server can therefore provide contradictory results for one request without invalidating discovery or a tool call. During discovery, this can make the published catalog depend on response ordering instead of rejecting the malformed exchange.

Sites

  • src/tools/mcp/client.py:392-420 resolves a stdio future once and drops another response with the same pending ID.
  • src/tools/mcp/client.py:611-616 returns the first matching HTTP response without checking cardinality.
  • src/tools/mcp/client.py:975-1007 overwrites streamed matches and routes extra JSON-body matches without detecting duplicates.

Handshake traffic already rejects duplicate matching responses at src/tools/mcp/client.py:508-516; post-handshake requests should enforce the same one-response-per-request invariant.

Expected

If more than one response matches a post-handshake request ID, fail that request with MCPProtocolError and do not publish or execute from either result.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions