Repository navigation
Simplify registering tools, resources and prompts on the modern server #1200
Description
Problem
On the modern server (io.modelcontextprotocol.modern.server), exposing a single tool means building three layers by hand. McpFeature is the first-class unit of composition: McpServer dispatches by method name to whichever feature serves it. The built-in features (ToolsFeature, ResourcesFeature, PromptsFeature, CompletionsFeature) each wrap a user-implemented repository. The repository is the only place where a user's actual tool logic lives.
To add one tool, a user must currently:
- Implement
McpSyncToolRepository(orMcpAsyncToolRepository), which has three methods:list(ctx, cursor),find(ctx, name)andcall(ctx, request). - Wrap that repository in a feature:
ToolsFeature.ofSync(repository). - Register the feature on the server:
McpServer.builder().feature(...).
The same applies to resources (including templates) and prompts.
Why this is cumbersome
- The repository is a catalogue interface, not a tool interface. Users must implement
list,findandcallthemselves. That means holding their own name → tool map, producingToolsPageresults, handling cursors (an unrecognized cursor must be an invalid-params error) and keepinglistandfindconsistent with each other. None of this is specific to the tool they want to write. - The common case is one tool == one function. The API makes no distinction between that and a dynamic, database-backed catalogue, so the simple case pays the full cost of the general one.
- Boilerplate shows up in our own code.
ModernConformanceServlethand-rolls aConformanceTools implements McpSyncToolRepositorywith an internal entry map and wrapper helpers (add(...),respond(...),stream(...)) just to register a handful of tools. Resources and prompts get the same treatment. - Three concepts to learn before the first tool works. Users need to understand feature, repository and handler, plus how
ofSync/ofAsyncrelate them.McpFeature, whose contract ismethods(),handle(ctx, params)andcapabilities(builder), is a protocol-level abstraction. It isn't something users should need to meet to register a tool.
Compared with the previous server API
The existing server API lets users register a tool as a specification (tool definition plus handler) with one builder call. The modern API has no equivalent shortcut. Moving to it makes the simplest use case noticeably heavier.
Desired outcome
Registering a tool, resource or prompt on the modern server should take roughly as much code as the thing being registered. Users shouldn't have to implement a repository or know about McpFeature for the common case. The explicit feature and repository model should stay available for advanced cases, such as dynamic catalogues, custom pagination and extensions.
Scope
- Tools, resources, resource templates, prompts and completions on the modern server
- Sync and async variants
Activity