GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add McpServerTool shortcuts for registering tools on the modern server by bhuvnsh · Pull Request #1271 · modelcontextprotocol/java-sdk

Conversation

@bhuvnsh

@bhuvnsh bhuvnsh commented Oct 24, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Part of #1200. Tools only for now.

Motivation and Context

Today, adding a single tool to the modern server means writing a whole McpSyncToolRepository (a name map, list/find/call, cursor handling), wrapping it in ToolsFeature.ofSync(...) and registering that feature. That's a lot of ceremony for what is usually one function. ModernConformanceServlet carries a fair bit of boilerplate for the same reason.

This adds a shortcut for the common case:

McpServer.builder()
    .serverInfo(info)
    .tool(McpServerTool.sync(greet, (ctx, request) -> greet(request)))
    .tool(McpServerTool.syncStreaming(count, (ctx, request, notifier) -> count(notifier)))
    .build();

McpServerTool is a Tool plus its handler, with sync, syncStreaming, async and asyncStreaming factories. The builder collects the tools into a small package-private in-memory repository and serves it through the regular ToolsFeature. Input/output schema validation and everything else in the feature still applies. If you need the same thing as an explicit feature, for example to set cache hints, there's ToolsFeature.ofTools(...).

A few mistakes now fail when you register the tool instead of when a request comes in:

  • duplicate tool names;
  • invalid tool names, checked by ToolNameValidator as the legacy builder does;
  • mixing tool(...) with another feature that serves tools/*. The error names tool(...) instead of "served by both ToolsFeature and ToolsFeature".

How Has This Been Tested?

I added ToolRegistrationComparisonTests. It registers the same three tools twice, once through a hand-written repository and once through tool(...). One tool is plain, one streams progress, and one asks the user for input. The test checks that both servers answer the same way for:

  • listing and calling tools;
  • schema validation failures;
  • unknown tools and bad cursors;
  • the input-required round trip;
  • progress streaming.

There are also focused tests in McpServerToolTests (the four factories, which thread a sync handler runs on, errors, output schema checks and ofTools) and new builder tests in McpServerTests.

./mvnw -pl mcp-core test passes locally, and so do the modern server tests in mcp-test with both the Jackson 3 and Jackson 2 profiles. I also ran the conformance suite (0.2.0-alpha.12, --requirements 2026-07-28) against the modern conformance server. It exits 0, and the only failures are the tasks-* and http-custom-header-server-validation scenarios, which aren't scored and are already listed in VALIDATION_RESULTS.md. I haven't run the full clean verify.

Breaking Changes

None. The change only adds new API.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

I kept this to tools on purpose, so the shape can be discussed in #1200 before I do the same for prompts, resources, templates and completions. The conformance server's tools now use the shortcut, so its hand-written tool repository is gone. One small difference there: the old repository ignored a tools/list cursor, and now a cursor is rejected as invalid params, as the repository contract says.

I also left out a .tool(Tool, handler) overload. Sync and async versions with the same lambda shape don't compile side by side (the call is ambiguous), so the builder takes an McpServerTool instead.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bhuvnsh @claude
Add McpServerTool shortcuts for registering tools on the modern server
dfc589d
Registering one tool on the modern server meant implementing a whole
McpSyncToolRepository, wrapping it in a ToolsFeature and registering the
feature. McpServer.Builder#tool now takes an McpServerTool (a Tool and
its handler) and serves all of them through one ToolsFeature built at
build(), so argument and output validation still apply.

Duplicate and invalid tool names fail at registration, and combining
tool(...) with another feature serving tools/* fails build() with a
message naming the shortcut. ToolsFeature.ofTools(...) serves a fixed
set of tools for users who need custom cache hints or a validator.

Tools only; prompts, resources, templates and completions would follow
the same shape. See modelcontextprotocol#1200.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@bhuvnsh bhuvnsh mentioned this pull request Oct 24, 2026
Simplify registering tools, resources and prompts on the modern server #1200
Open
@bhuvnsh @claude
Harden McpServerTool shortcuts and use them in the conformance server
3a47461
Document threading, error handling and name validation on McpServerTool,
and give it a toString. Add focused tests for the four handler factories
(including which thread a sync handler runs on), error mapping,
output-schema checks and ToolsFeature.ofTools, plus builder tests for
duplicate names, the tools/* conflict check, the advertised capability
with and without subscriptions, and the builder's schema validator.

ModernConformanceServlet now registers its tools through
McpServer.Builder#tools instead of a hand-written McpSyncToolRepository.
The 2026-07-28 conformance suite passes as before. The one behaviour
change is that a tools/list cursor, which the old repository ignored, is
now rejected as invalid params.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@bhuvnsh bhuvnsh closed this Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@bhuvnsh
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.