[BUG] HTTP MCP client drops Mcp-Session-Id header — tools/list fails on session-aware servers (mcp-grafana, mcp-go) despite ✓ Connected

Open 💬 1 comment Opened Jun 23, 2026 by shpp-abelokon

Summary

When registering an HTTP-transport MCP server that uses the MCP Streamable HTTP session model (server assigns Mcp-Session-Id on the initialize response and expects clients to echo it on subsequent requests), Claude Code's MCP HTTP client does not appear to propagate this header. The result:

  • claude mcp list reports ✓ Connected — because the initial handshake succeeds
  • Tools never surface in any Claude Code session — because tools/list is rejected server-side with Invalid session ID

I confirmed via raw curl against the same server, same network path, same auth, that the full tool catalog returns the moment Mcp-Session-Id is included on tools/list. So this is not a server / network / auth issue — it's missing session-header propagation in the client.

Expected behavior

Per MCP Streamable HTTP — session management spec:

"If the server returns a Mcp-Session-Id header in the initialize response, the client must include this header in all subsequent HTTP requests."

Claude Code's HTTP MCP client should:

  1. After receiving the initialize response, scan response headers for Mcp-Session-Id
  2. Persist that value in the per-server session state
  3. Include Mcp-Session-Id: <uuid> on every subsequent JSON-RPC request to that server (tools/list, tools/call, notifications)

Actual behavior

  • claude mcp add --transport http <name> <url> -s user → succeeds
  • claude mcp list<name>: <url> (HTTP) - ✓ Connected
  • Inside any Claude Code session, the server's tools never appear (ToolSearch with <name> keyword returns nothing)
  • Restarting Claude Code (full quit + new session) does not help
  • Server logs / direct curl confirm tools/list requests arrive without Mcp-Session-Id, so the server rejects them with Invalid session ID

Reproducer (3 minimal curls — works against any mcp-go HTTP server with session management, including mcp-grafana)

Step 1. initialize — note mcp-session-id in response headers:

curl -i -X POST https://<your-mcp-server>/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}},"id":1}'

Response:

HTTP/2 200
content-type: application/json
mcp-session-id: mcp-session-b773c0a7-a7ba-4b15-b403-44d603c2b1da   ← server assigns this
...
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"mcp-grafana","version":"(devel)"},...}}

Step 2. tools/list WITHOUT session header — fails:

curl -X POST https://<your-mcp-server>/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":2}'

Response:

Invalid session ID

This is what Claude Code is doing (deduced from observation: server is healthy and tools never reach the session).

Step 3. tools/list WITH the session header from step 1 — succeeds:

curl -X POST https://<your-mcp-server>/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H "Mcp-Session-Id: mcp-session-b773c0a7-a7ba-4b15-b403-44d603c2b1da" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":2}'

Response:

{"jsonrpc":"2.0","id":2,"result":{"tools":[
  {"name":"add_activity_to_incident",...},
  {"name":"alerting_manage_routing",...},
  {"name":"alerting_manage_rules",...},
  ... 58 tools total
]}}

Environment

  • Claude Code: 2.1.176
  • OS: macOS Darwin 24.2.0 arm64
  • Transport: --transport http
  • Server tested: mcp-grafana (Go, devel build), self-reporting protocolVersion: "2024-11-05", exposing 58 tools
  • Network path is behind Cloudflare Access + WARP Zero Trust, but I've verified end-to-end via raw curl that Mcp-Session-Id propagates cleanly through that stack (same path the working step-3 curl above goes through)

Impact

Any MCP server that implements MCP 2024-11-05 / 2025-03-26 Streamable HTTP session management is currently unusable in Claude Code, despite reporting ✓ Connected. That includes (at minimum):

  • mcp-grafana — 58 tools blocked (Grafana / Prometheus / Loki / dashboards / alerting / OnCall / Pyroscope / annotations / API)
  • Likely any other mcp-go-based HTTP server that opts into session management

Workaround

Direct service API via Bash + curl + service-account token. Lost the MCP tool integration but PromQL / dashboard reads still possible. Not a substitute for stateful operations.

Suggested fix area

The Claude Code HTTP MCP client needs to track and inject Mcp-Session-Id per connected server. This appears adjacent to but distinct from #62008 (recovery from 404 session-not-found): #62008 implies the client does send a session id (otherwise it wouldn't get 404 — server would return Invalid session ID), whereas in this report the client appears to never send the header at all on the first request after initialize.

I'm happy to capture claude --debug logs for a fresh handshake against mcp-grafana on request — that should confirm exactly what's serialized on the wire.

References

  • MCP Streamable HTTP transport — session management — clause 4 of session management
  • #62008 — related: client doesn't re-initialize after HTTP 404 session-not-found (a different facet — session id is sent but stale; here, session id appears never sent)
  • #67194 — related: stateless server's GET 405 mis-correlated to tools/list (different transport variant; same general "tools/list never reaches user" symptom from a different cause)
  • mcp-grafana: https://github.com/grafana/mcp-grafana
  • mcp-go (HTTP transport with session management — likely upstream for many affected servers): https://github.com/mark3labs/mcp-go

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗