Skip to content

refactor: remove request_ctx ContextVar, thread Context explicitly#2203

Open
maxisbey wants to merge 1 commit intomainfrom
remove-request-ctx-contextvar
Open

refactor: remove request_ctx ContextVar, thread Context explicitly#2203
maxisbey wants to merge 1 commit intomainfrom
remove-request-ctx-contextvar

Conversation

@maxisbey
Copy link
Contributor

@maxisbey maxisbey commented Mar 2, 2026

Removes the request_ctx ContextVar and threads Context explicitly through the MCPServer request-handling chain.

Motivation and Context

The request_ctx ContextVar in mcp.server.lowlevel.server was redundant: the lowlevel server already passes ServerRequestContext as the first argument to every _handle_* method. The ContextVar was a second mechanism carrying the same value, used only by MCPServer.get_context().

This PR removes the ContextVar entirely, making the data flow explicit. _handle_* methods construct the high-level Context at the lowlevel→MCPServer boundary and pass it through.

Part of #2112 (context refactor) / #1684 (contextvars cleanup).

How Has This Been Tested?

  • All existing tests pass (1123 passed, 98 skipped, 1 xfailed)
  • New tests for the context-required guards in Tool.run(), Prompt.render(), ResourceTemplate.create_resource()
  • uv run --frozen pyright src/ tests/ — 0 errors
  • uv run --frozen ruff check — clean

Breaking Changes

Yes — documented in docs/migration.md:

  • MCPServer.get_context() removed — use ctx: Context parameter injection in tool/resource/prompt functions instead (the existing recommended pattern)
  • request_ctx ContextVar removed from mcp.server.lowlevel.server — code importing it directly will need to use parameter injection
  • MCPServer.call_tool(), read_resource(), get_prompt() now accept an optional context: Context | None = None parameter — backward-compatible for callers that don't pass it
  • New behavior: if a tool/resource/prompt declares a ctx: Context parameter but is called with context=None, a clear error is raised (ToolError for tools, ValueError for prompts/resource templates). Previously None was silently injected.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Context class moved from mcp.server.mcpserver.server to mcp.server.mcpserver.context. The public import path (from mcp.server.mcpserver import Context) is unchanged via __init__.py re-export. The old direct-module path (from mcp.server.mcpserver.server import Context) also still works because server.py imports Context at module level.

Exception hierarchy cleanup (making prompts/resources raise MCPServerError subclasses instead of ValueError) was considered but deferred to #1742 (error taxonomy) to avoid scope creep — see that issue for the full analysis of the existing inconsistencies.

AI Disclaimer

The request_ctx ContextVar in mcp.server.lowlevel.server was redundant
with the ServerRequestContext already passed as the first argument to
every _handle_* method. This removes the ContextVar entirely and threads
Context explicitly.

Changes:
- MCPServer.get_context() removed — use ctx: Context parameter injection
  in tool/resource/prompt functions instead
- MCPServer.call_tool/read_resource/get_prompt now accept an optional
  context: Context | None = None parameter; _handle_* methods construct
  the Context at the lowlevel boundary and pass it through
- Context class moved from server.py to its own context.py module (still
  re-exported from mcp.server.mcpserver)
- Tool.run/Prompt.render/ResourceTemplate.create_resource now raise a
  clear error if the registered function requires a Context but none was
  provided, instead of silently injecting None

Github-Issue: #2112
Github-Issue: #1684
@maxisbey maxisbey requested review from Kludex and felixweinberger and removed request for Kludex March 2, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant