Describe the bug
On a session negotiated at 2026-07-28, ClientSession.SetLoggingLevel sends logging/setLevel with the MCP-Protocol-Version: 2026-07-28 header but without the SEP-2575 per-request _meta fields. It is the only Modern-eligible client call that does not inject them.
A server that validates header/_meta consistency — as the Streamable HTTP "Server Validation" rules require — sees a Modern protocol header alongside an empty _meta protocol version and must reject the request. So a Modern client cannot call logging/setLevel against a conformant server at all.
Cause
Every other Modern-eligible client method guards on cs.usesNewProtocol() and calls injectRequestMeta, e.g. ListResources (mcp/client.go:1309):
func (cs *ClientSession) ListResources(ctx context.Context, params *ListResourcesParams) (*ListResourcesResult, error) {
if cs.usesNewProtocol() {
if result, ok := cachedListResult(&cs.resourcesCache, params); ok {
return result, nil
}
params = injectRequestMeta(cs, params)
}
result, err := handleSend[*ListResourcesResult](ctx, methodListResources, newClientRequest(cs, orZero[Params](params)))
...
SetLoggingLevel (mcp/client.go:1303-1306) has no such guard:
func (cs *ClientSession) SetLoggingLevel(ctx context.Context, params *SetLoggingLevelParams) error {
_, err := handleSend[*emptyResult](ctx, methodSetLevel, newClientRequest(cs, orZero[Params](params)))
return err
}
The injectRequestMeta call sites in mcp/client.go are lines 1236, 1251, 1262, 1290, 1314, 1332, 1354, 1368, 1452, and 1676. SetLoggingLevel is absent from that list.
The header itself is still set by the streamable transport, so the two disagree on the wire: header says 2026-07-28, _meta[io.modelcontextprotocol/protocolVersion] (mcp/protocol.go:2363) is missing.
To Reproduce
- Serve a Streamable HTTP server that validates header/
_meta protocol-version consistency.
- Connect a
Client so it negotiates 2026-07-28 via server/discover.
- Call
cs.SetLoggingLevel(ctx, &SetLoggingLevelParams{Level: "debug"}).
Observed:
calling "logging/setLevel": sending "logging/setLevel":
MCP-Protocol-Version header "2026-07-28" does not match _meta protocol version "": Bad Request
Expected behavior
Either the request carries the SEP-2575 _meta triple like every other Modern-eligible call, or the client declines to send it with a clear error — but not a request that cannot validate.
Suggested fix
Smallest change, matching the sibling idiom:
func (cs *ClientSession) SetLoggingLevel(ctx context.Context, params *SetLoggingLevelParams) error {
if cs.usesNewProtocol() {
params = injectRequestMeta(cs, params)
}
_, err := handleSend[*emptyResult](ctx, methodSetLevel, newClientRequest(cs, orZero[Params](params)))
return err
}
Refusing client-side is also a legitimate resolution rather than a cop-out, and worth considering on its merits: SetLoggingLevel is already marked Deprecated for exactly this revision — its doc comment cites SEP-2577's deprecation of logging and points at consuming stderr or OpenTelemetry instead. If the intent is that logging/setLevel is Legacy-only, then returning a descriptive error on a Modern session is more honest than emitting a request the peer must reject, and it gives callers something actionable. What is hard to justify is the current middle state, where the call is advertised as functional during the deprecation window but cannot succeed against a conformant Modern server.
Note that SEP-2577 says the feature "remains functional during the deprecation window (at least twelve months)", which reads as favouring the injection fix — the deprecation is about discouraging new use, not about breaking the call.
Additional context
Found while implementing the MCP 2026-07-28 client-facing surface in a stateless proxy built on this SDK (a virtual MCP server that aggregates several backends and serves both revisions). Our revision classifier rejects the header/_meta mismatch with -32020, which is what surfaced it; the same request would be rejected by any server enforcing that consistency rule.
Related to #1112 and #1113, both from adopting v1.7.0-pre.3 in the same shim. Happy to send a PR for either resolution, and to supply a standalone repro (small server enforcing the consistency check, plus a client that negotiates Modern) if useful.
Describe the bug
On a session negotiated at
2026-07-28,ClientSession.SetLoggingLevelsendslogging/setLevelwith theMCP-Protocol-Version: 2026-07-28header but without the SEP-2575 per-request_metafields. It is the only Modern-eligible client call that does not inject them.A server that validates header/
_metaconsistency — as the Streamable HTTP "Server Validation" rules require — sees a Modern protocol header alongside an empty_metaprotocol version and must reject the request. So a Modern client cannot calllogging/setLevelagainst a conformant server at all.Cause
Every other Modern-eligible client method guards on
cs.usesNewProtocol()and callsinjectRequestMeta, e.g.ListResources(mcp/client.go:1309):SetLoggingLevel(mcp/client.go:1303-1306) has no such guard:The
injectRequestMetacall sites inmcp/client.goare lines 1236, 1251, 1262, 1290, 1314, 1332, 1354, 1368, 1452, and 1676.SetLoggingLevelis absent from that list.The header itself is still set by the streamable transport, so the two disagree on the wire: header says
2026-07-28,_meta[io.modelcontextprotocol/protocolVersion](mcp/protocol.go:2363) is missing.To Reproduce
_metaprotocol-version consistency.Clientso it negotiates2026-07-28viaserver/discover.cs.SetLoggingLevel(ctx, &SetLoggingLevelParams{Level: "debug"}).Observed:
Expected behavior
Either the request carries the SEP-2575
_metatriple like every other Modern-eligible call, or the client declines to send it with a clear error — but not a request that cannot validate.Suggested fix
Smallest change, matching the sibling idiom:
Refusing client-side is also a legitimate resolution rather than a cop-out, and worth considering on its merits:
SetLoggingLevelis already markedDeprecatedfor exactly this revision — its doc comment cites SEP-2577's deprecation of logging and points at consuming stderr or OpenTelemetry instead. If the intent is thatlogging/setLevelis Legacy-only, then returning a descriptive error on a Modern session is more honest than emitting a request the peer must reject, and it gives callers something actionable. What is hard to justify is the current middle state, where the call is advertised as functional during the deprecation window but cannot succeed against a conformant Modern server.Note that SEP-2577 says the feature "remains functional during the deprecation window (at least twelve months)", which reads as favouring the injection fix — the deprecation is about discouraging new use, not about breaking the call.
Additional context
Found while implementing the MCP 2026-07-28 client-facing surface in a stateless proxy built on this SDK (a virtual MCP server that aggregates several backends and serves both revisions). Our revision classifier rejects the header/
_metamismatch with-32020, which is what surfaced it; the same request would be rejected by any server enforcing that consistency rule.Related to #1112 and #1113, both from adopting
v1.7.0-pre.3in the same shim. Happy to send a PR for either resolution, and to supply a standalone repro (small server enforcing the consistency check, plus a client that negotiates Modern) if useful.