Repository navigation
CLI cannot connect to a modern server that advertises logging (sends legacy logging/setLevel) #1990
Description
Summary
The CLI cannot connect to any modern-era server that advertises the logging capability. Every command fails at connect — not just logging ones — because the client sends the legacy logging/setLevel during the post-connect sequence, and the modern wire era rejects it.
$ mcp-inspector --cli --config <catalog> --server showcase --method tools/list --format json
{"error":{"code":"error","message":"Method 'logging/setLevel' is not supported by the negotiated protocol version (wire era 2026-07-28)"}}
Reproduce
npm run test-servers:build
node test-servers/build/server-composable.js --config test-servers/configs/logging-modern-http.json
# note the announced URL, then point a catalog at it with "protocolEra": "modern"
node clients/cli/build/index.js --config <catalog> --server showcase --method tools/list --format jsontools/list is incidental — any method fails, because the failure is in connect, before the method runs.
Cause
Two things combine:
-
clients/cli/src/cli.ts:152hardcodesinitialLoggingLevel: "debug"for every CLI connection. -
core/mcp/inspectorClient.ts:1940gates the connect-time call on the server capability but not on the protocol era:// Set initial logging level if configured and server supports it if (this.initialLoggingLevel && this.capabilities?.logging) { await this.client.setLoggingLevel(this.initialLoggingLevel, this.getRequestOptions()); }
logging/setLevel is a legacy-era method. On the modern era the equivalent is the per-request _meta["io.modelcontextprotocol/logLevel"] opt-in (the modernLogLevel server field) — which is exactly what the root README documents for logging-modern-http.json:
Modern — the same tab instead shows Log Level per Request. Pick a level to opt in and the client stamps
_meta["io.modelcontextprotocol/logLevel"]on every subsequent request.
So the call is not merely rejected, it is the wrong mechanism for that era.
Scope
CLI only. initialLoggingLevel is set in exactly one place, and neither web nor TUI passes it — they drive logging through the Logs tab, which already era-splits correctly. That is why this has gone unnoticed: the showcase config is documented as a by-hand web exercise, and the web path works.
Not a regression
Verified against both SDK versions: it reproduces identically on 2.0.0-beta.5 and on 2.0.0. Found while verifying the showcase configs for #1988 / #1989, but it predates that bump and is not caused by it.
Fix
Gate the connect-time call on the negotiated era — legacy connections keep setLoggingLevel, modern ones fall through to the modernLogLevel per-request path they already have. The guard belongs in inspectorClient.ts next to the capability check rather than in the CLI, so any future caller passing initialLoggingLevel is covered too.
Acceptance criteria
-
--cliconnects tologging-modern-http.jsonatprotocolEra: "modern"andtools/listsucceeds. -
--cliagainstlogging-legacy-http.jsonstill applies the initial level vialogging/setLevel(no behavior change on legacy). - A unit test covers the era split at the
inspectorClient.tsguard, so a modern connection never emitslogging/setLevel. -
npm run cipasses.
Activity
docs: mark initialLoggingLevel as legacy-era only (#1990)
Merge pull request #2017 from modelcontextprotocol/v2/fix/1990-modern…
cliffhall commentedon Aug 15, 2026
Fixed by #2017, merged to
v2/mainas 548aa53. Closing manually —Closes #Ndoes not auto-close on a non-default base branch.fix: gate the connect-time logging/setLevel on the negotiated era (mo…