Skip to content

find_context_parameter treats a Context return annotation as a parameter #3298

Description

@otiscuilei

Initial checks

  • I tested the current main branch (6e30452).
  • I searched existing issues and pull requests for this behavior.

Description

find_context_parameter() iterates over every entry returned by typing.get_type_hints(). That mapping includes the function return annotation under the special key "return", even though it is not a parameter.

As a result, a tool, prompt, or resource function whose return annotation is Context (or a union containing Context) is incorrectly recorded as having a context parameter named "return". The SDK later attempts to inject context as a keyword argument with that name, which can produce an unexpected-keyword error when the callable is invoked.

Expected: context detection only examines actual function parameters and ignores the return annotation.

Example code

from mcp.server.mcpserver import Context
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter

def fn(value: int) -> Context:
    ...

print(find_context_parameter(fn))  # current: "return"; expected: None

Environment

  • Python 3.12
  • MCP Python SDK main at 6e30452

I used AI assistance while investigating this issue and reviewed and reproduced the behavior locally.

Activity

  1. nightcityblade commented on Aug 12, 2026

    @nightcityblade

    Hi, I'd like to work on this. I'll submit a focused PR with regression coverage shortly.

  2. nightcityblade commented on Aug 12, 2026

    @nightcityblade

    I noticed the contribution guide asks contributors to wait for maintainer feedback or a ready-for-work signal before implementation. I'm stepping back for now so this can be triaged first.

  3. added
    P3Nice to haves, rare edge cases
    on Aug 12, 2026
  4. hishammoizuddin commented on Aug 13, 2026

    @hishammoizuddin

    So I ran into this and dug in a bit. The cause is that get_type_hints() hands back the return annotation under a "return" key alongside the real parameters, and find_context_parameter loops over the whole mapping, so a handler annotated -> Context ends up recorded as having a context parameter literally named "return". Since return is a keyword, injecting it can never work: the handler registers fine and then blows up the first time it's called.

    One thing that surprised me is that it isn't just tools. Prompts and resource templates resolve their context through the same function, so all three break the same way.

    Fix is to drop the "return" key before scanning the hints. I've put up a PR with that plus regression tests, I'd be happy to close it if you'd rather take a different approach.

    Disclosure: I used AI assistance (Claude Code) on this. I read through the change myself and can explain it.

  5. added
    v1Affects the v1.x maintenance line
    v2Affects the v2 line (2.x on main)
    on Aug 18, 2026
  6. CodeAlex52 commented on Sep 10, 2026

    @CodeAlex52

    Reproduced on current main: find_context_parameter returns 'return' for 'def fn(value: int) -> Context', expected None. A normal 'ctx: Context' parameter still resolves correctly.

    The cause is that typing.get_type_hints() includes the return annotation under the key 'return', which is not a parameter. Skipping that key fixes it, including for Optional[Context] returns.

    I have a minimal fix plus a test ready and would be glad to open a PR if you are open to an outside contribution here.

  7. Drima-code commented on Sep 16, 2026

    @Drima-code

    I've put together a fix for this along with tests (the module previously had no direct test coverage): Drima-code@f37be04

    The change is minimal — find_context_parameter() skips the "return" key that typing.get_type_hints() injects for the return annotation, since it is the only non-parameter key the map can contain. Happy to open a PR whenever it's appropriate to do so.

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

    P3Nice to haves, rare edge casesbugSomething 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