You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a `list_roots_callback` is provided, the client automatically declares the `roots` capability (with `listChanged=True`) during initialization.
354
+
355
+
### Roots Change Notifications
356
+
357
+
When the client's workspace roots change (e.g., a folder is added or removed), notify the server:
358
+
359
+
```python
360
+
# After roots change, notify the server
361
+
await session.send_roots_list_changed()
362
+
```
363
+
364
+
## SSE Transport (Legacy)
365
+
366
+
For servers that use the older SSE transport, use `sse_client()` from `mcp.client.sse`:
367
+
368
+
```python
369
+
import asyncio
370
+
371
+
from mcp import ClientSession
372
+
from mcp.client.sse import sse_client
373
+
374
+
375
+
asyncdefmain():
376
+
asyncwith sse_client("http://localhost:8000/sse") as (read_stream, write_stream):
377
+
asyncwith ClientSession(read_stream, write_stream) as session:
378
+
await session.initialize()
379
+
380
+
tools =await session.list_tools()
381
+
print(f"Available tools: {[t.name for t in tools.tools]}")
382
+
383
+
384
+
asyncio.run(main())
385
+
```
386
+
387
+
The `sse_client()` function accepts optional `headers`, `timeout`, `sse_read_timeout`, and `auth` parameters. The SSE transport is considered legacy; prefer [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) for new servers.
388
+
389
+
## Ping
390
+
391
+
Send a ping to verify the server is responsive:
392
+
393
+
```python
394
+
# After session.initialize()
395
+
result =await session.send_ping()
396
+
# Returns EmptyResult on success; raises on timeout
397
+
```
398
+
399
+
## Logging
400
+
401
+
### Receiving Log Messages
402
+
403
+
Pass a `logging_callback` to receive log messages from the server:
Request that the server change its minimum log level:
424
+
425
+
```python
426
+
await session.set_logging_level("debug")
427
+
```
428
+
429
+
The `level` parameter is a `LoggingLevel` string: `"debug"`, `"info"`, `"notice"`, `"warning"`, `"error"`, `"critical"`, `"alert"`, or `"emergency"`.
430
+
320
431
## Parsing Tool Results
321
432
322
433
When calling tools through MCP, the `CallToolResult` object contains the tool's response in a structured format. Understanding how to parse this result is essential for properly handling tool outputs.
Both clients and servers can send ping requests to check that the other side is responsive:
30
+
31
+
```python
32
+
# From a client
33
+
result =await session.send_ping()
34
+
35
+
# From a server (via ServerSession)
36
+
result =await server_session.send_ping()
37
+
```
38
+
39
+
Both return an `EmptyResult` on success. If the remote side does not respond within the session timeout, an exception is raised.
40
+
41
+
## Cancellation
42
+
43
+
Either side can cancel a previously-issued request by sending a `CancelledNotification`:
44
+
45
+
```python
46
+
import mcp.types as types
47
+
48
+
# Send a cancellation notification
49
+
await session.send_notification(
50
+
types.ClientNotification(
51
+
types.CancelledNotification(
52
+
params=types.CancelledNotificationParams(
53
+
requestId="request-id-to-cancel",
54
+
reason="User navigated away",
55
+
)
56
+
)
57
+
)
58
+
)
59
+
```
60
+
61
+
The `CancelledNotificationParams` fields:
62
+
63
+
-`requestId` (optional): The ID of the request to cancel. Required for non-task cancellations.
64
+
-`reason` (optional): A human-readable string describing why the request was cancelled.
65
+
66
+
## Capability Negotiation
67
+
68
+
During initialization, the client and server exchange capability declarations. The Python SDK automatically declares capabilities based on which callbacks and handlers are registered:
69
+
70
+
**Client capabilities** (auto-declared when callbacks are provided):
71
+
72
+
-`sampling` -- declared when `sampling_callback` is passed to `ClientSession`
73
+
-`roots` -- declared when `list_roots_callback` is passed to `ClientSession`
74
+
-`elicitation` -- declared when `elicitation_callback` is passed to `ClientSession`
75
+
76
+
**Server capabilities** (auto-declared when handlers are registered):
77
+
78
+
-`prompts` -- declared when a `list_prompts` handler is registered
79
+
-`resources` -- declared when a `list_resources` handler is registered
80
+
-`tools` -- declared when a `list_tools` handler is registered
81
+
-`logging` -- declared when a `set_logging_level` handler is registered
82
+
-`completions` -- declared when a `completion` handler is registered
83
+
84
+
After initialization, clients can inspect server capabilities:
85
+
86
+
```python
87
+
capabilities = session.get_server_capabilities()
88
+
if capabilities and capabilities.tools:
89
+
tools =await session.list_tools()
90
+
```
91
+
92
+
## Protocol Version Negotiation
93
+
94
+
The SDK defines `LATEST_PROTOCOL_VERSION` and `SUPPORTED_PROTOCOL_VERSIONS` in `mcp.shared.version`:
95
+
96
+
```python
97
+
from mcp.shared.version importLATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS
98
+
99
+
# LATEST_PROTOCOL_VERSION is the version the SDK advertises during initialization
100
+
# SUPPORTED_PROTOCOL_VERSIONS lists all versions the SDK can work with
101
+
```
102
+
103
+
During initialization, the client sends `LATEST_PROTOCOL_VERSION`. If the server responds with a version not in `SUPPORTED_PROTOCOL_VERSIONS`, the client raises a `RuntimeError`. This ensures both sides agree on a compatible protocol version before exchanging messages.
104
+
105
+
## JSON Schema (2020-12)
106
+
107
+
MCP uses [JSON Schema 2020-12](https://json-schema.org/draft/2020-12) for tool input schemas, output schemas, and elicitation schemas. When using Pydantic models, schemas are generated automatically via `model_json_schema()`:
For FastMCP tools, input schemas are derived automatically from function signatures. For structured output, the output schema is derived from the return type annotation.
0 commit comments