Skip to content

Commit 86aa630

Browse files
committed
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.
1 parent b19d830 commit 86aa630

33 files changed

Lines changed: 485 additions & 444 deletions

README.v2.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
>
2020
> 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.
2121
>
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.**
2323
>
2424
> 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).
2525
2626
## Documentation
2727

2828
**The documentation lives at <https://py.sdk.modelcontextprotocol.io/v2/>.**
2929

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/).
3131

3232
## What is MCP?
3333

@@ -47,7 +47,7 @@ Python 3.10+.
4747
uv add "mcp[cli]" # or: pip install "mcp[cli]"
4848
```
4949

50-
While v2 is in pre-release you must pin the version explicitlyan 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.
5151

5252
## A server in 15 lines
5353

@@ -89,7 +89,7 @@ Notice what you did **not** write: no JSON Schema (`a: int, b: int` _is_ the sch
8989

9090
## A client in 10 lines
9191

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:
9393

9494
```python
9595
import asyncio
@@ -116,7 +116,7 @@ We are passionate about supporting contributors of all levels of experience and
116116

117117
## License
118118

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.
120120

121121
[pypi-badge]: https://img.shields.io/pypi/v/mcp.svg
122122
[pypi-url]: https://pypi.org/project/mcp/

docs/advanced/authorization.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ In OAuth terms, your server is a **resource server**. It never signs anyone in a
66

77
## The three parties
88

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).
1010
* The **resource server** is your MCP server. It verifies the token on every request.
1111
* The **client** discovers which authorization server you trust, gets a token from it, and sends it back to you as `Authorization: Bearer <token>`.
1212

@@ -26,9 +26,9 @@ The SDK has no opinion about what a valid token looks like. You tell it, by impl
2626

2727
`AuthSettings` is the public face of your resource server:
2828

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.
3232

3333
!!! tip
3434
`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.
6161
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.
6262

6363
!!! 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
6565
stopped at the door:
6666

6767
```text
@@ -72,11 +72,11 @@ This document is how a client that has never heard of your server finds its way
7272
```
7373

7474
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.
7676

7777
!!! warning
7878
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
8080
goes for the in-memory `Client(mcp)` you use in tests: it connects straight to the server object
8181
and skips the HTTP layer, authorization included.
8282

@@ -88,8 +88,8 @@ Inside any handler, **`get_access_token()`** is the `AccessToken` your verifier
8888
--8<-- "docs_src/authorization/tutorial002.py"
8989
```
9090

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.
9393
* Outside an authenticated HTTP request it returns `None`. In-memory and over `stdio` it is always `None`.
9494

9595
Call `whoami` with `Authorization: Bearer alice-token` and the model reads:
@@ -102,7 +102,7 @@ alice (scopes: notes:read)
102102

103103
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.
104104

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.
106106

107107
!!! info
108108
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
112112
## Recap
113113

114114
* 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.
116116
* `token_verifier=` and `auth=AuthSettings(issuer_url=..., resource_server_url=..., required_scopes=[...])` always travel together.
117117
* 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.
118118
* `get_access_token()` in any handler is who's calling.
119119
* Authorization is an HTTP concern. `stdio` and the in-memory client never see it.
120120

121-
The other side of the handshakea 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**.

docs/advanced/deprecated.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22

33
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**.
44

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.
66

77
## What is deprecated
88

99
| Deprecated | Why | What you do instead |
1010
|---|---|---|
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-
| **Clientserver progress**`client.send_progress_notification()` | 2026-07-28 makes progress serverclient 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**). |
1616

1717
Three things fall out of that table:
1818

1919
* Roots, sampling, and logging go together. One proposal, **SEP-2577**, deprecates all three capabilities at once.
2020
* 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"*.
2222

2323
## Deprecated is advisory
2424

@@ -35,9 +35,9 @@ MCPDeprecationWarning: The logging capability is deprecated as of 2026-07-28 (SE
3535
`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.
3636

3737
!!! warning
38-
"Advisory" stops at the wire. Sampling and roots are serverclient *requests*, and a
38+
"Advisory" stops at the wire. Sampling and roots are server-to-client *requests*, and a
3939
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
4141
fails with an error:
4242

4343
```text
@@ -64,7 +64,7 @@ from mcp import MCPDeprecationWarning
6464
warnings.filterwarnings("ignore", category=MCPDeprecationWarning)
6565
```
6666

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.
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.
6868

6969
!!! check
7070
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 —
8181

8282
## Recap
8383

84-
* The 2026-07-28 spec deprecates **roots**, server-initiated **sampling**, and protocol **logging** (all SEP-2577), restricts **progress** to serverclient, 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).
8787
* 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.
8888
* `warnings.filterwarnings("ignore", category=MCPDeprecationWarning)` silences the whole category; `"error::mcp.MCPDeprecationWarning"` in pytest turns it into a test failure.
8989
* New code should not be built on any of these.
9090

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

Comments
 (0)