Skip to content

Commit a86eabe

Browse files
authored
Merge branch 'main' into fix-hang-github-mcp
2 parents 1dd7f04 + 1a8c14a commit a86eabe

File tree

79 files changed

+348
-323
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+348
-323
lines changed

.github/actions/conformance/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838
PrivateKeyJWTOAuthProvider,
3939
SignedJWTParameters,
4040
)
41+
from mcp.client.context import ClientRequestContext
4142
from mcp.client.streamable_http import streamable_http_client
4243
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
43-
from mcp.shared.context import RequestContext
4444

4545
# Set up logging to stderr (stdout is for conformance test output)
4646
logging.basicConfig(
@@ -187,7 +187,7 @@ async def run_sse_retry(server_url: str) -> None:
187187

188188

189189
async def default_elicitation_callback(
190-
context: RequestContext[ClientSession, Any], # noqa: ARG001
190+
context: ClientRequestContext,
191191
params: types.ElicitRequestParams,
192192
) -> types.ElicitResult | types.ErrorData:
193193
"""Accept elicitation and apply defaults from the schema (SEP-1034)."""

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ The Context object provides the following capabilities:
682682
- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods))
683683
- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties))
684684
- `await ctx.debug(message)` - Send debug log message
685-
- `await ctx.info(message)` - Send info log message
685+
- `await ctx.info(message)` - Send info log message
686686
- `await ctx.warning(message)` - Send warning log message
687687
- `await ctx.error(message)` - Send error log message
688688
- `await ctx.log(level, message, logger_name=None)` - Send log with custom level
@@ -1110,13 +1110,13 @@ The session object accessible via `ctx.session` provides advanced control over c
11101110
async def notify_data_update(resource_uri: str, ctx: Context) -> str:
11111111
"""Update data and notify clients of the change."""
11121112
# Perform data update logic here
1113-
1113+
11141114
# Notify clients that this specific resource changed
11151115
await ctx.session.send_resource_updated(AnyUrl(resource_uri))
1116-
1116+
11171117
# If this affects the overall resource list, notify about that too
11181118
await ctx.session.send_resource_list_changed()
1119-
1119+
11201120
return f"Updated {resource_uri} and notified clients"
11211121
```
11221122

@@ -1145,11 +1145,11 @@ def query_with_config(query: str, ctx: Context) -> str:
11451145
"""Execute a query using shared database and configuration."""
11461146
# Access typed lifespan context
11471147
app_ctx: AppContext = ctx.request_context.lifespan_context
1148-
1148+
11491149
# Use shared resources
11501150
connection = app_ctx.db
11511151
settings = app_ctx.config
1152-
1152+
11531153
# Execute query with configuration
11541154
result = connection.execute(query, timeout=settings.query_timeout)
11551155
return str(result)
@@ -1644,7 +1644,7 @@ from contextlib import asynccontextmanager
16441644
from typing import Any
16451645

16461646
import mcp.server.stdio
1647-
import mcp.types as types
1647+
from mcp import types
16481648
from mcp.server.lowlevel import NotificationOptions, Server
16491649
from mcp.server.models import InitializationOptions
16501650

@@ -1758,7 +1758,7 @@ uv run examples/snippets/servers/lowlevel/basic.py
17581758
import asyncio
17591759

17601760
import mcp.server.stdio
1761-
import mcp.types as types
1761+
from mcp import types
17621762
from mcp.server.lowlevel import NotificationOptions, Server
17631763
from mcp.server.models import InitializationOptions
17641764

@@ -1837,7 +1837,7 @@ import asyncio
18371837
from typing import Any
18381838

18391839
import mcp.server.stdio
1840-
import mcp.types as types
1840+
from mcp import types
18411841
from mcp.server.lowlevel import NotificationOptions, Server
18421842
from mcp.server.models import InitializationOptions
18431843

@@ -1939,7 +1939,7 @@ import asyncio
19391939
from typing import Any
19401940

19411941
import mcp.server.stdio
1942-
import mcp.types as types
1942+
from mcp import types
19431943
from mcp.server.lowlevel import NotificationOptions, Server
19441944
from mcp.server.models import InitializationOptions
19451945

@@ -2012,7 +2012,7 @@ For servers that need to handle large datasets, the low-level server provides pa
20122012
```python
20132013
"""Example of implementing pagination with MCP server decorators."""
20142014

2015-
import mcp.types as types
2015+
from mcp import types
20162016
from mcp.server.lowlevel import Server
20172017

20182018
# Initialize the server
@@ -2120,8 +2120,8 @@ import asyncio
21202120
import os
21212121

21222122
from mcp import ClientSession, StdioServerParameters, types
2123+
from mcp.client.context import ClientRequestContext
21232124
from mcp.client.stdio import stdio_client
2124-
from mcp.shared.context import RequestContext
21252125

21262126
# Create server parameters for stdio connection
21272127
server_params = StdioServerParameters(
@@ -2133,7 +2133,7 @@ server_params = StdioServerParameters(
21332133

21342134
# Optional: create a sampling callback
21352135
async def handle_sampling_message(
2136-
context: RequestContext[ClientSession, None], params: types.CreateMessageRequestParams
2136+
context: ClientRequestContext, params: types.CreateMessageRequestParams
21372137
) -> types.CreateMessageResult:
21382138
print(f"Sampling request: {params.messages}")
21392139
return types.CreateMessageResult(

README.v2.md

Lines changed: 14 additions & 15 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.mcpserver import Context, MCPServer
232-
from mcp.server.session import ServerSession
233232

234233

235234
# Mock database class for example
@@ -275,7 +274,7 @@ mcp = MCPServer("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()
@@ -684,7 +683,7 @@ The Context object provides the following capabilities:
684683
- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods))
685684
- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties))
686685
- `await ctx.debug(message)` - Send debug log message
687-
- `await ctx.info(message)` - Send info log message
686+
- `await ctx.info(message)` - Send info log message
688687
- `await ctx.warning(message)` - Send warning log message
689688
- `await ctx.error(message)` - Send error log message
690689
- `await ctx.log(level, message, logger_name=None)` - Send log with custom level
@@ -1112,13 +1111,13 @@ The session object accessible via `ctx.session` provides advanced control over c
11121111
async def notify_data_update(resource_uri: str, ctx: Context) -> str:
11131112
"""Update data and notify clients of the change."""
11141113
# Perform data update logic here
1115-
1114+
11161115
# Notify clients that this specific resource changed
11171116
await ctx.session.send_resource_updated(AnyUrl(resource_uri))
1118-
1117+
11191118
# If this affects the overall resource list, notify about that too
11201119
await ctx.session.send_resource_list_changed()
1121-
1120+
11221121
return f"Updated {resource_uri} and notified clients"
11231122
```
11241123

@@ -1147,11 +1146,11 @@ def query_with_config(query: str, ctx: Context) -> str:
11471146
"""Execute a query using shared database and configuration."""
11481147
# Access typed lifespan context
11491148
app_ctx: AppContext = ctx.request_context.lifespan_context
1150-
1149+
11511150
# Use shared resources
11521151
connection = app_ctx.db
11531152
settings = app_ctx.config
1154-
1153+
11551154
# Execute query with configuration
11561155
result = connection.execute(query, timeout=settings.query_timeout)
11571156
return str(result)
@@ -1646,7 +1645,7 @@ from contextlib import asynccontextmanager
16461645
from typing import Any
16471646

16481647
import mcp.server.stdio
1649-
import mcp.types as types
1648+
from mcp import types
16501649
from mcp.server.lowlevel import NotificationOptions, Server
16511650
from mcp.server.models import InitializationOptions
16521651

@@ -1760,7 +1759,7 @@ uv run examples/snippets/servers/lowlevel/basic.py
17601759
import asyncio
17611760

17621761
import mcp.server.stdio
1763-
import mcp.types as types
1762+
from mcp import types
17641763
from mcp.server.lowlevel import NotificationOptions, Server
17651764
from mcp.server.models import InitializationOptions
17661765

@@ -1839,7 +1838,7 @@ import asyncio
18391838
from typing import Any
18401839

18411840
import mcp.server.stdio
1842-
import mcp.types as types
1841+
from mcp import types
18431842
from mcp.server.lowlevel import NotificationOptions, Server
18441843
from mcp.server.models import InitializationOptions
18451844

@@ -1941,7 +1940,7 @@ import asyncio
19411940
from typing import Any
19421941

19431942
import mcp.server.stdio
1944-
import mcp.types as types
1943+
from mcp import types
19451944
from mcp.server.lowlevel import NotificationOptions, Server
19461945
from mcp.server.models import InitializationOptions
19471946

@@ -2014,7 +2013,7 @@ For servers that need to handle large datasets, the low-level server provides pa
20142013
```python
20152014
"""Example of implementing pagination with MCP server decorators."""
20162015

2017-
import mcp.types as types
2016+
from mcp import types
20182017
from mcp.server.lowlevel import Server
20192018

20202019
# Initialize the server
@@ -2122,8 +2121,8 @@ import asyncio
21222121
import os
21232122

21242123
from mcp import ClientSession, StdioServerParameters, types
2124+
from mcp.client.context import ClientRequestContext
21252125
from mcp.client.stdio import stdio_client
2126-
from mcp.shared.context import RequestContext
21272126

21282127
# Create server parameters for stdio connection
21292128
server_params = StdioServerParameters(
@@ -2135,7 +2134,7 @@ server_params = StdioServerParameters(
21352134

21362135
# Optional: create a sampling callback
21372136
async def handle_sampling_message(
2138-
context: RequestContext[ClientSession, None], params: types.CreateMessageRequestParams
2137+
context: ClientRequestContext, params: types.CreateMessageRequestParams
21392138
) -> types.CreateMessageResult:
21402139
print(f"Sampling request: {params.messages}")
21412140
return types.CreateMessageResult(

docs/migration.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,51 @@ async def handle_tool(name: str, arguments: dict) -> list[TextContent]:
371371
await ctx.session.send_progress_notification(ctx.meta["progress_token"], 0.5, 100)
372372
```
373373

374+
### `RequestContext` and `ProgressContext` type parameters simplified
375+
376+
The `RequestContext` class has been split to separate shared fields from server-specific fields. The shared `RequestContext` now only takes 1 type parameter (the session type) instead of 3.
377+
378+
**`RequestContext` changes:**
379+
380+
- Type parameters reduced from `RequestContext[SessionT, LifespanContextT, RequestT]` to `RequestContext[SessionT]`
381+
- Server-specific fields (`lifespan_context`, `experimental`, `request`, `close_sse_stream`, `close_standalone_sse_stream`) moved to new `ServerRequestContext` class in `mcp.server.context`
382+
383+
**`ProgressContext` changes:**
384+
385+
- Type parameters reduced from `ProgressContext[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT]` to `ProgressContext[SessionT]`
386+
387+
**Before (v1):**
388+
389+
```python
390+
from mcp.client.session import ClientSession
391+
from mcp.shared.context import RequestContext, LifespanContextT, RequestT
392+
from mcp.shared.progress import ProgressContext
393+
394+
# RequestContext with 3 type parameters
395+
ctx: RequestContext[ClientSession, LifespanContextT, RequestT]
396+
397+
# ProgressContext with 5 type parameters
398+
progress_ctx: ProgressContext[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT]
399+
```
400+
401+
**After (v2):**
402+
403+
```python
404+
from mcp.client.context import ClientRequestContext
405+
from mcp.client.session import ClientSession
406+
from mcp.server.context import ServerRequestContext, LifespanContextT, RequestT
407+
from mcp.shared.progress import ProgressContext
408+
409+
# For client-side context (sampling, elicitation, list_roots callbacks)
410+
ctx: ClientRequestContext
411+
412+
# For server-specific context with lifespan and request types
413+
server_ctx: ServerRequestContext[LifespanContextT, RequestT]
414+
415+
# ProgressContext with 1 type parameter
416+
progress_ctx: ProgressContext[ClientSession]
417+
```
418+
374419
### Resource URI type changed from `AnyUrl` to `str`
375420

376421
The `uri` field on resource-related types now uses `str` instead of Pydantic's `AnyUrl`. This aligns with the [MCP specification schema](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.ts) which defines URIs as plain strings (`uri: string`) without strict URL validation. This change allows relative paths like `users/me` that were previously rejected.

examples/clients/simple-task-interactive-client/mcp_simple_task_interactive_client/main.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
"""
88

99
import asyncio
10-
from typing import Any
1110

1211
import click
1312
from mcp import ClientSession
13+
from mcp.client.context import ClientRequestContext
1414
from mcp.client.streamable_http import streamable_http_client
15-
from mcp.shared.context import RequestContext
1615
from mcp.types import (
1716
CallToolResult,
1817
CreateMessageRequestParams,
@@ -24,7 +23,7 @@
2423

2524

2625
async def elicitation_callback(
27-
context: RequestContext[ClientSession, Any],
26+
context: ClientRequestContext,
2827
params: ElicitRequestParams,
2928
) -> ElicitResult:
3029
"""Handle elicitation requests from the server."""
@@ -39,7 +38,7 @@ async def elicitation_callback(
3938

4039

4140
async def sampling_callback(
42-
context: RequestContext[ClientSession, Any],
41+
context: ClientRequestContext,
4342
params: CreateMessageRequestParams,
4443
) -> CreateMessageResult:
4544
"""Handle sampling requests from the server."""

examples/servers/simple-pagination/mcp_simple_pagination/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import anyio
1010
import click
11-
import mcp.types as types
11+
from mcp import types
1212
from mcp.server.lowlevel import Server
1313
from starlette.requests import Request
1414

examples/servers/simple-prompt/mcp_simple_prompt/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import anyio
22
import click
3-
import mcp.types as types
3+
from mcp import types
44
from mcp.server.lowlevel import Server
55
from starlette.requests import Request
66

examples/servers/simple-resource/mcp_simple_resource/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import anyio
22
import click
3-
import mcp.types as types
3+
from mcp import types
44
from mcp.server.lowlevel import Server
55
from mcp.server.lowlevel.helper_types import ReadResourceContents
66
from starlette.requests import Request

examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import anyio
77
import click
8-
import mcp.types as types
98
import uvicorn
9+
from mcp import types
1010
from mcp.server.lowlevel import Server
1111
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
1212
from starlette.applications import Starlette

examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import anyio
77
import click
8-
import mcp.types as types
8+
from mcp import types
99
from mcp.server.lowlevel import Server
1010
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
1111
from starlette.applications import Starlette

0 commit comments

Comments
 (0)