Skip to content

fix: correct MCPServer call_tool result type#2816

Merged
Kludex merged 5 commits into
modelcontextprotocol:mainfrom
fengjikui:fix-mcpserver-call-tool-result-shapes
Jun 20, 2026
Merged

fix: correct MCPServer call_tool result type#2816
Kludex merged 5 commits into
modelcontextprotocol:mainfrom
fengjikui:fix-mcpserver-call-tool-result-shapes

Conversation

@fengjikui

Copy link
Copy Markdown

Summary

Fixes #2695.

MCPServer.call_tool() currently advertises Sequence[ContentBlock] | dict[str, Any], but the convert_result=True path never returns a raw dict. It can return only:

  • a direct CallToolResult,
  • a Sequence[ContentBlock] for unstructured tools, or
  • a (content, structured_content) tuple for structured tools.

This PR removes the unreachable raw-dict branch in _handle_call_tool(), drops the now-unused json import, and introduces a ToolResult type alias so the public annotation and handler implementation share the same result shape.

Tests

  • uv run --frozen pytest tests/server/mcpserver/test_server.py -q
  • uv run --frozen pytest tests/server/mcpserver/test_server.py::TestServerTools::test_call_tool_returns_declared_result_shapes -q
  • uv run --frozen coverage erase && uv run --frozen coverage run -m pytest tests/server/mcpserver/test_server.py && uv run --frozen coverage combine && uv run --frozen coverage report --include='src/mcp/server/mcpserver/server.py' --fail-under=0 && UV_FROZEN=1 uv run --frozen strict-no-cover
  • uv run --frozen ruff format --check .
  • uv run --frozen ruff check .
  • uv run --frozen pyright
  • uvx --from pre-commit pre-commit run markdownlint --files docs/migration.md
  • uvx --from pre-commit pre-commit run end-of-file-fixer --files docs/migration.md src/mcp/server/mcpserver/server.py tests/server/mcpserver/test_server.py

AI assistance disclosure

I used an AI coding assistant to help trace the result shapes and draft the patch. I reviewed the final diff and ran the validation commands above locally.

@fengjikui

This comment was marked as spam.

Kludex added 4 commits June 20, 2026 16:28
Move the conversion of the internal tool-result shapes (bare content
sequence and (content, structured_content) tuple) out of the low-level
handler and into call_tool, so the public API has a single CallToolResult
return type. Type the conversion chain with a ToolResult alias and
convert_result overloads keyed on the convert_result flag, removing the
cast and type: ignore the previous approach needed.
ToolManager.call_tool forwards convert_result as a bool, never a literal,
so the Literal-keyed overloads never resolved. The overloads that matter
are on ToolManager.call_tool, which MCPServer.call_tool calls with
convert_result=True.
Have FuncMetadata.convert_result return a CallToolResult instead of the
intermediate (content, structured_content) tuple / bare content sequence
shapes. MCPServer.call_tool becomes a passthrough, and the ToolResult
alias plus the convert_result overloads on ToolManager.call_tool are no
longer needed.
@Kludex Kludex merged commit fda4c54 into modelcontextprotocol:main Jun 20, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dead code path in MCPServer._handle_call_tool and incorrect call_tool return type

3 participants