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
docs: plain ASCII punctuation throughout; rename the "Check it" sections
Review feedback on the new docs:
- Em-dashes, arrows, ellipses and the rest of the typographic non-ASCII are
gone from every page and example (457 em-dashes); each site is rewritten
as the punctuation the sentence wanted. A new test in
tests/docs_src/test_shape.py pins the rule for the book's own files.
One of these characters was also a real bug: pytest-examples pipes fence
source to ruff in the platform encoding, so a U+2026 inside two media.md
fences failed ruff on every Windows CI cell. That failure class is now
impossible.
- The recurring "### Check it" section heading becomes "### Try it".
- A few sentences that narrated the documentation instead of the SDK are now
plain statements of fact.
- The README, index and installation pages pin the newest real pre-release
(2.0.0a2) instead of a 2.0.0aN placeholder nobody can install.
Copy file name to clipboardExpand all lines: README.v2.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,15 +19,15 @@
19
19
>
20
20
> 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 the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/) for what's changed. We're targeting a beta on 2026-06-30 and a stable v2 on 2026-07-27, alongside the spec release. Before stable, we plan to add a significant set of backwards compatibility shims so the final upgrade is much smaller than today's diff.
21
21
>
22
-
> **v1.x is the only stable release line and remains recommended for production.** It is in maintenance mode and continues to receive critical bug fixes and security patches. Installers never select a pre-release unless you opt in (for example `pip install mcp==2.0.0aN`), 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.**
22
+
> **v1.x is the only stable release line and remains recommended for production.** It is in maintenance mode and continues to receive critical bug fixes and security patches. Installers never select a pre-release unless you opt in (for example `pip install mcp==2.0.0a2`), 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.**
23
23
>
24
24
> Try the alpha and tell us what breaks: [#python-sdk-dev on the MCP Contributors Discord](https://discord.gg/6CSzBmMkjX). For v1 documentation, see [the v1.x README](https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/README.md).
25
25
26
26
## Documentation
27
27
28
28
**The documentation lives at <https://py.sdk.modelcontextprotocol.io/v2/>.**
29
29
30
-
This README is just the pitch. The site has the full [tutorial](https://py.sdk.modelcontextprotocol.io/v2/tutorial/), the [API reference](https://py.sdk.modelcontextprotocol.io/v2/api/mcp/), and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/).
30
+
It has the full [tutorial](https://py.sdk.modelcontextprotocol.io/v2/tutorial/), the [API reference](https://py.sdk.modelcontextprotocol.io/v2/api/mcp/), and the [migration guide](https://py.sdk.modelcontextprotocol.io/v2/migration/).
31
31
32
32
## What is MCP?
33
33
@@ -47,7 +47,7 @@ Python 3.10+.
47
47
uv add "mcp[cli]"# or: pip install "mcp[cli]"
48
48
```
49
49
50
-
While v2 is in pre-release you must pin the version explicitly — an unpinned install resolves to the latest stable v1.x, which this README does not describe. Use `uv add "mcp[cli]==2.0.0aN"` (check [PyPI](https://pypi.org/project/mcp/#history) for the newest pre-release), and `uv run --with "mcp==2.0.0aN"` for one-off commands.
50
+
While v2 is in pre-release you must pin the version explicitly: an unpinned install resolves to the latest stable v1.x, which this README does not describe. Use `uv add "mcp[cli]==2.0.0a2"` (check [PyPI](https://pypi.org/project/mcp/#history) for the newest pre-release), and `uv run --with "mcp==2.0.0a2"` for one-off commands.
51
51
52
52
## A server in 15 lines
53
53
@@ -89,7 +89,7 @@ Notice what you did **not** write: no JSON Schema (`a: int, b: int` _is_ the sch
89
89
90
90
## A client in 10 lines
91
91
92
-
The same package is a full MCP **client**. `Client` connects to a URL, a stdio subprocess, a custom transport — or, for tests, straight to a server object in memory, with no transport at all:
92
+
The same package is a full MCP **client**. `Client` connects to a URL, a stdio subprocess, a custom transport, or (for tests) straight to a server object in memory with no transport at all:
93
93
94
94
```python
95
95
import asyncio
@@ -116,7 +116,7 @@ We are passionate about supporting contributors of all levels of experience and
116
116
117
117
## License
118
118
119
-
This project is licensed under the MIT License — see the [LICENSE](https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE) file for details.
119
+
This project is licensed under the MIT License. See the [LICENSE](https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE) file for details.
Copy file name to clipboardExpand all lines: docs/advanced/authorization.md
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ In OAuth terms, your server is a **resource server**. It never signs anyone in a
6
6
7
7
## The three parties
8
8
9
-
* The **authorization server** signs people in and issues access tokens. You don't write this — it's your identity provider (Auth0, Keycloak, Entra, your own).
9
+
* The **authorization server** signs people in and issues access tokens. You don't write this. It's your identity provider (Auth0, Keycloak, Entra, your own).
10
10
* The **resource server** is your MCP server. It verifies the token on every request.
11
11
* The **client** discovers which authorization server you trust, gets a token from it, and sends it back to you as `Authorization: Bearer <token>`.
12
12
@@ -26,9 +26,9 @@ The SDK has no opinion about what a valid token looks like. You tell it, by impl
26
26
27
27
`AuthSettings` is the public face of your resource server:
28
28
29
-
*`issuer_url` — the authorization server that issues your tokens.
30
-
*`resource_server_url` — the public URL of this MCP endpoint. It names *which* resource a token is for, and it's where the discovery document lives.
31
-
*`required_scopes` — every token must carry all of them.
29
+
*`issuer_url`: the authorization server that issues your tokens.
30
+
*`resource_server_url`: the public URL of this MCP endpoint. It names *which* resource a token is for, and it's where the discovery document lives.
31
+
*`required_scopes`: every token must carry all of them.
32
32
33
33
!!! tip
34
34
`examples/servers/simple-auth/` in the SDK repository has an `IntrospectionTokenVerifier` that calls
@@ -61,7 +61,7 @@ You registered one tool. The second route is the SDK's.
61
61
This document is how a client that has never heard of your server finds its way in: it reads `authorization_servers` and goes there for a token. You wrote none of it.
62
62
63
63
!!! check
64
-
Call `/mcp` with no token — or with one your verifier returned `None` for — and the request is
64
+
Call `/mcp` with no token (or with one your verifier returned `None` for) and the request is
65
65
stopped at the door:
66
66
67
67
```text
@@ -72,11 +72,11 @@ This document is how a client that has never heard of your server finds its way
72
72
```
73
73
74
74
Nothing was parsed and no tool ran. And that `resource_metadata` pointer in `WWW-Authenticate` is
75
-
what makes discovery automatic: 401 → metadata document → authorization server → token → retry.
75
+
what makes discovery automatic: 401 -> metadata document -> authorization server -> token -> retry.
76
76
77
77
!!! warning
78
78
None of this protects `stdio`. A pipe has no `Authorization` header, so `token_verifier` is never
79
-
consulted there — a`stdio` server's security boundary is the process that launched it. The same
79
+
consulted there. A`stdio` server's security boundary is the process that launched it. The same
80
80
goes for the in-memory `Client(mcp)` you use in tests: it connects straight to the server object
81
81
and skips the HTTP layer, authorization included.
82
82
@@ -88,8 +88,8 @@ Inside any handler, **`get_access_token()`** is the `AccessToken` your verifier
88
88
--8<--"docs_src/authorization/tutorial002.py"
89
89
```
90
90
91
-
* It works in tools, resources, and prompts, and there is nothing to pass around — the auth middleware stores it in a context variable per request.
92
-
* You get back the **same object your verifier built**: `client_id`, `scopes`, `subject`, `expires_at`, and any extra `claims` you attached. That's the hook for per-tool rules — read the scopes and refuse.
91
+
* It works in tools, resources, and prompts, and there is nothing to pass around: the auth middleware stores it in a context variable per request.
92
+
* You get back the **same object your verifier built**: `client_id`, `scopes`, `subject`, `expires_at`, and any extra `claims` you attached. That's the hook for per-tool rules: read the scopes and refuse.
93
93
* Outside an authenticated HTTP request it returns `None`. In-memory and over `stdio` it is always `None`.
94
94
95
95
Call `whoami` with `Authorization: Bearer alice-token` and the model reads:
@@ -102,7 +102,7 @@ alice (scopes: notes:read)
102
102
103
103
The SDK gives you the resource-server half: verify, advertise, refuse. It does not give you a login page, a consent screen, or a token.
104
104
105
-
To watch all three parties move, run `examples/servers/simple-auth/` from the SDK repository — a small authorization server and a resource server set up exactly like this page — and then point `examples/clients/simple-auth-client/` at it for the full discovery-and-token dance.
105
+
To watch all three parties move, run `examples/servers/simple-auth/` from the SDK repository (a small authorization server and a resource server set up exactly like this page) and then point `examples/clients/simple-auth-client/` at it for the full discovery-and-token dance.
106
106
107
107
!!! info
108
108
There is a second constructor argument, `auth_server_provider=`, that embeds a full authorization
@@ -112,10 +112,10 @@ To watch all three parties move, run `examples/servers/simple-auth/` from the SD
112
112
## Recap
113
113
114
114
* Over Streamable HTTP your server is an OAuth 2.1 **resource server**: it verifies tokens, it never issues them.
115
-
*`TokenVerifier` is the whole integration surface — one async method, token in, `AccessToken | None` out.
115
+
*`TokenVerifier` is the whole integration surface: one async method, token in, `AccessToken | None` out.
116
116
*`token_verifier=` and `auth=AuthSettings(issuer_url=..., resource_server_url=..., required_scopes=[...])` always travel together.
117
117
* The SDK publishes RFC 9728 Protected Resource Metadata at `/.well-known/oauth-protected-resource/...` and answers unauthenticated requests with a 401 whose `WWW-Authenticate` header points at it. That is the entire discovery story.
118
118
*`get_access_token()` in any handler is who's calling.
119
119
* Authorization is an HTTP concern. `stdio` and the in-memory client never see it.
120
120
121
-
The other side of the handshake — a client that discovers your authorization server and fetches the token for you — is **OAuth clients**.
121
+
The other side of the handshake, a client that discovers your authorization server and fetches the token for you, is **OAuth clients**.
Copy file name to clipboardExpand all lines: docs/advanced/deprecated.md
+14-14Lines changed: 14 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,23 +2,23 @@
2
2
3
3
The 2026-07-28 spec retires five things. The SDK still implements every one of them, and every one of them now carries a **deprecation warning**.
4
4
5
-
No other page in these docs will show them to you. This is that page: find your warning, read the row, build on the replacement.
5
+
The table below names each deprecated feature, why it is going away, and the replacement to build on.
6
6
7
7
## What is deprecated
8
8
9
9
| Deprecated | Why | What you do instead |
10
10
|---|---|---|
11
-
|**Roots** —`ctx.session.list_roots()`, `client.send_roots_list_changed()`, the `list_roots_callback=` you pass to `Client(...)`|[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577) retires the capability. | Take the paths that matter as ordinary tool arguments or resource URIs. |
12
-
|**Server-initiated sampling** — `ctx.session.create_message()`, the `sampling_callback=` you pass to `Client(...)`| SEP-2577 retires the capability. | Return `InputRequiredResult` and let the client retry the call —**Multi-round-trip requests**. |
13
-
|**Protocol logging** — `ctx.log()`, `ctx.debug()`, `ctx.info()`, `ctx.warning()`, `ctx.error()`, `ctx.session.send_log_message()`, `client.set_logging_level()`| SEP-2577 retires the capability. Nothing in-protocol replaces it. | Ordinary `import logging` to stderr —**Logging**. |
14
-
|**`ping`** —`client.send_ping()`|**Removed** from the protocol, not merely deprecated. There is no `ping` method in 2026-07-28. | Nothing. It only works against a `mode="legacy"` connection. |
15
-
|**Client→server progress** — `client.send_progress_notification()`| 2026-07-28 makes progress server→client only. | Nothing to send. Your *server* reports progress with `ctx.report_progress()`—**Progress**. |
11
+
|**Roots**:`ctx.session.list_roots()`, `client.send_roots_list_changed()`, the `list_roots_callback=` you pass to `Client(...)`|[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577) retires the capability. | Take the paths that matter as ordinary tool arguments or resource URIs. |
12
+
|**Server-initiated sampling**: `ctx.session.create_message()`, the `sampling_callback=` you pass to `Client(...)`| SEP-2577 retires the capability. | Return `InputRequiredResult` and let the client retry the call (see**Multi-round-trip requests**). |
13
+
|**Protocol logging**: `ctx.log()`, `ctx.debug()`, `ctx.info()`, `ctx.warning()`, `ctx.error()`, `ctx.session.send_log_message()`, `client.set_logging_level()`| SEP-2577 retires the capability. Nothing in-protocol replaces it. | Ordinary `import logging` to stderr (see**Logging**). |
14
+
|**`ping`**:`client.send_ping()`|**Removed** from the protocol, not merely deprecated. There is no `ping` method in 2026-07-28. | Nothing. It only works against a `mode="legacy"` connection. |
15
+
|**Client->server progress**: `client.send_progress_notification()`| 2026-07-28 makes progress server->client only. | Nothing to send. Your *server* reports progress with `ctx.report_progress()`(see**Progress**). |
16
16
17
17
Three things fall out of that table:
18
18
19
19
* Roots, sampling, and logging go together. One proposal, **SEP-2577**, deprecates all three capabilities at once.
20
20
* Sampling and roots share a deeper problem: they are the two places a **server** sends a **request** to the **client**. That whole direction is what 2026-07-28 replaces with **Multi-round-trip requests**.
21
-
*`ping` is the odd one out. The protocol does not deprecate it, it removes it. The SDK method still warns — its message says *removed*, not *deprecated* — and calling it on a modern connection answers with *"Method not found"*.
21
+
*`ping` is the odd one out. The protocol does not deprecate it, it removes it. The SDK method still warns (its message says *removed*, not *deprecated*) and calling it on a modern connection answers with *"Method not found"*.
22
22
23
23
## Deprecated is advisory
24
24
@@ -35,9 +35,9 @@ MCPDeprecationWarning: The logging capability is deprecated as of 2026-07-28 (SE
35
35
`MCPDeprecationWarning` subclasses `UserWarning`, **not**`DeprecationWarning`. That is deliberate: Python's default filter only shows `DeprecationWarning` in code run directly as `__main__`, which is how libraries deprecate things and nobody notices for two years. This one shows up everywhere, with no `-W` flag.
36
36
37
37
!!! warning
38
-
"Advisory" stops at the wire. Sampling and roots are server→client *requests*, and a
38
+
"Advisory" stops at the wire. Sampling and roots are server-to-client *requests*, and a
39
39
2026-07-28 session has no channel to carry one. Call `ctx.session.create_message()`
40
-
inside a tool on a modern connection and the warning still fires — and then the send
40
+
inside a tool on a modern connection and the warning still fires, and then the send
41
41
fails with an error:
42
42
43
43
```text
@@ -64,7 +64,7 @@ from mcp import MCPDeprecationWarning
That is the whole API. There is no per-method switch, and you don't want one — the point of one category is that one line silences it and one line brings it back.
67
+
That is the whole API. There is no per-method switch, and you don't want one: the point of one category is that one line silences it and one line brings it back.
68
68
69
69
!!! check
70
70
Run the filter the other way and you get a free regression test. Add
@@ -81,11 +81,11 @@ That is the whole API. There is no per-method switch, and you don't want one —
81
81
82
82
## Recap
83
83
84
-
* The 2026-07-28 spec deprecates **roots**, server-initiated **sampling**, and protocol **logging** (all SEP-2577), restricts **progress** to server→client, and removes **`ping`**.
85
-
* The replacement column points you onward: **Multi-round-trip requests** for sampling, **Logging** for logging, **Progress** for progress. Roots needs no chapter — pass the paths as arguments — and `ping` needs nothing at all.
86
-
* Deprecated is advisory: no wire changes, everything keeps working against pre-2026 sessions, and you get a visible `MCPDeprecationWarning`— a `UserWarning`, so it is on by default.
84
+
* The 2026-07-28 spec deprecates **roots**, server-initiated **sampling**, and protocol **logging** (all SEP-2577), restricts **progress** to server-to-client, and removes **`ping`**.
85
+
* The replacement column points you onward: **Multi-round-trip requests** for sampling, **Logging** for logging, **Progress** for progress. Roots needs no chapter (pass the paths as arguments) and `ping` needs nothing at all.
86
+
* Deprecated is advisory: no wire changes, everything keeps working against pre-2026 sessions, and you get a visible `MCPDeprecationWarning`(a `UserWarning`, so it is on by default).
87
87
* Sampling and roots additionally need a back-channel that a 2026-07-28 session does not have. On a modern connection they warn and then they raise.
88
88
*`warnings.filterwarnings("ignore", category=MCPDeprecationWarning)` silences the whole category; `"error::mcp.MCPDeprecationWarning"` in pytest turns it into a test failure.
89
89
* New code should not be built on any of these.
90
90
91
-
If a warning brought you here and a row in the table answered it, you are done — every other page in these docs teaches the current API.
91
+
Every other page in these docs teaches the current API.
0 commit comments