Skip to content

openai-mcp/1.0.0 drops mcp-session-id header between tool-call batches, causing unbounded session leak and spurious re-auth prompts #201

@SarahLacard

Description

@SarahLacard

Summary

The ChatGPT MCP connector (openai-mcp/1.0.0) does not persist the mcp-session-id header between tool-call batches. Every batch sends mcp-session-id: null, triggering a fresh initializetools/list → tool-call cycle with a new OAuth token exchange. This causes:

  1. Unbounded server-side session accumulation — 78 orphaned sessions from a single user in one process lifetime
  2. Spurious re-authentication prompts — users are asked to "Continue" / re-authorize after every few tool calls despite valid tokens with offline_access scope
  3. 7:1 auth-to-work ratio — 84 OIDC token verifications for 12 actual tool calls

Server-Side Evidence

Our MCP server emits structured JSON logs for every request. All data below is from production logs, not synthetic tests.

Capture 1: Session accumulation pattern

The connector sends mcp_session_id: null on every initialize, creating a new session each time:

{"event":"mcp_request_headers","headers":{"mcp_session_id":null,"has_authorization":true,"user_agent":"openai-mcp/1.0.0"},"method":"POST","is_initialize":true}
{"event":"session_created","session_id":"15a9bdc6-...","active_sessions":53}

Immediately after, it correctly uses the session ID for the tool call in that batch:

{"event":"mcp_request_headers","headers":{"mcp_session_id":"15a9bdc6-...","user_agent":"openai-mcp/1.0.0"},"is_initialize":false}
{"event":"mcp_tool_call","tool":"fetch","outcome":"ok","duration_ms":11}

Then it disconnects and starts over with mcp_session_id: null for the next batch:

{"event":"client_disconnected","session_id":"15a9bdc6-...","elapsed_ms":281}
// 4 seconds later:
{"event":"mcp_request_headers","headers":{"mcp_session_id":null},"is_initialize":true}
{"event":"session_created","session_id":"459e29da-...","active_sessions":54}

Capture 2: Quantified impact (14.5-minute window)

┌─────────────────────────────────┬──────────────┐
│ Metric │ Value │
├─────────────────────────────────┼──────────────┤
│ Wall-clock duration │ 14.5 minutes │
├─────────────────────────────────┼──────────────┤
│ MCP sessions created │ 20 │
├─────────────────────────────────┼──────────────┤
│ Active sessions (start → end) │ 55 → 73 │
├─────────────────────────────────┼──────────────┤
│ Tool calls completed │ 12 │
├─────────────────────────────────┼──────────────┤
│ OIDC token verifications │ 84 │
├─────────────────────────────────┼──────────────┤
│ Session ID reuse across batches │ 0 │
├─────────────────────────────────┼──────────────┤
│ DELETE requests received │ 0 │
└─────────────────────────────────┴──────────────┘

Capture 3: Worst burst

Five new sessions spawned within 34 seconds, each with mcp_session_id: null:

22:46:12Z session_created active_sessions: 68
22:46:18Z session_created active_sessions: 69
22:46:25Z session_created active_sessions: 70
22:46:34Z session_created active_sessions: 71
22:46:46Z session_created active_sessions: 72

All five had the same OAuth subject (99daa1af-...) and client ID (chatgpt-mcp-connector).

Root Cause

The connector correctly receives and uses the mcp-session-id response header within a single batch (initialize → tools/list → tool call). But it discards the session ID between batches. Each new batch starts fresh with a null session ID, forcing a complete re-initialization cycle.

Expected Behavior

Per the MCP Streamable HTTP specification, the client MUST:

  1. Persist the mcp-session-id from the initialize response
  2. Include it in all subsequent requests to the same server
  3. Send a DELETE when the session is no longer needed

The connector does none of these across batch boundaries.

Impact

  • Memory leak: Orphaned sessions accumulate until server TTL cleanup (24h) or restart
  • Auth fatigue: Users see repeated "Continue" prompts that erode trust in the MCP integration
  • OIDC pressure: 7x authentication overhead per tool call hits the identity provider unnecessarily
  • Affects all MCP servers: This is client-side behavior, not server-specific. Any MCP server using OAuth with the ChatGPT connector will see this pattern.

Environment

  • ChatGPT Plus (web, February 2026)
  • User-Agent: openai-mcp/1.0.0
  • OAuth client: chatgpt-mcp-connector
  • Identity provider: Keycloak (OIDC-compliant)
  • MCP protocol version: 2025-11-25
  • Server: Custom Streamable HTTP (Node.js/Express)

Related

Server-Side Mitigation (for other MCP server operators)

We implemented a subject-to-session replacement map that evicts the prior session when the same OAuth subject re-initializes, bounding leak to 1 session per subject. This is a workaround, not a fix — the client should persist session IDs.

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