Skip to content

Identity proxy sends the Mcp-Session-Id header twice, so affected MCP clients fail to attach (404 Session not found) #80

Description

@maxlamagna

Summary

The MCP identity proxy (mcp_proxy.py) emits the Mcp-Session-Id response header twice. Its _send_response_headers helper iterates a fixed header list that contains both the Mcp-Session-Id and mcp-session-id spellings. Python's response-header lookup is case-insensitive, so both lookups find the same session ID and the proxy sends it twice.

Clients that combine repeated response headers into a single comma-joined value receive abc123, abc123, echo that combined value as their session ID on the next request, and the MCP server answers 404 Session not found during the initialize to notifications/initialized handshake, so no tools attach. Verified affected clients: Claude Code 2.1.216 and 2.1.217, where native MCP tools silently fail to attach, and the Python MCP SDK streamable HTTP client, which fails with McpError: Session terminated. Claude Code 2.1.202 tolerated the duplicate, which hid the defect.

Reproduction

  1. Start the agentchattr server and a proxy-routed wrapper, such as Codex with the default configuration, or instantiate McpIdentityProxy directly in front of the server's /mcp endpoint.

  2. Send an initialize request to the proxy and inspect the response headers: Mcp-Session-Id appears twice with the same value. Set AGENTCHATTR_PROXY_PORT to the proxy port printed at wrapper startup (the MCP proxy: port NNNNN line) before running:

    AGENTCHATTR_PROXY_PORT=12345
    curl -i -X POST "http://127.0.0.1:${AGENTCHATTR_PROXY_PORT}/mcp" \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"repro","version":"0.0.1"}}}'
    
  3. Connect with an affected client (the Python MCP SDK streamable HTTP client, or Claude Code 2.1.216 or 2.1.217 configured through the proxy): initialize succeeds, the next request fails with 404 Session not found, and no tools attach.

Expected behavior

The proxy relays exactly one Mcp-Session-Id header, the handshake completes, and tools/list and tool calls work through the proxy for the affected clients.

Secondary defect

do_DELETE collapses every upstream HTTP error into a generic 502, which hides the real session-termination status from clients. It should relay the upstream status, body, and session header, and reserve 502 for network-level failures.

Validation

PR #79 fixes both defects and adds five regression tests: a single case-insensitive session header on initialize, session-ID preservation on follow-up POSTs, DELETE success and HTTP-error relay, and a full SDK-style initialize, notifications/initialized, tools/list lifecycle through the proxy. Verified live: Claude Code 2.1.217 attaches native tools and completes chat_read and chat_send through the patched proxy.

Related work

This is distinct from #73, which was about stale token recovery after sleep and was resolved server-side by #75.

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