Skip to content

Positional-only handler parameters break tools, prompts and resource templates #3760

Open

Description

@PerryLink

Handlers registered with a positional-only parameter (def echo(x: str, /)) are accepted and advertised, but every call fails, for tools, prompts and resource templates alike.

Reproduction

from mcp.server.mcpserver import MCPServer
from mcp import Client

mcp = MCPServer("posonly")

@mcp.tool()
def echo(x: str, /) -> str:
    return f"got:{x}"

async with Client(mcp) as client:
    result = await client.call_tool("echo", {"x": "hi"})

Actual: tools/list advertises {"properties": {"x": {"type": "string"}}, "required": ["x"]}, but the call returns is_error=True with Error executing tool echo; the server logs TypeError: echo() got some positional-only arguments passed as keyword arguments: 'x'.

The same happens for prompts (def greet(name: str, /) → client.get_prompt raises MCPError: Internal server error, log ValueError: Error rendering prompt greet) and resource templates (@mcp.resource("posonly://{name}") def read(name: str, /) → MCPError: Error creating resource from template posonly://thing).

Expected: got:hi, the rendered prompt, and the resource content respectively.

Cause

The handlers are invoked with keyword arguments only:

  • src/mcp/server/mcpserver/utilities/func_metadata.py (call_fn: fn(**kwargs) / functools.partial(fn, **kwargs))
  • src/mcp/server/mcpserver/prompts/base.py (Prompt.render: same)
  • src/mcp/server/mcpserver/resources/templates.py (ResourceTemplate.create_resource: same)

There is no POSITIONAL_ONLY handling anywhere in src. The tool/prompt/resource input schemas are derived from the type hints, so the parameter is advertised as required and then cannot be bound.

A positional-only parameter is valid Python and the docs describe the handler signature as "just Python" (docs/servers/tools.md), so either the parameters should be bound positionally (a small helper that splits the leading positional-only run out of the kwargs dict, using declared defaults when omitted) or registration should reject positional-only parameters instead of advertising an uncallable handler.

Happy to prepare the binding change if maintainers want it — not opening a PR because the contributing guide asks for an assigned issue first.

Activity

  1. added
    bugSomething isn't working
    v2Affects the v2 line (2.x on main)
    v1Affects the v1.x maintenance line
    on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingv1Affects the v1.x maintenance linev2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions