Skip to content

server/discover advertises deprecated logging unconditionally, but logging/setLevel rejects 2026-07-28+ with MethodNotFound #1774

Description

@bseekford-st

Summary

server/discover advertises the deprecated logging capability unconditionally, while the logging/setLevel handler rejects 2026-07-28+ requests with MethodNotFound. Since server/discover only exists on 2026-07-28+, the server advertises a capability whose only method it refuses to serve on the very era doing the asking.

There is also no way for a server author to opt out.

Detail

McpServerImpl.ConfigureLogging is called unconditionally from the constructor and does:

ServerCapabilities.Logging = new();

with no guard — not on Handlers.SetLoggingLevelHandler being non-null, not on protocol version, not on any option.

The same method's handler then rejects the modern era:

if (IsJuly2026OrLaterProtocolRequest(jsonRpcRequest))
{
    throw new McpProtocolException(
        $"The method '{RequestMethods.LoggingSetLevel}' is not available on protocol version '...'. Use per-request _meta/{MetaKeys.LogLevel} instead.",
        McpErrorCode.MethodNotFound);
}

So a 2026-07-28 client reading capabilities.logging from server/discover and calling logging/setLevel gets MethodNotFound.

Why a server author cannot work around it

McpServerOptions.Capabilities is not the source of the advertised set. McpServerImpl builds its own ServerCapabilities = new() and reads only two members from options (Experimental, Extensions); everything else is derived from registrations. Measured against 2.0.0 on a stateless HTTP server:

Attempt Result
caps.Logging = null in PostConfigure<McpServerOptions> MCP9005 compile error — the analyzer forbids touching the member even to clear it
Same, with a scoped #pragma warning disable MCP9005 No effect; options.Capabilities is null at PostConfigure time
options.Capabilities = new ServerCapabilities() No wire change — {"logging":{},"tools":{}}
options.Capabilities = new ServerCapabilities { Tools = new ToolsCapability() } No wire change

Legacy initialize advertises logging identically, and identically on 1.4.1 — so this is long-standing rather than a 2.0.0 regression.

The only remaining lever is overriding server/discover via the [Experimental] McpServerOptions.RequestHandlers, which requires re-deriving SupportedVersions from the private _perRequestMetadataProtocolVersions and taking ownership of a MUST endpoint.

Impact

For a server that deliberately does not adopt deprecated features, the advertised capability set is not something it can make true. A client may reasonably call a method the advertisement promised.

Possible resolutions

  1. Guard ServerCapabilities.Logging on the negotiated/least-supported protocol version, so 2026-07-28-only servers do not advertise it.
  2. Set it only when Handlers.SetLoggingLevelHandler is non-null — the level is still stored either way, and it makes the advertisement reflect a real handler.
  3. Honour an explicit options.Capabilities.Logging = null as a suppression signal (needs a non-[Obsolete] opt-out so it does not trip MCP9005).

Happy to send a PR for whichever shape you prefer.

Environment

ModelContextProtocol 2.0.0, net10.0, stateless Streamable HTTP, MCP-Protocol-Version: 2026-07-28.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions