docs(server): document Err vs Ok(CallToolResult::error) visibility contract on ServerHandler::call_tool#854
Open
gregvirgin-ls wants to merge 1 commit into
Conversation
…ntract
The MCP spec separates two failure modes that surface very differently in
clients:
- Err(ErrorData) is a JSON-RPC protocol error. Most MCP clients render
it opaquely ("Tool result missing due to internal error") - the
caller does not see the message text.
- Ok(CallToolResult::error(content)) is a tool-level error. Clients
render the content; the caller reads the message.
The right shape for "the tool didn't work" is the latter, but Err is
what most handlers reach for because it looks like the natural Rust
return value. This commit adds rustdoc on both ServerHandler::call_tool
and CallToolResult::error pointing handlers at the correct shape, with
a worked example showing protocol errors (-32602 invalid_params) vs
tool errors (empty result, downstream failure).
This is the docs half of the visibility-contract ask. A follow-up may
introduce a typed ToolOutcome sum type to enforce the distinction at
compile time; this PR is the lower-risk version that unblocks the
class immediately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Pure rustdoc PR. Documents on
ServerHandler::call_toolandCallToolResult::errorthe distinction between the two failure modes the MCP spec defines, since they look identical at the Rust call site but reach the caller's UI very differently:Ok(CallToolResult::error(content))— tool-level error. Thecontentis rendered in the caller's MCP client; the user sees the message. The right shape for almost every "the tool didn't work" path.Err(McpError)— JSON-RPC protocol error. Used forMETHOD_NOT_FOUND,INVALID_PARAMS(-32602),INTERNAL_ERROR(-32603), and other unroutable-request cases. Clients render these opaquely — the caller does not see the message text.The two-failure-mode shape exists in the SDK today but isn't currently explained anywhere a handler author would notice. In practice, handlers reach for
Err(...)because it looks like the natural Rust return value, and the caller sees "Tool result missing due to internal error" instead of the actual failure reason.What this PR does
crates/rmcp/src/handler/server.rs— rustdoc on thecall_toolmethod generated byserver_handler_methods!. Explains both return paths, when each is correct, and points atCallToolResult::errorfor the worked example.crates/rmcp/src/model.rs— rustdoc onCallToolResult::errorwith a worked example contrasting:Err(McpError::invalid_params(...)).Ok(CallToolResult::error(vec![Content::text("no such row")])).Total diff: 81 lines added across the two files.
What this PR does NOT do
ToolOutcomesum type to enforce the distinction at compile time (tracked as a separate follow-up); this PR is the lower-risk docs-only version that unblocks the class immediately.call_tool; once that lands, a small follow-up doc-update PR will extend the rustdoc here to cover the new behaviour. Keeping the two changes independent so each can land on its own merit.Behaviour change
None. Pure rustdoc addition.
Test matrix
(Local verification: rebased onto current
upstream/main(v1.7.0+ tip);cargo build -p rmcp --features "client,server,macros"andcargo doc -p rmcp --features "client,server,macros" --no-depsboth succeeded. Full test/clippy matrix above not run locally — left to CI.)Downstream motivation
Multiple MCP-server consumers we've worked with built up the
Err-everywhere pattern in their handlers, then had to do a sweep when they realised callers couldn't read their error messages. The docstring is the cheapest possible intervention that prevents that sweep for future implementations.