Thank you for your interest in contributing to the MCP Python SDK! This document provides guidelines and instructions for contributing.
Important
The most useful contribution is a good issue. Pull requests from outside the maintainer team are only reviewed when a maintainer has assigned you the linked issue, and others are closed automatically. The rest of this section explains why, and what we'd love help with.
This SDK is looked after by a very small team with limited time for review. Now that coding agents can turn any open issue into a plausible-looking pull request within hours, we receive far more PRs than we could ever read carefully — and reviewing a PR properly still takes as long as it always did. When an issue is well described, it's usually quicker for a maintainer, with tooling that already knows this codebase and its conventions, to write a fix that fits than to review and reshape someone else's.
What we can't produce ourselves is your context: what you were trying to do, what you expected, a minimal reproduction, the environment it breaks in, the constraint we hadn't considered. That's the valuable part, and it's what a good issue carries — so that's what we ask for first.
A PR from someone outside the maintainer team stays open when both of these hold:
- Its description links an open issue in this repository with a closing keyword (
Fixes #123,Closes #123,Resolves #123). - A maintainer has assigned that issue to you, or the issue carries the
help wantedlabel (which means we'd welcome a PR for it from anyone).
Otherwise a bot labels the PR missing-issue-link, leaves a comment explaining this, and closes it. If that happens to yours, there's no need to open a new one: it reopens automatically as soon as a maintainer assigns you the issue, or when you edit the description to link one that qualifies. While it's closed, push updates as new commits rather than force-pushing, since GitHub can't reopen a PR whose branch has been rewritten. This applies to small fixes like typos too — for those, an issue pointing at the problem is all we need.
Whether to assign an issue, and to whom, is a maintainer call, and it depends on our capacity at the time as much as on the change itself. Comments that only ask to be assigned don't factor into it, so please skip those (and don't have an agent post them). What does help is engaging with the issue itself: confirming the reproduction, asking about the intended behaviour, or briefly describing the approach you'd take. If you reported the issue and would like to fix it yourself, mention that in the issue — the reporter has first call if we do take an outside PR for it.
- You've hit a real bug. If you've run into a bug that affects your use case, that's extremely helpful for us to hear about. Talking through why it's a problem for you — rather than just that it is one — helps us both design the right fix and prioritise it, and a minimal reproduction makes it far more likely we can act quickly.
- You'd like to learn the codebase or contribute regularly. You're welcome, with one honest caveat: how much mentoring and review we can offer depends entirely on maintainer capacity, which is very limited at the moment, so replies may be slow and we may not be able to take everything on. The best way to start is by filing and triaging issues well and engaging on existing ones.
good first issuestill needs assignment — we'd like a short conversation first. You can find us in #python-sdk-dev on the MCP Contributors Discord. - You maintain another MCP SDK or work on the spec. Say so on the issue or in #python-sdk-dev; a maintainer can reopen a specific PR past the gate.
We use AI tooling constantly and have no problem with you using it too. What matters is that a person is accountable for the result:
- Disclose it. One line in the PR or issue description.
- Own it. You can explain the change and the reasoning in your own words, and when a maintainer asks a question the answer comes from you rather than being pasted from a chat window.
- Keep a human in the loop. Issues, PRs, and comments generated by an agent without a person who has actually hit the problem and read the output may be closed without warning. If you have an agent filing PRs against open issues autonomously, please turn it off for this repository.
- Keep issues short and factual. What happened, what you expected, and how to reproduce it.
Undisclosed AI contributions may be closed, and repeated cases can lead to a block from the modelcontextprotocol org. The org-wide AI contribution policy also applies.
Not every contribution will be accepted, even with a working implementation and an assigned issue. We prioritize maintainability and consistency over adding capabilities. This is at maintainers' discretion.
These always need discussion on an issue before anyone writes code:
- New public APIs or decorators
- Architectural changes or refactoring
- Changes that touch multiple modules
- Features that might require spec changes (these need a SEP first)
| Label | Meaning |
|---|---|
help wanted |
We'd welcome a PR for this from anyone — no assignment needed |
good first issue |
Approachable without deep codebase knowledge; still needs assignment (see above) |
ready for work |
Triaged and queued for a maintainer to pick up (not a call for PRs) |
needs confirmation, needs repro, needs decision, needs design |
Not actionable yet; more information or a maintainer decision is needed first |
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 (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 has the private channel.
- Make sure you have Python 3.10+ installed
- Install uv
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR-USERNAME/python-sdk.git - Install dependencies:
uv sync --frozen --all-extras --dev- Set up pre-commit hooks:
uv tool install pre-commit --with pre-commit-uv --force-reinstall-
Choose the correct branch for your changes:
Change Type Target Branch Example New features and fixes for v2 mainNew APIs, refactors Security fixes for v1 v1.xCritical patches Critical bug fixes for v1 v1.xBackports of severe bugs Note:
mainis the current stable line (v2). Thev1.xbranch is the previous major's maintenance line and receives only security and critical bug fixes. -
Create a new branch from your chosen base branch
-
Make your changes
-
Ensure tests pass:
uv run pytest- Run type checking:
uv run pyright- Run linting:
uv run ruff check .
uv run ruff format .- Update README snippets if you modified
docs_src/code embedded in the README:
uv run scripts/update_readme_snippets.py- (Optional) Run pre-commit hooks on all files:
pre-commit run --all-files- Open a pull request against the branch you started from — see Pull Requests; you need to be assigned to the linked issue first
- We use
rufffor linting and formatting - Follow PEP 8 style guidelines
- Add type hints to all functions
- Include docstrings for public APIs
Documentation contributions are English only: the pages under docs/ are the source of truth, and the translated documentation sites are generated from them, guided by the per-language style guides and glossaries under i18n/<lang>/. Never edit the generated pages under i18n/<lang>/pages/—the tool can't tell a hand edit from its own output, so the edit persists unchecked, is carried forward into future runs, and hides the real fix. To fix a translation, change that language's instructions.md or glossary.json (or the English page, if that's where the problem is) and re-run translate --lang <code> --pages <page> … for the affected pages; the fix then carries into every future run. See i18n/README.md for the details.
By the time you open a PR, you should be assigned to the issue it fixes (see How Pull Requests Get In) and the "what" and "why" should already be settled there. This keeps reviews focused on implementation.
- Put
Fixes #<issue>in the description — the intake gate looks for it. - If your PR was auto-closed, there's no need to open another: fix the description or wait to be assigned and it reopens itself. Avoid force-pushing the branch while it's closed.
Small PRs get reviewed fast. Large PRs sit in the queue.
A few dozen lines can be reviewed in minutes. Hundreds of lines across many files takes real effort and things slip through. If your change is big, break it into smaller PRs or get alignment from a maintainer first.
- No assigned issue: closed automatically until one is linked, as above
- Scope creep: changes that go beyond what was discussed on the issue
- Misalignment: even well-implemented features may be rejected if they don't fit the SDK's direction
- Overengineering: unnecessary complexity for simple problems
- Undisclosed or unreviewed AI output: see AI-Assisted Contributions
- Update documentation as needed
- Add tests for new functionality
- Ensure CI passes
- Address review feedback
- Dependency bound changes and new runtime dependencies follow the Dependency Policy
Please note that this project is released with a Code of Conduct. By participating in this project you agree to abide by its terms.
By contributing, you agree that your contributions will be licensed under the MIT License.