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
Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,7 @@
18
18
>
19
19
> **v1.x is the only stable release line and remains recommended for production.** It lives on the [`v1.x` branch](https://github.com/modelcontextprotocol/python-sdk/tree/v1.x) and continues to receive critical bug fixes and security patches; see [the v1.x README](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/README.md) for its documentation. `pip` and `uv` don't select a pre-release unless you explicitly request one, so existing installs are unaffected. **If your package depends on `mcp`, add a `<2` upper bound to your version constraint (for example `mcp>=1.27,<2`) before the stable release lands.**
20
20
>
21
-
> v2 is a major rework of the SDK, both to support the [2026-07-28 MCP specification release](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/) and to fix long-standing architectural issues. See [What's new in v2](https://py.sdk.modelcontextprotocol.io/v2/whats-new/) for the tour of what changed, and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/) for every breaking change. Stable v2 is targeted for 2026-07-27, alongside the spec release. Try the pre-releases and [tell us what breaks](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml), or discuss in [#python-sdk-dev on the MCP Contributors Discord](https://discord.gg/6CSzBmMkjX).
21
+
> v2 is a major rework of the SDK, both to support the [2026-07-28 MCP specification release](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/) and to fix long-standing architectural issues. See [What's new in v2](https://py.sdk.modelcontextprotocol.io/v2/whats-new/) for the tour of what changed, and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/) for every breaking change. Stable v2 is targeted for 2026-07-28, alongside the spec release. Try the pre-releases and [tell us what breaks](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=v2-feedback.yaml), or discuss in [#python-sdk-dev on the MCP Contributors Discord](https://discord.gg/6CSzBmMkjX).
Copy file name to clipboardExpand all lines: docs/client/caching.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -51,7 +51,7 @@ Four calls, three fetches. The second call found a fresh entry and never reached
51
51
52
52
One rule sits above `"use"`: **calls carrying `meta` always reach the server.** A request with `meta` set (a progress token, tracing fields) expects a wire request, so under `cache_mode="use"` it is treated as `"refresh"`: the cache read is skipped, and the fetched result still replaces the cached entry. `"bypass"` and an explicit `"refresh"` behave as they always do.
53
53
54
-
To turn caching off entirely, construct with `Client(server, cache=False)`: every call is a round trip again, and `cache_mode`, while still accepted, does nothing.
54
+
To turn caching off entirely, construct with `Client(server, cache=None)`: every call is a round trip again, and `cache_mode`, while still accepted, does nothing.
55
55
56
56
Scope is honored automatically too: `"private"` entries are keyed to the cache's *partition* (below), while `"public"` ones may opt into wider sharing. And **notifications beat TTL** for the exact entries they name: a `list_changed` notification evicts the matching cached listing, and `resources/updated` evicts the cached read stored under exactly its URI, however fresh they were. On a 2026-07-28 connection those notifications arrive on a `subscriptions/listen` stream you open with `client.listen(...)`, and eviction completes before your watcher sees the event; **[Subscriptions](subscriptions.md)** is that page.
57
57
@@ -114,4 +114,4 @@ Clients on pre-2026 protocol versions never see either field; the SDK strips the
114
114
* A handler that sets the fields on its result overrides the map, per field.
115
115
*`"public"` is a promise that the result is identical for every caller. It is not access control.
116
116
*`Client` honors the hints automatically: its response cache is on by default, serves fresh entries instead of refetching, and caches nothing for servers (or sessions) that provide no hints.
117
-
* Per call, `cache_mode="refresh"` refetches and `"bypass"` skips the cache; `cache=False` at construction turns it off entirely.
117
+
* Per call, `cache_mode="refresh"` refetches and `"bypass"` skips the cache; `cache=None` at construction turns it off entirely.
Copy file name to clipboardExpand all lines: docs/client/callbacks.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -135,7 +135,7 @@ Two more. Neither declares anything.
135
135
136
136
`logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**[Logging](../handlers/logging.md)** has what to do instead), so this callback exists for the servers that still emit it.
137
137
138
-
`message_handler` is the catch-all: every server notification reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
138
+
`message_handler` is the catch-all: every server notification the session surfaces reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. Two never do: `notifications/cancelled` is applied by the SDK rather than surfaced, and a subscription acknowledgment for a live `listen()` stream is consumed by that stream. Annotate the parameter with `IncomingMessage` (`ServerNotification | Exception`, exported from `mcp.client`). The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
Copy file name to clipboardExpand all lines: docs/client/oauth-clients.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -83,7 +83,7 @@ The first time `Client` sends a request, the server answers `401`. The provider
83
83
84
84
After that it is quiet. Tokens come out of storage, an expired access token is refreshed with the refresh token, and only when none of that works does it run the flow again.
85
85
86
-
You wrote none of it. Three keyword arguments remain (`timeout`, `client_metadata_url` and `validate_resource_url`), and this file needs none of them. `client_metadata_url` is the one worth knowing about; it gets its own section below.
86
+
You wrote none of it. Two keyword arguments remain (`client_metadata_url` and `validate_resource_url`), and this file needs neither. `client_metadata_url` is the one worth knowing about; it gets its own section below.
87
87
88
88
### Try it
89
89
@@ -112,7 +112,7 @@ A nightly job, a CI step, another service. There is no browser and nobody to cli
112
112
What changed:
113
113
114
114
* No `OAuthClientMetadata`, no handlers. You pass `client_id` and `client_secret`; the provider builds a minimal `client_credentials` registration around them and skips dynamic registration entirely.
115
-
*`scopes` is a space-separated string, the OAuth wire format.
115
+
*`scope` is a space-separated string, the OAuth wire format.
116
116
* Everything downstream is identical: the same `TokenStorage`, the same `httpx2.AsyncClient(auth=...)`, the same `streamable_http_client`.
117
117
118
118
By default the secret travels as HTTP Basic auth on the token request (`client_secret_basic`). Pass `token_endpoint_auth_method="client_secret_post"` to put it in the form body instead. Some authorization servers only accept one of the two.
Copy file name to clipboardExpand all lines: docs/get-started/installation.md
-1Lines changed: 0 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,6 @@ You don't need to know any of this to use the SDK, but if you're wondering what
34
34
*`mcp-types`: every protocol type (requests, results, content blocks) as its own package, versioned in lockstep with the SDK. Every `from mcp_types import ...` in these docs is this package.
35
35
*[`anyio`](https://anyio.readthedocs.io/): the async runtime. The whole SDK is written against anyio, so it runs on either `asyncio` or `trio`.
36
36
*[`pydantic`](https://docs.pydantic.dev/): what every `mcp_types` model is built on, plus all schema generation and validation.
37
-
*[`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/): server configuration via `MCP_*` environment variables and `.env` files.
38
37
*[`httpx2`](https://pypi.org/project/httpx2/): the HTTP client behind the Streamable HTTP and SSE *client* transports, with server-sent events support built in.
39
38
*[`starlette`](https://www.starlette.io/), [`uvicorn`](https://www.uvicorn.org/), [`sse-starlette`](https://pypi.org/project/sse-starlette/), and [`python-multipart`](https://pypi.org/project/python-multipart/): the HTTP *server* transports.
40
39
*[`jsonschema`](https://pypi.org/project/jsonschema/): validates a tool's structured output against its declared output schema.
Copy file name to clipboardExpand all lines: docs/get-started/real-host.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -165,7 +165,7 @@ Once that command sits and waits, what's left is almost always one of three thin
165
165
166
166
***A relative path.** The host launches your server from *its* working directory, not the one you registered from. `server.py` where `/absolute/path/to/server.py` is needed is the single most common failure. If the host can't find `uv` either, that path has to be absolute too.
167
167
***The host is still running its old config.** Hosts read their config at launch. Claude Desktop in particular has to be *fully quit* (not just its window closed) and reopened before an edit to `claude_desktop_config.json` takes effect.
168
-
***Something reached stdout.** On stdio, stdout *is* the protocol. One stray `print()`and the host reads a corrupt message and drops the connection. Log with the `logging`module, which writes to stderr. **[Logging](../handlers/logging.md)** has the whole story.
168
+
***Something reached stdout outside the diverted window.** On stdio, stdout *is* the protocol. The SDK diverts flushed stray output to stderr while serving, but output flushed to stdout before then (a wrapper script echoing, an import-time `print()`in an unbuffered process), or a buffered `print()` drained at interpreter exit, hands the host a corrupt message and it drops the connection. Log with the default `logging`configuration, whose stderr handler flushes each record; custom handlers must also avoid stdout. **[Logging](../handlers/logging.md)** has the whole story.
169
169
170
170
Claude Desktop keeps a log per server: `mcp-server-<NAME>.log` is your server's stderr, next to `mcp.log` for connections, under `~/Library/Logs/Claude` on macOS and `%APPDATA%\Claude\logs` on Windows.
Copy file name to clipboardExpand all lines: docs/handlers/logging.md
+6-3Lines changed: 6 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,8 +33,11 @@ For a **stdio** server this question matters more than usual. The host launched
33
33
The standard library already does the right thing: log output goes to `sys.stderr` by default. Your `logger.info(...)` lines land in the terminal (or wherever the host collects the subprocess's stderr), and the protocol stream stays clean.
34
34
35
35
!!! tip
36
-
Never `print()` in a stdio server. `print` writes to **stdout**, and stdout *is* the wire: one stray
37
-
line and the client is trying to parse it as JSON-RPC.
36
+
Don't `print()` in a stdio server. `print` writes to **stdout**, and stdout belongs to the protocol.
37
+
While serving, the SDK diverts stdout that is actually *flushed* to stderr, so it can't corrupt the
38
+
wire, but a `print()` in a block-buffered process usually sits unflushed in `sys.stdout`'s buffer
39
+
until the interpreter drains it at exit, straight onto the protocol stream. Even when it is diverted,
40
+
the line lands raw among the log output, with no level, no logger name, and no way to filter it.
38
41
39
42
`logger.debug("got here")` is the same one line of effort and goes to the right place.
40
43
@@ -72,7 +75,7 @@ went to standard error: the terminal, not the wire.
72
75
* The MCP protocol's logging capability is deprecated by the 2026-07-28 spec and not replaced. Don't build on it.
73
76
*`logger = logging.getLogger(__name__)` at module level, `logger.info(...)` in the tool. That's the whole pattern.
74
77
* Log output never reaches the model. Only the value you `return` does.
75
-
* Standard error is yours; stdout belongs to the protocol. Never `print()`in a stdio server.
78
+
* Standard error is yours; stdout belongs to the protocol. The SDK diverts flushed stray stdout to stderr while serving, but an unflushed `print()`can still drain onto the wire at exit, and diverted lines arrive unlabeled; use `logging`, whose handler flushes every record.
76
79
*`MCPServer(..., log_level="DEBUG")` sets the level, and a logging configuration you made first is left alone.
77
80
78
81
Telling connected clients that something on your server changed (the tool list, a resource) is **[Subscriptions](subscriptions.md)**.
0 commit comments