HTTP-transport MCP server tools unreachable ("No such tool available") despite /mcp showing connected + listing tools, persists across full app restart
Description
An HTTP-transport MCP server added via claude mcp add --transport http -s user <name> <url> --header "Authorization: Bearer <token>" shows as connected in /mcp, and /mcp's detail view correctly lists all of its tools by name. But calling any of those tools directly fails immediately with Error: No such tool available: <toolname> — the call never reaches the MCP server (no corresponding request observed server-side).
This looks related to #49152 but that issue is closed (fixed for 2.1.104→2.1.109) and this reproduces on versions outside that range.
Steps to Reproduce
claude mcp add --transport http -s user myserver https://example.com/api/mcp --header "Authorization: Bearer <token>"- Restart/reload so the new server connects
- Run
/mcp— server shows connected, tool list is shown (e.g. 5 named tools) - Ask Claude to call one of those tools, or have Claude call it directly by name
Expected
The tool call reaches the MCP server and returns a result (or a server-side error).
Actual
Immediate client-side error: Error: No such tool available: <toolname>. No request ever reaches the MCP server. ToolSearch/tool-discovery on the model side also finds nothing for the tool, even by exact name, despite /mcp showing it.
Additional notes
- Reproduced on 2.1.80 (before upgrading)
- Upgraded via
claude updateto 2.1.233 — same behavior persists - Tried multiple remediation steps between attempts, all ineffective:
- VS Code "Developer: Reload Window"
- Fully quitting and reopening VS Code (not just window reload)
- Suspect the same open chat/conversation may be getting resumed across restarts rather than the tool registry being rebuilt fresh, since no fresh MCP-server "instructions" system message (which did appear the one time this worked, immediately after the server was first added) reappeared on subsequent restarts — but
/mcpitself still reports the server as freshly connected each time. - Server confirmed independently reachable and correctly authenticating (verified via manual
curl/direct HTTP calls to the same endpoint with the same bearer token, outside of Claude Code) — not a network/auth/server-side issue. - Other MCP servers (SSE transport) in the same config work fine and are callable normally; only the HTTP-transport server exhibits this.
Environment
- Claude Code 2.1.80 → 2.1.233 (native installer,
~/.local/share/claude/versions/) - Linux
- MCP transport:
http(Streamable HTTP)
3 Comments
Update: hit a variant of this today on the same server referenced in the original report (Dozzle's HTTP-transport MCP,
--transport http).claude mcp listnow shows:So this time it's not "No such tool available" after a listed-but-unreachable tool — it's the client failing to complete
tools/listat all, right after reporting the server as connected.Confirmed server-side is completely healthy: replayed the full Streamable HTTP handshake by hand with
curl(same bearer token, same endpoint) —POST /api/mcpinitialize→ 200, returnsMcp-Session-Idheader and fullserverInfo/capabilitiesPOST /api/mcpnotifications/initialized(with the session header) → 202POST /api/mcptools/list(with the session header) → 200, returns all 5 tools with full schemasNo errors, no timeouts, clean JSON-RPC responses at every step. So the server correctly implements the initialize → notifications/initialized → tools/list handshake and session continuity — whatever's failing client-side isn't a protocol-compliance gap on the server end.
Seems like the Claude Code HTTP-transport MCP client has more than one way to fail keeping the Streamable HTTP session alive across the handshake / first real call — this session was freshly re-authenticated (a token that had previously been outright rejected, i.e. this isn't a stale-session-reuse case like the earlier report speculated).
Environment: Claude Code (native, Linux), same
--transport httpconfig style as the original report.Maintainer disclosure: I built MCP Host Canary. A narrow A/B that may help separate the two failure modes here is to create a 30-minute baseline run and add its generated URL as a second no-auth HTTP server:
Confirm
/mcplistscanary_ping, ask Claude to call it, then finalize the run. The server-side receipt records optional modernserver/discoveror the legacy initialize lifecycle,tools/list, thetools/callrequest, and actual callback execution as separate boundaries.If it stops after
tools/list.response, that independently reproduces the client registration/dispatch break against a disposable known endpoint. Ifcanary_pingexecutes while the authenticated Dozzle server still fails, the useful delta is the Bearer/session-continuity path or server-specific response behavior rather than generic HTTP tool registration.The canary is no-auth and expires after 30 minutes, so it cannot test the authenticated session path or establish root cause. Please do not post the live capability URL; only share finalized safe receipt fields.
Ran the canary A/B @sjh9714 suggested, plus a third data point against a real authenticated HTTP-transport server. Findings flip the "Bearer/session-continuity" hypothesis:
1. Canary baseline (no-auth, disposable, 3 tools) — full round-trip after fresh reload:
initialize→initialized→tools/list→tools/call.request→tools/call.executed, all 200/202. Receipt fingerprintZiK4mHQZWiUdYO4iRydhlT1j.2. Real server, direct HTTP transport (Bearer-token auth, Streamable HTTP, 5 tools):
/mcpshows it connected with named tools, same as the report above — but none of those tools ever reach the client's dispatchable tool registry, even after a full app restart (confirmed viaclaude mcp add --transport http, checked withToolSearch/direct call).3. Same server, manually replaying the identical protocol over stdio: wrote a local wrapper that does
initialize→notifications/initialized→tools/callby hand via plainurllib, holdingMcp-Session-Idacross calls, using the same Bearer token. Works every time, no drop-off.(3) rules out server, auth, and session-continuity as the cause — a plain, naive HTTP client handling the same handshake against the same server/token works fine. (1) rules out a blanket "no HTTP-transport tool call ever registers" bug. So the break looks specific to Claude Code's native HTTP-transport client under some condition this server hits and the canary doesn't (tool count, response shape, SSE framing — haven't isolated which yet).
Wrapper code for reference (secrets pulled from env, none hardcoded; internal hostname redacted):