HTTP MCP client works in long-running sessions but fails at connect in brand-new sessions on the identical CLI version

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Aug 13, 2026

Title: HTTP MCP client works in long-running sessions but fails at connect in brand-new sessions on the identical CLI version

Summary

Connecting to a self-hosted Streamable-HTTP MCP server (Quarkus's embedded Dev UI "Dev MCP" endpoint) fails
every time from a newly started Claude Code session, but continues to work fine in sessions that were already
running before the break started -- on the exact same installed CLI binary/version. This rules out the CLI
version as the differentiator and points at something evaluated once at session startup (client-side cached
state or a server-side feature gate/rollout) rather than a code difference between versions.

Environment

  • OS: macOS (darwin), Node v26.3.0 (bundled)
  • Claude Code: native install, tested at 2.1.226, 2.1.228, 2.1.229 (all reproduce; see isolation test below)
  • MCP server under test: Quarkus 3.36.0's embedded Dev UI "Dev MCP" endpoint, Streamable HTTP transport,

configured in .mcp.json as:
``json
{
"quarkus-dev": {
"type": "http",
"url": "http://localhost:8080/q/dev-mcp"
}
}
``

Observed behavior

Every newly started session that connects to this MCP server hits a 30s connection timeout on the client side:

[DEBUG] MCP server "quarkus-dev": HTTP transport options: {"url":"http://localhost:8080/q/dev-mcp","headers":
  {"User-Agent":"claude-code/2.1.229 (sdk-cli)","Accept-Encoding":"identity"},"hasAuthProvider":true,"timeoutMs":60000}
[DEBUG] MCP server "quarkus-dev": Testing basic HTTP connectivity to http://localhost:8080/q/dev-mcp
[DEBUG] MCP server "quarkus-dev": Connection timeout triggered after 30011ms (limit: 30000ms)
[ERROR] MCP server "quarkus-dev" TelemetrySafeError: MCP server "quarkus-dev" connection timed out after 30000ms

(That specific capture was taken via claude --debug mcp inside a separately-sandboxed subprocess, so its exact
failure shape may not be identical to the reporter's normal interactive session -- included for the transport
option/version detail, not as proof of where exactly the client-side attempt stalls.)

On the server side (Quarkus), the request does reach the handler and fails while parsing it, every time a new
session tries to connect:

2026-08-13 09:43:57,840 ERROR [io.quarkus.vertx.core.runtime.VertxCoreRecorder] (vert.x-eventloop-thread-7)
Uncaught exception received by Vert.x: java.lang.ClassCastException: class java.lang.String cannot be cast to
class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
        at io.vertx.core.json.JsonObject.getInteger(JsonObject.java:475)
        at io.quarkus.devui.runtime.jsonrpc.JsonRpcRequestCreator.createWithFilter(JsonRpcRequestCreator.java:73)
        at io.quarkus.devui.runtime.jsonrpc.JsonRpcRequestCreator.mcpCreate(JsonRpcRequestCreator.java:38)
        at io.quarkus.devui.runtime.jsonrpc.JsonRpcCodec.readMCPRequest(JsonRpcCodec.java:28)
        at io.quarkus.devui.runtime.mcp.McpHttpHandler.lambda$handleMCPJsonRPCRequest$1(McpHttpHandler.java:97)

This suggests the client is sending a JSON-RPC request whose id (or a similarly-typed field) is not the JSON
number Quarkus's handler assumes -- MCP/JSON-RPC both permit id: string | number, so a client sending a string
id would be spec-legal but would trip this specific server implementation.

Isolation test (the key finding)

  1. A Claude Code session that has been running for multiple days, on CLI version 2.1.226, still connects to

this same quarkus-dev MCP server without any problem -- including after manually reconnecting the MCP
server mid-session (/mcp).

  1. claude install 2.1.226 --force followed by a brand-new terminal and a brand-new session, on the identical

reinstalled 2.1.226 binary, reproduces the failure above every time.

  1. Same result was independently reproduced on 2.1.228 (freshly pinned via claude install 2.1.228 --force,

confirmed via claude --version) and 2.1.229 (the version that first surfaced this for the reporter).

Because the exact same binary version behaves differently purely based on when the session was started, the CLI
version itself cannot be the differentiator. This also rules out anything Quarkus-side or machine-config-side
that we separately checked and confirmed unchanged (see "Ruled out" below).

Ruled out

  • Quarkus version: pinned at 3.36.0, unedited since 2026-06-05, confirmed via git history. No pom.xml changes

since. No Quarkus release since 3.36.0 (checked 3.36.1-3.36.3 patches, and 3.37.x/3.38.x/3.39.0.CR1 minors)
documents a fix touching Dev UI/Dev MCP/JSON-RPC/getInteger/ClassCastException.

  • Restarting the Quarkus quarkus:dev process: done, no change -- new sessions still fail against the fresh

process.

  • A locally-enforced managed security/sandbox policy (separately suspected and ruled out): the exception

appearing in the Quarkus server log proves the request does reach the server and gets far enough to be
parsed and crash -- this is not a blocked/intercepted connection.

  • CLI version: see isolation test above.

Leading hypothesis

Something evaluated once at session startup and then cached for the life of that session -- most likely a
server-side feature gate/rollout affecting the MCP HTTP client's request construction (e.g. how the JSON-RPC
id field is generated/typed for the Streamable HTTP transport) -- changed for newly-started sessions, while
already-running sessions keep whatever behavior they picked up at their own startup. Supporting evidence that
this kind of startup-time gate evaluation is a real, active mechanism in the client:

[DEBUG] [auto-mode] verifyAutoModeGateAccess: enabledState=enabled disabledBySettings=false ... canEnterAuto=true

(A 2.1.227 changelog entry independently confirms feature-flag evaluation happens at session start: "Fixed
feature flags being evaluated without the user's subscription tier when a session started with an expired login
token...".)

This is a guess at the mechanism, not a confirmed root cause -- we don't have a client-side capture of the
literal outgoing JSON-RPC request from a real (non-sandboxed) session showing the id field's actual type. Happy
to provide one via claude --debug mcp --debug-file <path> if it helps narrow this down further.

Ask

  • Did anything change recently in the MCP HTTP client's request construction (JSON-RPC id type/generation, or

anything else Streamable-HTTP-transport-specific) behind a gradual rollout or feature gate, independent of the
installed CLI version?

  • Separately, whether or not this is the exact mechanism: a client that always sends a spec-legal string id

would be reasonable, so the underlying Quarkus behavior (JsonRpcRequestCreator.createWithFilter assuming
id is always a JSON number) is arguably worth hardening regardless -- happy to raise that separately against
quarkusio/quarkus if useful.

View original on GitHub ↗