Skip to content

BaseSession.send_request fails when forwarding a request received via ServerSession (envelope-fields collision) #2548

@Botschagow

Description

@Botschagow

Repro

Any time a ServerSession.incoming_messages RequestResponder.request is forwarded to a ClientSession.send_request(...) — the canonical pattern for an MCP gateway/proxy — the SDK raises:

TypeError: mcp.types.JSONRPCRequest() got multiple values for keyword argument 'jsonrpc'

Root cause

  1. In ServerSession._receive_loop, the incoming wire message is parsed via:

    self._receive_request_type.model_validate(
        message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True)
    )

    The dump of a JSONRPCRequest includes jsonrpc and id.

  2. CallToolRequest, ListToolsRequest, etc. are configured with model_config = {'extra': 'allow'}, so the envelope fields are preserved on the validated ClientRequest.

  3. When that received ClientRequest is then forwarded via BaseSession.send_request, the SDK does:

    request_data = request.model_dump(by_alias=True, mode="json", exclude_none=True)
    # ...
    jsonrpc_request = JSONRPCRequest(jsonrpc="2.0", id=request_id, **request_data)

    request_data already contains jsonrpc and idTypeError.

Workaround in consumer code

def _strip_envelope_fields(request: ClientRequest) -> ClientRequest:
    raw = request.model_dump(by_alias=True, mode="json", exclude_none=True)
    raw.pop("jsonrpc", None)
    raw.pop("id", None)
    return ClientRequest.model_validate(raw)

This is currently in production in MCP-IDS's ProxySession._handle_one.

Question

Is the extra='allow' on Request subtypes intentional? If yes, a non-breaking fix would be inside BaseSession.send_request:

request_data = request.model_dump(by_alias=True, mode="json", exclude_none=True)
request_data.pop("jsonrpc", None)
request_data.pop("id", None)
jsonrpc_request = JSONRPCRequest(jsonrpc="2.0", id=request_id, **request_data)

This preserves consumer expectations (extra fields tolerated on receive) and fixes proxy use cases without breaking anything.

Affected use cases

  • MCP gateways / proxies / IDS (a gateway is by definition a ServerSessionClientSession bridge)
  • Test harnesses that round-trip messages through both session types
  • Anything relying on ClientRequest's wire-form survival across the parse/forward boundary

SDK version observed

mcp==1.27.0. Likely reproduces on later 1.x — happy to confirm if there's a specific version you'd like tested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions