Skip to content

Commit 31889d1

Browse files
committed
fix: correct Context type parameters in examples and tests
Context is Generic[LifespanContextT, RequestT], not Generic[ServerSessionT, ...]. The Context[ServerSession, None] pattern scattered across examples, tests, and docs was passing ServerSession as LifespanContextT, which is semantically wrong (the type checker only accepted it because LifespanContextT is unbounded). Both TypeVars have PEP 696 defaults (dict[str, Any] and Any respectively), so bare Context is the correct annotation when neither parameter needs to be constrained. The one exception is the lifespan example, which correctly uses Context[AppContext] to type the lifespan context. This also removes the now-unused ServerSession imports from the affected files.
1 parent 7ba41dc commit 31889d1

File tree

13 files changed

+66
-88
lines changed

13 files changed

+66
-88
lines changed

README.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ from contextlib import asynccontextmanager
229229
from dataclasses import dataclass
230230

231231
from mcp.server.fastmcp import Context, FastMCP
232-
from mcp.server.session import ServerSession
233232

234233

235234
# Mock database class for example
@@ -275,7 +274,7 @@ mcp = FastMCP("My App", lifespan=app_lifespan)
275274

276275
# Access type-safe lifespan context in tools
277276
@mcp.tool()
278-
def query_db(ctx: Context[ServerSession, AppContext]) -> str:
277+
def query_db(ctx: Context[AppContext]) -> str:
279278
"""Tool that uses initialized resources."""
280279
db = ctx.request_context.lifespan_context.db
281280
return db.query()
@@ -347,13 +346,12 @@ Tools can optionally receive a Context object by including a parameter with the
347346
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
348347
```python
349348
from mcp.server.fastmcp import Context, FastMCP
350-
from mcp.server.session import ServerSession
351349

352350
mcp = FastMCP(name="Progress Example")
353351

354352

355353
@mcp.tool()
356-
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
354+
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
357355
"""Execute a task with progress updates."""
358356
await ctx.info(f"Starting: {task_name}")
359357

@@ -695,13 +693,12 @@ The Context object provides the following capabilities:
695693
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
696694
```python
697695
from mcp.server.fastmcp import Context, FastMCP
698-
from mcp.server.session import ServerSession
699696

700697
mcp = FastMCP(name="Progress Example")
701698

702699

703700
@mcp.tool()
704-
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
701+
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
705702
"""Execute a task with progress updates."""
706703
await ctx.info(f"Starting: {task_name}")
707704

@@ -828,7 +825,6 @@ import uuid
828825
from pydantic import BaseModel, Field
829826

830827
from mcp.server.fastmcp import Context, FastMCP
831-
from mcp.server.session import ServerSession
832828
from mcp.shared.exceptions import UrlElicitationRequiredError
833829
from mcp.types import ElicitRequestURLParams
834830

@@ -846,7 +842,7 @@ class BookingPreferences(BaseModel):
846842

847843

848844
@mcp.tool()
849-
async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerSession, None]) -> str:
845+
async def book_table(date: str, time: str, party_size: int, ctx: Context) -> str:
850846
"""Book a table with date availability check.
851847
852848
This demonstrates form mode elicitation for collecting non-sensitive user input.
@@ -870,7 +866,7 @@ async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerS
870866

871867

872868
@mcp.tool()
873-
async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> str:
869+
async def secure_payment(amount: float, ctx: Context) -> str:
874870
"""Process a secure payment requiring URL confirmation.
875871
876872
This demonstrates URL mode elicitation using ctx.elicit_url() for
@@ -894,7 +890,7 @@ async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> st
894890

895891

896892
@mcp.tool()
897-
async def connect_service(service_name: str, ctx: Context[ServerSession, None]) -> str:
893+
async def connect_service(service_name: str, ctx: Context) -> str:
898894
"""Connect to a third-party service requiring OAuth authorization.
899895
900896
This demonstrates the "throw error" pattern using UrlElicitationRequiredError.
@@ -935,14 +931,13 @@ Tools can interact with LLMs through sampling (generating text):
935931
<!-- snippet-source examples/snippets/servers/sampling.py -->
936932
```python
937933
from mcp.server.fastmcp import Context, FastMCP
938-
from mcp.server.session import ServerSession
939934
from mcp.types import SamplingMessage, TextContent
940935

941936
mcp = FastMCP(name="Sampling Example")
942937

943938

944939
@mcp.tool()
945-
async def generate_poem(topic: str, ctx: Context[ServerSession, None]) -> str:
940+
async def generate_poem(topic: str, ctx: Context) -> str:
946941
"""Generate a poem using LLM sampling."""
947942
prompt = f"Write a short poem about {topic}"
948943

@@ -972,13 +967,12 @@ Tools can send logs and notifications through the context:
972967
<!-- snippet-source examples/snippets/servers/notifications.py -->
973968
```python
974969
from mcp.server.fastmcp import Context, FastMCP
975-
from mcp.server.session import ServerSession
976970

977971
mcp = FastMCP(name="Notifications Example")
978972

979973

980974
@mcp.tool()
981-
async def process_data(data: str, ctx: Context[ServerSession, None]) -> str:
975+
async def process_data(data: str, ctx: Context) -> str:
982976
"""Process data with logging."""
983977
# Different log levels
984978
await ctx.debug(f"Debug: Processing '{data}'")

README.v2.md

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -346,13 +346,12 @@ Tools can optionally receive a Context object by including a parameter with the
346346
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
347347
```python
348348
from mcp.server.mcpserver import Context, MCPServer
349-
from mcp.server.session import ServerSession
350349

351350
mcp = MCPServer(name="Progress Example")
352351

353352

354353
@mcp.tool()
355-
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
354+
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
356355
"""Execute a task with progress updates."""
357356
await ctx.info(f"Starting: {task_name}")
358357

@@ -694,13 +693,12 @@ The Context object provides the following capabilities:
694693
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
695694
```python
696695
from mcp.server.mcpserver import Context, MCPServer
697-
from mcp.server.session import ServerSession
698696

699697
mcp = MCPServer(name="Progress Example")
700698

701699

702700
@mcp.tool()
703-
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
701+
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
704702
"""Execute a task with progress updates."""
705703
await ctx.info(f"Starting: {task_name}")
706704

@@ -826,7 +824,6 @@ import uuid
826824
from pydantic import BaseModel, Field
827825

828826
from mcp.server.mcpserver import Context, MCPServer
829-
from mcp.server.session import ServerSession
830827
from mcp.shared.exceptions import UrlElicitationRequiredError
831828
from mcp.types import ElicitRequestURLParams
832829

@@ -844,7 +841,7 @@ class BookingPreferences(BaseModel):
844841

845842

846843
@mcp.tool()
847-
async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerSession, None]) -> str:
844+
async def book_table(date: str, time: str, party_size: int, ctx: Context) -> str:
848845
"""Book a table with date availability check.
849846
850847
This demonstrates form mode elicitation for collecting non-sensitive user input.
@@ -868,7 +865,7 @@ async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerS
868865

869866

870867
@mcp.tool()
871-
async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> str:
868+
async def secure_payment(amount: float, ctx: Context) -> str:
872869
"""Process a secure payment requiring URL confirmation.
873870
874871
This demonstrates URL mode elicitation using ctx.elicit_url() for
@@ -892,7 +889,7 @@ async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> st
892889

893890

894891
@mcp.tool()
895-
async def connect_service(service_name: str, ctx: Context[ServerSession, None]) -> str:
892+
async def connect_service(service_name: str, ctx: Context) -> str:
896893
"""Connect to a third-party service requiring OAuth authorization.
897894
898895
This demonstrates the "throw error" pattern using UrlElicitationRequiredError.
@@ -933,14 +930,13 @@ Tools can interact with LLMs through sampling (generating text):
933930
<!-- snippet-source examples/snippets/servers/sampling.py -->
934931
```python
935932
from mcp.server.mcpserver import Context, MCPServer
936-
from mcp.server.session import ServerSession
937933
from mcp.types import SamplingMessage, TextContent
938934

939935
mcp = MCPServer(name="Sampling Example")
940936

941937

942938
@mcp.tool()
943-
async def generate_poem(topic: str, ctx: Context[ServerSession, None]) -> str:
939+
async def generate_poem(topic: str, ctx: Context) -> str:
944940
"""Generate a poem using LLM sampling."""
945941
prompt = f"Write a short poem about {topic}"
946942

@@ -970,13 +966,12 @@ Tools can send logs and notifications through the context:
970966
<!-- snippet-source examples/snippets/servers/notifications.py -->
971967
```python
972968
from mcp.server.mcpserver import Context, MCPServer
973-
from mcp.server.session import ServerSession
974969

975970
mcp = MCPServer(name="Notifications Example")
976971

977972

978973
@mcp.tool()
979-
async def process_data(data: str, ctx: Context[ServerSession, None]) -> str:
974+
async def process_data(data: str, ctx: Context) -> str:
980975
"""Process data with logging."""
981976
# Different log levels
982977
await ctx.debug(f"Debug: Processing '{data}'")

examples/servers/everything-server/mcp_everything_server/server.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from mcp.server import ServerRequestContext
1414
from mcp.server.mcpserver import Context, MCPServer
1515
from mcp.server.mcpserver.prompts.base import UserMessage
16-
from mcp.server.session import ServerSession
1716
from mcp.server.streamable_http import EventCallback, EventMessage, EventStore
1817
from mcp.types import (
1918
AudioContent,
@@ -142,7 +141,7 @@ def test_multiple_content_types() -> list[TextContent | ImageContent | EmbeddedR
142141

143142

144143
@mcp.tool()
145-
async def test_tool_with_logging(ctx: Context[ServerSession, None]) -> str:
144+
async def test_tool_with_logging(ctx: Context) -> str:
146145
"""Tests tool that emits log messages during execution"""
147146
await ctx.info("Tool execution started")
148147
await asyncio.sleep(0.05)
@@ -155,7 +154,7 @@ async def test_tool_with_logging(ctx: Context[ServerSession, None]) -> str:
155154

156155

157156
@mcp.tool()
158-
async def test_tool_with_progress(ctx: Context[ServerSession, None]) -> str:
157+
async def test_tool_with_progress(ctx: Context) -> str:
159158
"""Tests tool that reports progress notifications"""
160159
await ctx.report_progress(progress=0, total=100, message="Completed step 0 of 100")
161160
await asyncio.sleep(0.05)
@@ -173,7 +172,7 @@ async def test_tool_with_progress(ctx: Context[ServerSession, None]) -> str:
173172

174173

175174
@mcp.tool()
176-
async def test_sampling(prompt: str, ctx: Context[ServerSession, None]) -> str:
175+
async def test_sampling(prompt: str, ctx: Context) -> str:
177176
"""Tests server-initiated sampling (LLM completion request)"""
178177
try:
179178
# Request sampling from client
@@ -198,7 +197,7 @@ class UserResponse(BaseModel):
198197

199198

200199
@mcp.tool()
201-
async def test_elicitation(message: str, ctx: Context[ServerSession, None]) -> str:
200+
async def test_elicitation(message: str, ctx: Context) -> str:
202201
"""Tests server-initiated elicitation (user input request)"""
203202
try:
204203
# Request user input from client
@@ -230,7 +229,7 @@ class SEP1034DefaultsSchema(BaseModel):
230229

231230

232231
@mcp.tool()
233-
async def test_elicitation_sep1034_defaults(ctx: Context[ServerSession, None]) -> str:
232+
async def test_elicitation_sep1034_defaults(ctx: Context) -> str:
234233
"""Tests elicitation with default values for all primitive types (SEP-1034)"""
235234
try:
236235
# Request user input with defaults for all primitive types
@@ -289,7 +288,7 @@ class EnumSchemasTestSchema(BaseModel):
289288

290289

291290
@mcp.tool()
292-
async def test_elicitation_sep1330_enums(ctx: Context[ServerSession, None]) -> str:
291+
async def test_elicitation_sep1330_enums(ctx: Context) -> str:
293292
"""Tests elicitation with enum schema variations per SEP-1330"""
294293
try:
295294
result = await ctx.elicit(
@@ -313,7 +312,7 @@ def test_error_handling() -> str:
313312

314313

315314
@mcp.tool()
316-
async def test_reconnection(ctx: Context[ServerSession, None]) -> str:
315+
async def test_reconnection(ctx: Context) -> str:
317316
"""Tests SSE polling by closing stream mid-call (SEP-1699)"""
318317
await ctx.info("Before disconnect")
319318

examples/snippets/servers/elicitation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from pydantic import BaseModel, Field
1111

1212
from mcp.server.mcpserver import Context, MCPServer
13-
from mcp.server.session import ServerSession
1413
from mcp.shared.exceptions import UrlElicitationRequiredError
1514
from mcp.types import ElicitRequestURLParams
1615

@@ -28,7 +27,7 @@ class BookingPreferences(BaseModel):
2827

2928

3029
@mcp.tool()
31-
async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerSession, None]) -> str:
30+
async def book_table(date: str, time: str, party_size: int, ctx: Context) -> str:
3231
"""Book a table with date availability check.
3332
3433
This demonstrates form mode elicitation for collecting non-sensitive user input.
@@ -52,7 +51,7 @@ async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerS
5251

5352

5453
@mcp.tool()
55-
async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> str:
54+
async def secure_payment(amount: float, ctx: Context) -> str:
5655
"""Process a secure payment requiring URL confirmation.
5756
5857
This demonstrates URL mode elicitation using ctx.elicit_url() for
@@ -76,7 +75,7 @@ async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> st
7675

7776

7877
@mcp.tool()
79-
async def connect_service(service_name: str, ctx: Context[ServerSession, None]) -> str:
78+
async def connect_service(service_name: str, ctx: Context) -> str:
8079
"""Connect to a third-party service requiring OAuth authorization.
8180
8281
This demonstrates the "throw error" pattern using UrlElicitationRequiredError.

examples/snippets/servers/notifications.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from mcp.server.mcpserver import Context, MCPServer
2-
from mcp.server.session import ServerSession
32

43
mcp = MCPServer(name="Notifications Example")
54

65

76
@mcp.tool()
8-
async def process_data(data: str, ctx: Context[ServerSession, None]) -> str:
7+
async def process_data(data: str, ctx: Context) -> str:
98
"""Process data with logging."""
109
# Different log levels
1110
await ctx.debug(f"Debug: Processing '{data}'")

examples/snippets/servers/sampling.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from mcp.server.mcpserver import Context, MCPServer
2-
from mcp.server.session import ServerSession
32
from mcp.types import SamplingMessage, TextContent
43

54
mcp = MCPServer(name="Sampling Example")
65

76

87
@mcp.tool()
9-
async def generate_poem(topic: str, ctx: Context[ServerSession, None]) -> str:
8+
async def generate_poem(topic: str, ctx: Context) -> str:
109
"""Generate a poem using LLM sampling."""
1110
prompt = f"Write a short poem about {topic}"
1211

examples/snippets/servers/tool_progress.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from mcp.server.mcpserver import Context, MCPServer
2-
from mcp.server.session import ServerSession
32

43
mcp = MCPServer(name="Progress Example")
54

65

76
@mcp.tool()
8-
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
7+
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
98
"""Execute a task with progress updates."""
109
await ctx.info(f"Starting: {task_name}")
1110

0 commit comments

Comments
 (0)