Skip to content

Commit a9ca217

Browse files
committed
Move the SEP-2663 wire models to mcp.shared.tasks and complete the task lifecycle
- The wire models (Task, CreateTaskResult, request params, typed request wrappers, and a lenient GetTaskResult parser) move to mcp.shared.tasks so client code can import them without reaching into the server tier; mcp.server.tasks re-exports the public names. - Tasks(augment=...) scopes augmentation per request (SEP-2663: the server decides at its own discretion); None keeps augment-everything. - A JSON-RPC error under augmentation now records a task born "failed" (error inlined on tasks/get with no result key, statusMessage carrying the diagnostic) and returns CreateTaskResult(status="failed"). Errors on every non-augmented path propagate unchanged. - require_client_extension moves to mcp.server.extension so the extension tier no longer reaches into the composition tier; mcp.server.mcpserver keeps re-exporting it.
1 parent c509eb1 commit a9ca217

5 files changed

Lines changed: 449 additions & 184 deletions

File tree

src/mcp/server/extension.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@
2323
from dataclasses import dataclass, field
2424
from typing import TYPE_CHECKING, Any
2525

26-
from mcp_types import CallToolRequestParams
26+
from mcp_types import (
27+
MISSING_REQUIRED_CLIENT_CAPABILITY,
28+
CallToolRequestParams,
29+
ClientCapabilities,
30+
MissingRequiredClientCapabilityErrorData,
31+
)
2732
from mcp_types.methods import SPEC_CLIENT_METHODS
2833
from pydantic import BaseModel
2934

3035
from mcp.server.context import CallNext, HandlerResult, ServerMiddleware, ServerRequestContext
36+
from mcp.shared.exceptions import MCPError
3137

3238
# Re-exported from `mcp.shared.extension` (shared with the client surface) for existing importers.
3339
from mcp.shared.extension import validate_extension_identifier as validate_extension_identifier
@@ -149,6 +155,36 @@ async def intercept_tool_call(
149155
return await call_next(ctx)
150156

151157

158+
def require_client_extension(ctx: ServerRequestContext[Any, Any], identifier: str) -> None:
159+
"""Assert the connected client declared support for `identifier`.
160+
161+
Call this from an extension's handler or `intercept_tool_call` before
162+
offering extension-specific behaviour. Raises `MCPError` with the
163+
`-32021` (missing required client capability) code and a
164+
`requiredCapabilities` payload when the client did not declare the
165+
extension, per SEP-2133.
166+
167+
Args:
168+
ctx: The current request context.
169+
identifier: The extension identifier the client must have declared.
170+
171+
Raises:
172+
MCPError: With code `MISSING_REQUIRED_CLIENT_CAPABILITY` if the client
173+
did not advertise `identifier`.
174+
"""
175+
client_params = ctx.session.client_params
176+
declared = client_params.capabilities.extensions if client_params else None
177+
if not declared or identifier not in declared:
178+
data = MissingRequiredClientCapabilityErrorData(
179+
required_capabilities=ClientCapabilities(extensions={identifier: {}})
180+
)
181+
raise MCPError(
182+
code=MISSING_REQUIRED_CLIENT_CAPABILITY,
183+
message=f"Client did not declare required extension {identifier!r}",
184+
data=data.model_dump(by_alias=True, mode="json", exclude_none=True),
185+
)
186+
187+
152188
def compose_tool_call_interceptor(extensions: Sequence[Extension]) -> ServerMiddleware[Any]:
153189
"""Fold every extension's `intercept_tool_call` into one `ServerMiddleware`.
154190

src/mcp/server/mcpserver/server.py

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414
INTERNAL_ERROR,
1515
INVALID_PARAMS,
1616
METHOD_NOT_FOUND,
17-
MISSING_REQUIRED_CLIENT_CAPABILITY,
1817
Annotations,
1918
BlobResourceContents,
2019
CallToolRequestParams,
2120
CallToolResult,
22-
ClientCapabilities,
2321
CompleteRequestParams,
2422
CompleteResult,
2523
Completion,
@@ -31,7 +29,6 @@
3129
ListResourcesResult,
3230
ListResourceTemplatesResult,
3331
ListToolsResult,
34-
MissingRequiredClientCapabilityErrorData,
3532
PaginatedRequestParams,
3633
ReadResourceRequestParams,
3734
ReadResourceResult,
@@ -67,6 +64,9 @@
6764
compose_tool_call_interceptor,
6865
validate_extension_identifier,
6966
)
67+
from mcp.server.extension import (
68+
require_client_extension as require_client_extension,
69+
)
7070
from mcp.server.lowlevel.helper_types import ReadResourceContents
7171
from mcp.server.lowlevel.server import LifespanResultT, Server
7272
from mcp.server.lowlevel.server import lifespan as default_lifespan
@@ -1296,33 +1296,3 @@ async def gated(ctx: ServerRequestContext[Any, Any], params: Any) -> HandlerResu
12961296
return await method.handler(ctx, params)
12971297

12981298
return gated
1299-
1300-
1301-
def require_client_extension(ctx: ServerRequestContext[Any, Any], identifier: str) -> None:
1302-
"""Assert the connected client declared support for `identifier`.
1303-
1304-
Call this from an extension's handler or `intercept_tool_call` before
1305-
offering extension-specific behaviour. Raises `MCPError` with the
1306-
`-32021` (missing required client capability) code and a
1307-
`requiredCapabilities` payload when the client did not declare the
1308-
extension, per SEP-2133.
1309-
1310-
Args:
1311-
ctx: The current request context.
1312-
identifier: The extension identifier the client must have declared.
1313-
1314-
Raises:
1315-
MCPError: With code `MISSING_REQUIRED_CLIENT_CAPABILITY` if the client
1316-
did not advertise `identifier`.
1317-
"""
1318-
client_params = ctx.session.client_params
1319-
declared = client_params.capabilities.extensions if client_params else None
1320-
if not declared or identifier not in declared:
1321-
data = MissingRequiredClientCapabilityErrorData(
1322-
required_capabilities=ClientCapabilities(extensions={identifier: {}})
1323-
)
1324-
raise MCPError(
1325-
code=MISSING_REQUIRED_CLIENT_CAPABILITY,
1326-
message=f"Client did not declare required extension {identifier!r}",
1327-
data=data.model_dump(by_alias=True, mode="json", exclude_none=True),
1328-
)

0 commit comments

Comments
 (0)