docs: add code fences to Example: docstring blocks (#2104)

This commit is contained in:
Jonathan Hefner 2026-02-19 14:06:11 -06:00 • committed by GitHub
commit cb07adeca3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 83 additions and 18 deletions

View file

@ -187,11 +187,13 @@ class ExperimentalTaskHandlers:
WARNING: These APIs are experimental and may change without notice. WARNING: These APIs are experimental and may change without notice.
Example: Example:
```python
handlers = ExperimentalTaskHandlers( handlers = ExperimentalTaskHandlers(
get_task=my_get_task_handler, get_task=my_get_task_handler,
list_tasks=my_list_tasks_handler, list_tasks=my_list_tasks_handler,
) )
session = ClientSession(..., experimental_task_handlers=handlers) session = ClientSession(..., experimental_task_handlers=handlers)
```
""" """
# Pure task request handlers # Pure task request handlers

View file

@ -5,6 +5,7 @@ This module provides client methods for interacting with MCP tasks.
WARNING: These APIs are experimental and may change without notice. WARNING: These APIs are experimental and may change without notice.
Example: Example:
```python
# Call a tool as a task # Call a tool as a task
result = await session.experimental.call_tool_as_task("tool_name", {"arg": "value"}) result = await session.experimental.call_tool_as_task("tool_name", {"arg": "value"})
task_id = result.task.task_id task_id = result.task.task_id
@ -21,6 +22,7 @@ Example:
# Cancel a task # Cancel a task
await session.experimental.cancel_task(task_id) await session.experimental.cancel_task(task_id)
```
""" """
from collections.abc import AsyncIterator from collections.abc import AsyncIterator
@ -72,6 +74,7 @@ class ExperimentalClientFeatures:
CreateTaskResult containing the task reference CreateTaskResult containing the task reference
Example: Example:
```python
# Create task # Create task
result = await session.experimental.call_tool_as_task( result = await session.experimental.call_tool_as_task(
"long_running_tool", {"input": "data"} "long_running_tool", {"input": "data"}
@ -87,6 +90,7 @@ class ExperimentalClientFeatures:
# Get result # Get result
final = await session.experimental.get_task_result(task_id, CallToolResult) final = await session.experimental.get_task_result(task_id, CallToolResult)
```
""" """
return await self._session.send_request( return await self._session.send_request(
types.CallToolRequest( types.CallToolRequest(
@ -189,6 +193,7 @@ class ExperimentalClientFeatures:
GetTaskResult for each poll GetTaskResult for each poll
Example: Example:
```python
async for status in session.experimental.poll_task(task_id): async for status in session.experimental.poll_task(task_id):
print(f"Status: {status.status}") print(f"Status: {status.status}")
if status.status == "input_required": if status.status == "input_required":
@ -197,6 +202,7 @@ class ExperimentalClientFeatures:
# Task is now terminal, get the result # Task is now terminal, get the result
result = await session.experimental.get_task_result(task_id, CallToolResult) result = await session.experimental.get_task_result(task_id, CallToolResult)
```
""" """
async for status in poll_until_terminal(self.get_task, task_id): async for status in poll_until_terminal(self.get_task, task_id):
yield status yield status

View file

@ -206,8 +206,10 @@ class ClientSession(
These APIs are experimental and may change without notice. These APIs are experimental and may change without notice.
Example: Example:
```python
status = await session.experimental.get_task(task_id) status = await session.experimental.get_task(task_id)
result = await session.experimental.get_task_result(task_id, CallToolResult) result = await session.experimental.get_task_result(task_id, CallToolResult)
```
""" """
if self._experimental_features is None: if self._experimental_features is None:
self._experimental_features = ExperimentalClientFeatures(self) self._experimental_features = ExperimentalClientFeatures(self)

View file

@ -91,13 +91,14 @@ class ClientSessionGroup:
For auxiliary handlers, such as resource subscription, this is delegated to For auxiliary handlers, such as resource subscription, this is delegated to
the client and can be accessed via the session. the client and can be accessed via the session.
Example Usage: Example:
```python
name_fn = lambda name, server_info: f"{(server_info.name)}_{name}" name_fn = lambda name, server_info: f"{(server_info.name)}_{name}"
async with ClientSessionGroup(component_name_hook=name_fn) as group: async with ClientSessionGroup(component_name_hook=name_fn) as group:
for server_param in server_params: for server_param in server_params:
await group.connect_to_server(server_param) await group.connect_to_server(server_param)
... ...
```
""" """
class _ComponentNames(BaseModel): class _ComponentNames(BaseModel):

View file

@ -160,6 +160,7 @@ class Experimental:
RuntimeError: If task support is not enabled or task_metadata is missing RuntimeError: If task support is not enabled or task_metadata is missing
Example: Example:
```python
async def handle_tool(ctx: RequestContext, params: CallToolRequestParams) -> CallToolResult: async def handle_tool(ctx: RequestContext, params: CallToolRequestParams) -> CallToolResult:
async def work(task: ServerTaskContext) -> CallToolResult: async def work(task: ServerTaskContext) -> CallToolResult:
result = await task.elicit( result = await task.elicit(
@ -170,6 +171,7 @@ class Experimental:
return CallToolResult(content=[TextContent(text="Done" if confirmed else "Cancelled")]) return CallToolResult(content=[TextContent(text="Done" if confirmed else "Cancelled")])
return await ctx.experimental.run_task(work) return await ctx.experimental.run_task(work)
```
WARNING: This API is experimental and may change without notice. WARNING: This API is experimental and may change without notice.
""" """

View file

@ -56,6 +56,7 @@ class ServerTaskContext:
- Status notifications via the session - Status notifications via the session
Example: Example:
```python
async def my_task_work(task: ServerTaskContext) -> CallToolResult: async def my_task_work(task: ServerTaskContext) -> CallToolResult:
await task.update_status("Starting...") await task.update_status("Starting...")
@ -68,6 +69,7 @@ class ServerTaskContext:
return CallToolResult(content=[TextContent(text="Done!")]) return CallToolResult(content=[TextContent(text="Done!")])
else: else:
return CallToolResult(content=[TextContent(text="Cancelled")]) return CallToolResult(content=[TextContent(text="Cancelled")])
```
""" """
def __init__( def __init__(

View file

@ -31,14 +31,20 @@ class TaskSupport:
- Manages a task group for background task execution - Manages a task group for background task execution
Example: Example:
# Simple in-memory setup Simple in-memory setup:
server.experimental.enable_tasks()
# Custom store/queue for distributed systems ```python
server.experimental.enable_tasks()
```
Custom store/queue for distributed systems:
```python
server.experimental.enable_tasks( server.experimental.enable_tasks(
store=RedisTaskStore(redis_url), store=RedisTaskStore(redis_url),
queue=RedisTaskMessageQueue(redis_url), queue=RedisTaskMessageQueue(redis_url),
) )
```
""" """
store: TaskStore store: TaskStore

View file

@ -118,14 +118,20 @@ class ExperimentalHandlers(Generic[LifespanResultT]):
The TaskSupport configuration object The TaskSupport configuration object
Example: Example:
# Simple in-memory setup Simple in-memory setup:
server.experimental.enable_tasks()
# Custom store/queue for distributed systems ```python
server.experimental.enable_tasks()
```
Custom store/queue for distributed systems:
```python
server.experimental.enable_tasks( server.experimental.enable_tasks(
store=RedisTaskStore(redis_url), store=RedisTaskStore(redis_url),
queue=RedisTaskMessageQueue(redis_url), queue=RedisTaskMessageQueue(redis_url),
) )
```
WARNING: This API is experimental and may change without notice. WARNING: This API is experimental and may change without notice.
""" """

View file

@ -535,19 +535,25 @@ class MCPServer(Generic[LifespanResultT]):
- If False, unconditionally creates an unstructured tool - If False, unconditionally creates an unstructured tool
Example: Example:
```python
@server.tool() @server.tool()
def my_tool(x: int) -> str: def my_tool(x: int) -> str:
return str(x) return str(x)
```
```python
@server.tool() @server.tool()
async def tool_with_context(x: int, ctx: Context) -> str: async def tool_with_context(x: int, ctx: Context) -> str:
await ctx.info(f"Processing {x}") await ctx.info(f"Processing {x}")
return str(x) return str(x)
```
```python
@server.tool() @server.tool()
async def async_tool(x: int, context: Context) -> str: async def async_tool(x: int, context: Context) -> str:
await context.report_progress(50, 100) await context.report_progress(50, 100)
return str(x) return str(x)
```
""" """
# Check if user passed function directly instead of calling decorator # Check if user passed function directly instead of calling decorator
if callable(name): if callable(name):
@ -579,12 +585,14 @@ class MCPServer(Generic[LifespanResultT]):
- context: Optional CompletionContext with previously resolved arguments - context: Optional CompletionContext with previously resolved arguments
Example: Example:
```python
@mcp.completion() @mcp.completion()
async def handle_completion(ref, argument, context): async def handle_completion(ref, argument, context):
if isinstance(ref, ResourceTemplateReference): if isinstance(ref, ResourceTemplateReference):
# Return completions based on ref, argument, and context # Return completions based on ref, argument, and context
return Completion(values=["option1", "option2"]) return Completion(values=["option1", "option2"])
return None return None
```
""" """
def decorator(func: _CallableT) -> _CallableT: def decorator(func: _CallableT) -> _CallableT:
@ -647,6 +655,7 @@ class MCPServer(Generic[LifespanResultT]):
meta: Optional metadata dictionary for the resource meta: Optional metadata dictionary for the resource
Example: Example:
```python
@server.resource("resource://my-resource") @server.resource("resource://my-resource")
def get_data() -> str: def get_data() -> str:
return "Hello, world!" return "Hello, world!"
@ -664,6 +673,7 @@ class MCPServer(Generic[LifespanResultT]):
async def get_weather(city: str) -> str: async def get_weather(city: str) -> str:
data = await fetch_weather(city) data = await fetch_weather(city)
return f"Weather for {city}: {data}" return f"Weather for {city}: {data}"
```
""" """
# Check if user passed function directly instead of calling decorator # Check if user passed function directly instead of calling decorator
if callable(uri): if callable(uri):
@ -747,6 +757,7 @@ class MCPServer(Generic[LifespanResultT]):
icons: Optional list of icons for the prompt icons: Optional list of icons for the prompt
Example: Example:
```python
@server.prompt() @server.prompt()
def analyze_table(table_name: str) -> list[Message]: def analyze_table(table_name: str) -> list[Message]:
schema = read_table_schema(table_name) schema = read_table_schema(table_name)
@ -772,6 +783,7 @@ class MCPServer(Generic[LifespanResultT]):
} }
} }
] ]
```
""" """
# Check if user passed function directly instead of calling decorator # Check if user passed function directly instead of calling decorator
if callable(name): if callable(name):
@ -813,9 +825,11 @@ class MCPServer(Generic[LifespanResultT]):
include_in_schema: Whether to include in OpenAPI schema, defaults to True include_in_schema: Whether to include in OpenAPI schema, defaults to True
Example: Example:
```python
@server.custom_route("/health", methods=["GET"]) @server.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> Response: async def health_check(request: Request) -> Response:
return JSONResponse({"status": "ok"}) return JSONResponse({"status": "ok"})
```
""" """
def decorator( # pragma: no cover def decorator( # pragma: no cover

View file

@ -2,8 +2,8 @@
This module implements a Server-Sent Events (SSE) transport layer for MCP servers. This module implements a Server-Sent Events (SSE) transport layer for MCP servers.
Example usage: Example:
``` ```python
# Create an SSE transport at an endpoint # Create an SSE transport at an endpoint
sse = SseServerTransport("/messages/") sse = SseServerTransport("/messages/")
@ -27,7 +27,7 @@ Example usage:
# Create and run Starlette app # Create and run Starlette app
starlette_app = Starlette(routes=routes) starlette_app = Starlette(routes=routes)
uvicorn.run(starlette_app, host="127.0.0.1", port=port) uvicorn.run(starlette_app, host="127.0.0.1", port=port)
``` ```
Note: The handle_sse function must return a Response to avoid a Note: The handle_sse function must return a Response to avoid a
"TypeError: 'NoneType' object is not callable" error when client disconnects. The example above returns "TypeError: 'NoneType' object is not callable" error when client disconnects. The example above returns

View file

@ -4,8 +4,8 @@ This module provides functionality for creating an stdio-based transport layer
that can be used to communicate with an MCP client through standard input/output that can be used to communicate with an MCP client through standard input/output
streams. streams.
Example usage: Example:
``` ```python
async def run_server(): async def run_server():
async with stdio_server() as (read_stream, write_stream): async with stdio_server() as (read_stream, write_stream):
# read_stream contains incoming JSONRPCMessages from stdin # read_stream contains incoming JSONRPCMessages from stdin
@ -14,7 +14,7 @@ Example usage:
await server.run(read_stream, write_stream, init_options) await server.run(read_stream, write_stream, init_options)
anyio.run(run_server) anyio.run(run_server)
``` ```
""" """
import sys import sys

View file

@ -44,26 +44,38 @@ def create_mcp_http_client(
The returned AsyncClient must be used as a context manager to ensure The returned AsyncClient must be used as a context manager to ensure
proper cleanup of connections. proper cleanup of connections.
Examples: Example:
# Basic usage with MCP defaults Basic usage with MCP defaults:
```python
async with create_mcp_http_client() as client: async with create_mcp_http_client() as client:
response = await client.get("https://api.example.com") response = await client.get("https://api.example.com")
```
# With custom headers With custom headers:
```python
headers = {"Authorization": "Bearer token"} headers = {"Authorization": "Bearer token"}
async with create_mcp_http_client(headers) as client: async with create_mcp_http_client(headers) as client:
response = await client.get("/endpoint") response = await client.get("/endpoint")
```
# With both custom headers and timeout With both custom headers and timeout:
```python
timeout = httpx.Timeout(60.0, read=300.0) timeout = httpx.Timeout(60.0, read=300.0)
async with create_mcp_http_client(headers, timeout) as client: async with create_mcp_http_client(headers, timeout) as client:
response = await client.get("/long-request") response = await client.get("/long-request")
```
# With authentication With authentication:
```python
from httpx import BasicAuth from httpx import BasicAuth
auth = BasicAuth(username="user", password="pass") auth = BasicAuth(username="user", password="pass")
async with create_mcp_http_client(headers, timeout, auth) as client: async with create_mcp_http_client(headers, timeout, auth) as client:
response = await client.get("/protected-endpoint") response = await client.get("/protected-endpoint")
```
""" """
# Set MCP defaults # Set MCP defaults
kwargs: dict[str, Any] = {"follow_redirects": True} kwargs: dict[str, Any] = {"follow_redirects": True}

View file

@ -65,6 +65,7 @@ class UrlElicitationRequiredError(MCPError):
must complete one or more URL elicitations before the request can be processed. must complete one or more URL elicitations before the request can be processed.
Example: Example:
```python
raise UrlElicitationRequiredError([ raise UrlElicitationRequiredError([
ElicitRequestURLParams( ElicitRequestURLParams(
message="Authorization required for your files", message="Authorization required for your files",
@ -72,6 +73,7 @@ class UrlElicitationRequiredError(MCPError):
elicitation_id="auth-001" elicitation_id="auth-001"
) )
]) ])
```
""" """
def __init__(self, elicitations: list[ElicitRequestURLParams], message: str | None = None): def __init__(self, elicitations: list[ElicitRequestURLParams], message: str | None = None):

View file

@ -72,8 +72,10 @@ async def cancel_task(
- Task is already in a terminal state (completed, failed, cancelled) - Task is already in a terminal state (completed, failed, cancelled)
Example: Example:
```python
async def handle_cancel(ctx, params: CancelTaskRequestParams) -> CancelTaskResult: async def handle_cancel(ctx, params: CancelTaskRequestParams) -> CancelTaskResult:
return await cancel_task(store, params.task_id) return await cancel_task(store, params.task_id)
```
""" """
task = await store.get_task(task_id) task = await store.get_task(task_id)
if task is None: if task is None:

View file

@ -18,11 +18,13 @@ def get_display_name(obj: Tool | Resource | Prompt | ResourceTemplate | Implemen
For other objects: title > name For other objects: title > name
Example: Example:
```python
# In a client displaying available tools # In a client displaying available tools
tools = await session.list_tools() tools = await session.list_tools()
for tool in tools.tools: for tool in tools.tools:
display_name = get_display_name(tool) display_name = get_display_name(tool)
print(f"Available tool: {display_name}") print(f"Available tool: {display_name}")
```
Args: Args:
obj: An MCP object with name and optional title fields obj: An MCP object with name and optional title fields

View file

@ -25,6 +25,7 @@ class ResponseRouter(Protocol):
and deliver the response/error to the appropriate handler. and deliver the response/error to the appropriate handler.
Example: Example:
```python
class TaskResultHandler(ResponseRouter): class TaskResultHandler(ResponseRouter):
def route_response(self, request_id, response): def route_response(self, request_id, response):
resolver = self._pending_requests.pop(request_id, None) resolver = self._pending_requests.pop(request_id, None)
@ -32,6 +33,7 @@ class ResponseRouter(Protocol):
resolver.set_result(response) resolver.set_result(response)
return True return True
return False return False
```
""" """
def route_response(self, request_id: RequestId, response: dict[str, Any]) -> bool: def route_response(self, request_id: RequestId, response: dict[str, Any]) -> bool:

View file

@ -60,8 +60,10 @@ class RequestResponder(Generic[ReceiveRequestT, SendResultT]):
cancellation handling: cancellation handling:
Example: Example:
```python
with request_responder as resp: with request_responder as resp:
await resp.respond(result) await resp.respond(result)
```
The context manager ensures: The context manager ensures:
1. Proper cancellation scope setup and cleanup 1. Proper cancellation scope setup and cleanup

View file

@ -77,7 +77,8 @@ class StreamSpyCollection:
def stream_spy() -> Generator[Callable[[], StreamSpyCollection], None, None]: def stream_spy() -> Generator[Callable[[], StreamSpyCollection], None, None]:
"""Fixture that provides spies for both client and server write streams. """Fixture that provides spies for both client and server write streams.
Example usage: Example:
```python
async def test_something(stream_spy): async def test_something(stream_spy):
# ... set up server and client ... # ... set up server and client ...
@ -92,6 +93,7 @@ def stream_spy() -> Generator[Callable[[], StreamSpyCollection], None, None]:
# Clear for the next operation # Clear for the next operation
spies.clear() spies.clear()
```
""" """
client_spy = None client_spy = None
server_spy = None server_spy = None