Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,25 @@
| [`help wanted`](https://github.com/modelcontextprotocol/python-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) | Experienced contributors | Maintainers probably won't get to this |
| [`ready for work`](https://github.com/modelcontextprotocol/python-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22ready+for+work%22) | Maintainers | Triaged and ready for a maintainer to pick up |

Issues labeled `needs confirmation` or `needs maintainer action` are **not** ready for work—wait for maintainer input first.
Issues labeled `needs confirmation` or `needs maintainer` are **not** ready for work—wait for maintainer input first.
Comment thread
maxisbey marked this conversation as resolved.
Resolved

Before starting, comment on the issue so we can assign it to you. This prevents duplicate effort.

## Issue Triage

Every new issue gets a first look from a maintainer within two business days. That first look is the *triage*: it means labeling the issue and deciding whether it is valid and actionable, not fixing it.

The core labels follow the shared [MCP SDK taxonomy](https://modelcontextprotocol.io/community/sdk-tiers#issue-triage-labels) (the repository also carries workflow labels of its own, such as `needs maintainer` and `needs decision`): one **type** (`bug`, `enhancement`, `question`), one **status** (`needs confirmation`, `needs repro`, `ready for work`, `good first issue`, `help wanted`), and — once actionable — one **priority**:

| Label | Meaning | Commitment |
|-------|---------|------------|
| `P0` | Critical: core functionality failures (connections, message exchange, tools/resources/prompts) or a High/Critical-severity security issue | resolved within 7 days |
| `P1` | Significant bug affecting many users | next release |
| `P2` | Moderate issue or valuable feature request | as capacity allows |
| `P3` | Nice-to-have or rare edge case | opportunistic |

Security reports do not belong in the issue tracker; [SECURITY.md](SECURITY.md) has the private channel.

## Development Setup

1. Make sure you have Python 3.10+ installed
Expand Down Expand Up @@ -125,6 +140,7 @@
- Follow PEP 8 style guidelines
- Add type hints to all functions
- Include docstrings for public APIs
- Changing a dependency's version bound or adding a runtime dependency follows the [Dependency Policy](DEPENDENCY_POLICY.md)

Check warning on line 143 in CONTRIBUTING.md

View check run for this annotation

Claude / Claude Code Review

[quality] nit: The new dependency-policy pointer is appended under the "## Code Style" heading, whose other bullets are ruff, PEP 8, type hints, and docstrings — a process/policy rule ("Changing a dependency's version bound or adding a runtime dependenc

[quality] nit: The new dependency-policy pointer is appended under the "## Code Style" heading, whose other bullets are ruff, PEP 8, type hints, and docstrings — a process/policy rule ("Changing a dependency's version bound or adding a runtime dependency follows the Dependency Policy") is not a code-style rule. The natural home is the "## Pull Requests" / Scope guidance (or Development Setup), where contributors planning a change actually look; DEPENDENCY_POLICY.md itself says such changes are
Comment thread
maxisbey marked this conversation as resolved.
Resolved

## Pull Requests

Expand Down
15 changes: 15 additions & 0 deletions DEPENDENCY_POLICY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Dependency Policy

`mcp` is a library that lives inside other people's environments, so its requirements are chosen to constrain your resolver as little as possible while still describing what the SDK needs.

## How requirements are declared

Every runtime dependency is a `>=` floor set to the oldest version that provides what the SDK uses, with no upper bound unless a dependency's next major is known to break the SDK. The one exception is `mcp-types`, the wire-types package released in lockstep with `mcp`: each `mcp` release requires exactly its own version of it, so it is the other half of the SDK rather than an independent constraint.

## When a floor moves

A floor is raised only when the SDK starts relying on something that first appeared in that version — not because the dependency published a security advisory. The `>=` bound already lets, and expects, you to run the newest release your other constraints allow, so a higher floor would only shrink the environments the SDK installs into; nor does the SDK add code to work around a dependency's vulnerability, since the fix belongs upstream and in your lockfile ([background](https://github.com/Kludex/uvicorn/discussions/2643), [python-sdk#1552](https://github.com/modelcontextprotocol/python-sdk/issues/1552)). Adding a new runtime dependency, or moving one to its next major version, is decided in an issue before the pull request. Which of these may ship in a minor release is set by the [versioning policy](VERSIONING.md); floor raises are called out in the release notes.

Check warning on line 11 in DEPENDENCY_POLICY.md

View check run for this annotation

Claude / Claude Code Review

nit: Dangling deferral between the two new policy docs: after "Adding a new runtime dependency, or moving one to its next major version, is decided in an issue", the sentence "Which of these may ship in a minor release is set by the [versioning policy](VE

nit: Dangling deferral between the two new policy docs: after "Adding a new runtime dependency, or moving one to its next major version, is decided in an issue", the sentence "Which of these may ship in a minor release is set by the [versioning policy](VERSIONING.md)" points at a document that never answers for one of the two cases — VERSIONING.md's "Allowed in a minor" list (lines 21-27) covers only "raising a dependency floor the SDK needs" (which subsumes the next-major move), while adding
Comment thread
maxisbey marked this conversation as resolved.
Resolved

## Automated updates

[Dependabot](https://github.com/modelcontextprotocol/python-sdk/blob/main/.github/dependabot.yml) opens monthly, grouped pull requests for the `uv` lockfile and for GitHub Actions. These refresh the versions the SDK is developed and tested against; the requirements published to PyPI move only under the rules above.
14 changes: 11 additions & 3 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

## Bumping Dependencies

[`DEPENDENCY_POLICY.md`](DEPENDENCY_POLICY.md) says *when* a bound should
move; this is the mechanics.
Comment thread
claude[bot] marked this conversation as resolved.
Resolved

1. Change the dependency version in `pyproject.toml`. The root `mcp` project's
runtime dependencies are dynamic and live under
`[tool.hatch.metadata.hooks.uv-dynamic-versioning].dependencies`.
2. Upgrade lock with `uv lock --resolution lowest-direct`
2. Regenerate the lock with `uv lock` (or `uv lock --upgrade-package <package>`
Comment thread
maxisbey marked this conversation as resolved.
Resolved
to move just that package's locked version). The committed `uv.lock` is a
normal, newest-allowed resolution; the `lowest-direct` resolution that
Comment thread
maxisbey marked this conversation as resolved.
Resolved
proves the floors still work is applied only by its CI matrix leg at test
time and is never committed.

## Release lines

Expand Down Expand Up @@ -104,8 +111,9 @@ hand for the same reason as above. Then ask someone to review the release.
Pre-releases of the next version are cut from `main` with a PEP 440
pre-release tag: `aN` for alphas, later `bN`/`rcN` for betas and release
candidates. The PEP 440 suffix is what keeps `pip install mcp` on the stable
version — installers only select a pre-release when it is requested explicitly (an
exact pin, a specifier that names a pre-release version, or `--pre`).
version — installers select a pre-release only when it is requested explicitly (an
exact pin, a specifier that names a pre-release version, or `--pre`) or when no
final release satisfies the requirement at all.
Comment thread
maxisbey marked this conversation as resolved.
Resolved

1. During a pre-release phase the README and docs pin the exact pre-release
version, so update those examples first (grep the outgoing version — the
Expand Down
21 changes: 21 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Roadmap
Comment thread
maxisbey marked this conversation as resolved.
Resolved

The SDK's work is organized by MCP specification revision, with one GitHub project board per revision; each item is an issue or pull request you can follow.

## The 2026-07-28 revision

v2 implements the [2026-07-28 specification](https://modelcontextprotocol.io/specification/2026-07-28) and negotiates back to every earlier revision. Board: **[python-sdk · 2026-07-28 spec](https://github.com/orgs/modelcontextprotocol/projects/42)** (tracking issue [#2891](https://github.com/modelcontextprotocol/python-sdk/issues/2891)); the cross-SDK view is [2026-07-28 Spec Implementation](https://github.com/orgs/modelcontextprotocol/projects/41). Still open there: the capabilities API and `server/discover` handler ([#2896](https://github.com/modelcontextprotocol/python-sdk/issues/2896)).

Check warning on line 7 in ROADMAP.md

View check run for this annotation

Claude / Claude Code Review

nit: The roadmap's "Still open there: the capabilities API and `server/discover` handler ([#2896])" claims the `server/discover` handler is unimplemented work, but the SDK ships it: src/mcp/server/lowlevel/server.py:448 registers a default `("server/disco

nit: The roadmap's "Still open there: the capabilities API and `server/discover` handler ([#2896])" claims the `server/discover` handler is unimplemented work, but the SDK ships it: src/mcp/server/lowlevel/server.py:448 registers a default `("server/discover", types.RequestParams, self._handle_discover)` handler (implemented at lines 660-675), the client probes it by default (src/mcp/client/_probe.py), and docs/protocol-versions.md:29 states "MCPServer answers server/discover on every transport"
Comment thread
maxisbey marked this conversation as resolved.
Resolved

## Not yet implemented

The extensions and optional client-auth mechanisms this SDK does not implement yet are tracked as the entries in the conformance suite's expected-failures baseline, [`.github/actions/conformance/expected-failures.yml`](.github/actions/conformance/expected-failures.yml), which burns down as each lands:

* **Tasks extension** (`io.modelcontextprotocol/tasks`, [SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md)) — deferred at 2.0 because the 2026-07-28 design is wire-incompatible with the earlier in-core Tasks; tracked in [#2806](https://github.com/modelcontextprotocol/python-sdk/issues/2806).
* **DPoP-bound access tokens** ([SEP-1932](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1932)) in the OAuth client.
* **The workload-identity `jwt-bearer` grant** in the OAuth client.

Everything else — bugs and smaller features — lives in the [issue tracker](https://github.com/modelcontextprotocol/python-sdk/issues), prioritized `P0`–`P3`. The SDK aims to release support for each new specification revision alongside that revision.

## The previous major

`v1.x` is a maintenance line: critical bug fixes and security fixes only. Support terms are in [Versioning and support policy](VERSIONING.md#support-and-announcements); the path off it is the **[Migration Guide](https://py.sdk.modelcontextprotocol.io/migration/)**.
35 changes: 35 additions & 0 deletions VERSIONING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Versioning and support policy

What a version number of `mcp` promises: which changes can arrive in a minor release, which wait for a major, how deprecations are announced, and which release lines are supported.

## The version number

[Semantic Versioning](https://semver.org/) semantics in [PEP 440](https://peps.python.org/pep-0440/) syntax, taken from the git tag: in `2.X.Y`, **X** (minor) carries new functionality and every non-breaking change, **Y** (patch) carries bug fixes only, and a breaking change to the public API lands only in a new **major**. Pre-releases are cut from `main` as `aN`/`bN`/`rcN`; installers prefer final releases by default, so an unpinned `pip install mcp` stays on a stable release whenever one satisfies your requirement. `mcp` and its wire-types package `mcp-types` release in lockstep, each `mcp` requiring exactly the matching `mcp-types`.
Comment thread
maxisbey marked this conversation as resolved.
Resolved

## The public API

The promise covers every name exported by `mcp` and `mcp_types` (their `__all__`), the import paths, signatures, and behavior documented on the [documentation site](https://py.sdk.modelcontextprotocol.io/) and in its [API Reference](https://py.sdk.modelcontextprotocol.io/api/mcp/). It does not cover underscore-prefixed names, undocumented modules, or the wording of log lines, warnings, and exception messages (their types and documented raise conditions are covered). APIs labelled **provisional** (for example the middleware chain) may still change in a minor release; **experimental** APIs are opt-in previews.
Comment thread
maxisbey marked this conversation as resolved.
Resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nit: The public-API boundary is vacuous as written: it covers "signatures, and behavior documented ... in its API Reference" and carves out "undocumented modules", but the repo's reference generator (scripts/docs/gen_ref_pages.py) auto-writes an API Reference page for every non-underscore module of both packages (PACKAGES loop skips only components starting with '_' and the mcp.types alias in EXCLUDED). There are no undocumented non-underscore modules, so the carve-out matches nothing and the compatibility promise extends to the SDK's entire internal surface — e.g. mcp.shared.dispatcher, mcp.shared.inbound, mcp.shared.peer, mcp.shared.tool_name_validation, mcp.os.posix, mcp.cli all have generated reference pages, far beyond the __all__ boundary the same sentence (and AGENTS.md's "sr

Extended reasoning...

A maintainer renames a helper in mcp.shared.tool_name_validation (or changes a signature in mcp.shared.dispatcher) in a 2.x minor release, treating it as internal per AGENTS.md. A user who imported it points at VERSIONING.md: the name's signature is "documented ... in its API Reference" (the auto-generated page at /api/mcp/shared/tool_name_validation/) and is not underscore-prefixed nor in an "undocumented module", so under the published policy this is a breaking change that "lands only in a new major" — the SDK is now either in violation of its own versioning commitment or unable to refactor any non-underscore internal module until 3.0. The fix is to scope the promise to all exports plus hand-written docs pages, or to state that auto-generated reference pages do not by themselves confer API stability.

Verification: nit — the claim is factually true. VERSIONING.md:11 (added by this diff) covers "the import paths, signatures, and behavior documented ... in its API Reference" and carves out "undocumented modules", but scripts/docs/gen_ref_pages.py generates a reference page for every non-underscore module: the loop at lines 178–198 skips only components starting with "_" (lines 190–191) and EXCLUDED = fro


## Breaking and non-breaking changes

Held for the next major:

* removing or renaming a public name,
* changing a signature, return type, raised exception type, or documented behavior so that working code stops working,
* removing a documented import path, extra, or CLI command.

Allowed in a minor:

* additions — functions, defaulted parameters, classes, fields, enum members,
* changes to provisional or experimental APIs,
* new deprecation warnings, and the eventual removal of protocol features the specification has retired,
Comment thread
maxisbey marked this conversation as resolved.
Resolved
* raising a dependency floor the SDK needs (see the [dependency policy](DEPENDENCY_POLICY.md)) when the dependency's changes don't reach you through the SDK's API, or dropping a Python version after its upstream end-of-life — both called out in the release notes,
* bug fixes, including ones that make the SDK match its documented or specified behavior.

## Deprecations

**SDK APIs** are deprecated before removal: they keep working for at least one minor release, marked with [`typing_extensions.deprecated`](https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.deprecated) wherever Python can carry the marker (docstring and migration guide otherwise), and are removed only in a major. **Protocol features** the specification retires keep their implementation through the spec's deprecation window and warn with `MCPDeprecationWarning`, a `UserWarning` subclass that shows by default; what still functions depends on the revision a connection negotiated — see [Deprecated features](https://py.sdk.modelcontextprotocol.io/deprecated/).

## Support and announcements

Two lines are maintained and only the newest release of each receives fixes: **2.x** (`main`) gets bug fixes, security fixes, and features; **1.x** ([`v1.x`](https://github.com/modelcontextprotocol/python-sdk/tree/v1.x)) gets critical bug fixes and security fixes. [SECURITY.md](https://github.com/modelcontextprotocol/python-sdk/blob/main/SECURITY.md) has the reporting process. Every release publishes notes on [GitHub Releases](https://github.com/modelcontextprotocol/python-sdk/releases); every breaking change between majors is documented in the [Migration Guide](https://py.sdk.modelcontextprotocol.io/migration/) before it merges; and pull requests that make one carry the `breaking change` label.
Comment thread
maxisbey marked this conversation as resolved.
Resolved
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ You wrote two Python functions with type hints and a docstring. The SDK does the
* Already have a FastAPI or Starlette app? **[Add to an existing app](run/asgi.md)** mounts an MCP server inside it.
* Hunting an exact error message? **[Troubleshooting](troubleshooting.md)** is keyed by the verbatim text.
* Wondering what changed in v2? **[What's new in v2](whats-new.md)** is the five-minute tour.
* What a version number promises, and what is coming: **[Versioning and support policy](https://github.com/modelcontextprotocol/python-sdk/blob/main/VERSIONING.md)** and the **[Roadmap](https://github.com/modelcontextprotocol/python-sdk/blob/main/ROADMAP.md)**.
* Migrating from v1? Start with the **[Migration Guide](migration.md)**.
* Hunting for an exact signature? The **[API Reference](api/mcp/index.md)** is generated from the source.
* Reading with an LLM? This documentation is also published in the [llms.txt](https://llmstxt.org/) format:
Expand Down
Loading