modelcontextprotocol / modelcontextprotocol/java-sdk

ServerCapabilities.logging is added unconditionally, overriding the caller's explicit capabilities

未关闭 适合新手
#1,086 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

bug P2 ready for work
主要语言
Java
星标
3.7k
派生
1.1k
平均合并
1 天 15 小时
30 天内合并 PR
9

描述

What happens

McpAsyncServer adds the logging capability to every server it builds, overriding whatever the
caller passed to .capabilities(...). There is no flag and no branch, so a server cannot decline to
advertise it.

Both constructors — the McpServerTransportProvider one and the McpStreamableServerTransportProvider
one — run:

this.serverCapabilities = features.serverCapabilities().mutate().logging().build();
Reproduction

Build a server that asks for tools only:

McpServer.sync(transport)
        .serverInfo("example", "1.0.0")
        .capabilities(ServerCapabilities.builder().tools(true).build())
        .tools(theTools)
        .build();

initialize answers:

"capabilities": { "logging": {}, "tools": { "listChanged": true } }
Evidence

Verified in the bytecode of mcp-core-2.0.0.jar rather than from source, in case the mutation was
conditional at runtime. It is not — javap -c io/modelcontextprotocol/server/McpAsyncServer.class
shows the same three calls at identical offsets in both constructors:

101: invokevirtual  // McpServerFeatures$Async.serverCapabilities:()...ServerCapabilities;
104: invokevirtual  // ServerCapabilities.mutate:()...ServerCapabilities$Builder;
107: invokevirtual  // ServerCapabilities$Builder.logging:()...ServerCapabilities$Builder;
113: putfield       // serverCapabilities
Why this is worth changing

MCP's in-protocol logging utility is deprecated as of protocol revision 2026-07-28
(SEP-2577); new
implementations SHOULD NOT adopt it. The current behaviour means every server built with this SDK
advertises the deprecated capability
, whether or not it sends notifications/message — which is
close to the opposite of what the deprecation is trying to achieve, and it makes the advertisement
useless to clients as a signal, since it is true of everyone.

It also leaves implementors with only two honest options, neither of them "follow the spec's advice":

  1. implement a deprecated feature they did not want, purely so the advertisement is not empty; or
  2. advertise a capability that does nothing, and hope no client acts on it.

Worth noting the gap is narrower than it first appears, which is why this is a small fix rather than
a design change: the SDK does implement logging/setLevel and filters on
McpServerSession.minLoggingLevel (default INFO) inside loggingNotification. So a server that
never calls loggingNotification is offering an always-empty stream rather than a broken method.
The problem is only that it cannot say so.

Suggested fix

Honour what the caller passed:

this.serverCapabilities = features.serverCapabilities();

If the unconditional .logging() is load-bearing for existing users, an opt-out on the builder would
also do — anything that lets a server say "I do not implement this". Happy to open a PR if you have a
preference between the two.

Related but not the same ask: #872 (constructors package-private, so behaviour cannot be customised
by subclassing).

Version

io.modelcontextprotocol.sdk:mcp:2.0.0, Java 21.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 McpServerTransportProvider 和 McpStreamableServerTransportProvider 的 McpAsyncServer 构造函数入手,其中 serverCapabilities 根据 features 构建。复现 issue 中的 tools-only 服务器并检查其 initialize 响应;完成的标准是,该响应反映调用方的 capabilities,且没有未请求的 logging。

由索引模型根据 Issue 内容生成。

评估

技术栈
java
领域
api, backend
Issue 类型
缺陷
难度
2/5
预计耗时
1-3 小时
活跃度
冷清
描述清晰度
描述清楚
新手友好度
68/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。