Skip to content

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

@SHAI-Akshay-Tripathi

Description

@SHAI-Akshay-Tripathi

Summary

MCPServer._handle_call_tool in src/mcp/server/mcpserver/server.py
contains a dead isinstance(result, dict) branch, with an inline TODO
that already documents both the dead-code issue and the related
incorrect return-type annotation on MCPServer.call_tool.

I'd like to clean this up. Posting the diagnosis here first per
CONTRIBUTING.md.

Diagnosis

FuncMetadata.convert_result in
src/mcp/server/mcpserver/utilities/func_metadata.py can return exactly
three shapes (lines 105-123):

  1. CallToolResult (when the tool function returned one directly)
  2. Sequence[ContentBlock] (no output schema — via _convert_to_content)
  3. (unstructured_content, structured_content) tuple (with output schema)

Never a raw dict. So:

  • The isinstance(result, dict) branch in _handle_call_tool (lines
    325-332 on main) is unreachable. It's marked # pragma: no cover
    because tests cannot reach it.
  • MCPServer.call_tool's return-type annotation
    Sequence[ContentBlock] | dict[str, Any] (line 402 on main) is wrong:
    it advertises a dict return that cannot happen, and is missing the
    CallToolResult and tuple shapes that can happen.

Proposed fix

  1. Remove the dead isinstance(result, dict) branch.
  2. Drop the now-unused import json.
  3. Change call_tool's return type to
    CallToolResult | Sequence[ContentBlock] | tuple[Sequence[ContentBlock], dict[str, Any]]
    and document all three shapes in the docstring.

The return-type change is a breaking type-signature change for
subclasses, so this targets main (v2) per CONTRIBUTING.md.

I have the patch ready and CI-clean locally (pytest + ruff + pyright).
Happy to open the PR once this is acknowledged.

AI assistance disclosure

I used an AI assistant to help trace the call path and draft the diff.
I've reviewed every changed line, validated the diagnosis against the
source, and run the local checks myself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions