Skip to content

Fix NameError with future annotations and Context/Depends parameters#3243

Merged
jlowin merged 6 commits intomainfrom
fix/future-annotations-wrapper-module
Feb 20, 2026
Merged

Fix NameError with future annotations and Context/Depends parameters#3243
jlowin merged 6 commits intomainfrom
fix/future-annotations-wrapper-module

Conversation

@jlowin
Copy link
Copy Markdown
Member

@jlowin jlowin commented Feb 20, 2026

When a tool uses from __future__ import annotations and has a Context or Depends() parameter, without_injected_parameters creates a wrapper function to strip those params before Pydantic processes the signature. But the wrapper inherited __module__ = 'fastmcp.server.dependencies' instead of the user's module. Pydantic resolves string annotations (which is what future annotations produces) via sys.modules[fn.__module__].__dict__ — so it was looking in the wrong namespace and failing with NameError for any type not imported by dependencies.py itself (Annotated, Literal, user-defined types, etc.).

The fix sets wrapper.__module__ and wrapper.__qualname__ from the original function so Pydantic resolves annotations against the user's module where the names actually exist.

from __future__ import annotations
from typing import Annotated
from pydantic import Field
from fastmcp import FastMCP, Context

mcp = FastMCP("example")

@mcp.tool()
def my_tool(query: Annotated[str, Field(description="Search query")], ctx: Context) -> str:
    return f"Result for: {query}"
# Previously: NameError: name 'Annotated' is not defined
# Now: works correctly

Closes #3238, closes #905

@jlowin jlowin added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality. labels Feb 20, 2026
marvin-context-protocol Bot and others added 5 commits February 20, 2026 13:41
Pydantic (even 2.11.7) uses __module__ not __globals__ to resolve
annotations, so setting __module__ alone is sufficient.
The wrapper's __globals__ is read-only and points to dependencies.py,
so some Pydantic versions use it instead of __module__ when resolving
string annotations. Pre-resolving via get_type_hints on the original
function ensures annotations are type objects before Pydantic sees them.
@jlowin jlowin merged commit ea13286 into main Feb 20, 2026
14 of 15 checks passed
@jlowin jlowin deleted the fix/future-annotations-wrapper-module branch February 20, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

1 participant