fix(mcpserver): ignore the return annotation when finding the context parameter - #3301
Conversation
… parameter `find_context_parameter` iterated every entry from `typing.get_type_hints`, which includes the return annotation under the special `"return"` key. A tool, prompt, or resource function annotated `-> Context` (or a union containing it) was therefore recorded as having a context parameter named `"return"`, and the handler failed at invocation with `got an unexpected keyword argument 'return'`. Drop the `"return"` key before scanning, so only real parameters are considered. Fixes modelcontextprotocol#3298 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for the contribution. This repository only keeps pull requests open when they're linked to an issue that a maintainer has assigned to the author — CONTRIBUTING.md explains why and how we work. This PR has been closed for now because you aren't currently assigned to #3298. If a maintainer would like this change as a PR from you, they'll assign you to #3298 and this PR will reopen automatically — there's nothing more you need to do. (If you opened the issue, this PR already shows up on its timeline.) There's no need to open a new PR — this one will be reopened. While it's closed, please push any updates as new commits rather than force-pushing, since GitHub can't reopen a PR whose branch has been rewritten. Maintainers: reopening this PR, removing the |
Fixes #3298
What's wrong
find_context_parameter()loops over everythingtyping.get_type_hints()returns. Thatmapping includes the function's return annotation under the special
"return"key, whichisn't a parameter.
So a handler annotated
-> Context(or a union containing it) gets recorded as having acontext parameter named
"return", and the context is injected under that name when thehandler is called.
returnis a keyword and can't be declared as a parameter, so the callalways fails — registration succeeds and the breakage only shows up at invocation time.
It isn't only tools: prompts and resource templates resolve their context through the same
function. Reverting just
context_injection.pyand exercising one of each:The fix
Drop the
"return"key before scanning the hints, so only real parameters are considered.Why this should be safe
Every path that previously resolved to
"return"failed at invocation, so nothing couldhave been depending on it — this only turns a guaranteed failure into working behaviour.
Handlers that have both a real
Contextparameter and aContextreturn annotation werealready fine, because
get_type_hints()yields parameters beforereturn(you get['a', 'ctx', 'b', 'return']fordef f(a, ctx, b) -> Context). I've pinned that orderingin a test so a later refactor can't quietly break it.
Tests
New
tests/server/mcpserver/test_context_injection.py:Contextis found)-> Contextisn't reported as a parameter-> Context | Noneisn't reported as a parameterContextparameter still wins when the return annotation is alsoContextClient(server)for a tool, a prompt and a resource templateFive of the seven fail without the
src/change../scripts/testpasses (100% branch coverage,strict-no-coverclean), ruff and pyrightare clean on the changed files, and the new tests pass on 3.10 and 3.14.
Related PRs
No overlap with #3236 or #2623, which touch the same module for unrelated reasons. I
test-merged both against this branch and neither conflicts.
Disclosure: I used AI assistance (Claude Code) for this change. I've reviewed it myself
and can explain it.