You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
addTool/removeTool throw NullPointerException when server capabilities are derived from registered features #1177
Bug description
When you build a server without .capabilities(...) and register tools with .tools(...), McpServerFeatures derives ToolCapabilities.builder().build(), which leaves listChanged as null. McpAsyncServer.addTool then evaluates if (this.serverCapabilities.tools().listChanged()) and throws NullPointerException. The tool is already added at that point. removeTool, addResource, removeResource, addResourceTemplate, addPrompt and removePrompt use the same check.
I found this while checking whether a runtime addTool sends list_changed on a server that registers its tools on the builder. The test below reproduces it on main.
This is a regression from #928 (22a0efa). In 1.1.4, McpServerFeatures derived new ToolCapabilities(false).
Environment
mcp-core 2.0.1 (also 2.0.0). Java 21.0.10 (Temurin), macOS 26.2. 1.1.4 is not affected.
Steps to reproduce
Build an McpAsyncServer or McpSyncServer with .tools(...) and without .capabilities(...).
Call addTool(...) on the built server.
The call fails with NullPointerException from McpAsyncServer.addTool.
Expected behavior addTool completes. No notifications/tools/list_changed goes out, because listChanged was not declared. A fix could use Boolean.TRUE.equals(...listChanged()), as McpAsyncServer already does for resources().subscribe().
Minimal Complete Reproducible example
Failing test in the mcp-test module, package io.modelcontextprotocol.server:
Activity