MCP Python SDK v2: Building MCP Servers and Clients in Python
The official Python SDK for Model Context Protocol servers and clients
At a glance
- What is it?
- The official Python implementation of the Model Context Protocol, now on a v2 line that targets the 2026-07-28 specification. This covers what it does, how the server and client halves fit together, and what the v1 to v2 split means for your requirements file.
- Who is it for?
- Adopt it if you are writing an MCP server or client in Python and can run Python 3.10 or newer; the type hints and docstrings you already write become the protocol schema. Do not adopt it if you are on Python 3.9 or older, or if you need a non-Python implementation of the protocol.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What the MCP Python SDK solves, and for whom
The Model Context Protocol defines how an LLM application talks to external data and functionality. Without an SDK you would implement that wire protocol yourself: transport framing, request parsing, JSON Schema generation for every tool, and validation of incoming arguments. The README describes the protocol as "like a web API, but designed for LLM interactions," and this package is the Python side of that contract.
There are two audiences. The first is people building MCP servers, who want to expose existing Python functions as tools, resources and prompts that any MCP host can call. The second is people building MCP clients, who need to connect to servers someone else wrote. The same installed package covers both roles, which is unusual for an SDK and worth noting: you do not pick a server library or a client library, you import from mcp either way.
If you are writing a Python application that already has functions worth exposing to an assistant, this is the intended path. If you are writing a server in Go, TypeScript or Rust, this package is irrelevant to you.
How the decorator-to-protocol pipeline actually works
The mechanism is decorator registration plus type introspection. You create an MCPServer instance with a name, then decorate plain functions. The README's example registers add with @mcp.tool() and a templated resource at the URI pattern greeting://{name} with @mcp.resource(). The function signature a: int, b: int is the schema; the README states plainly that you write "no JSON Schema ... no request parsing, no validation code, no protocol handling."
The docstring becomes the description the model sees, which is why the README's example includes one on each function. The URI template greeting://{name} is parsed so that the path segment binds to the name parameter at call time, a pattern most Python web frameworks use for routing.
On the client side the flow is the reverse. A Client object is constructed with a URL or another transport, entered as an async context manager, and calls are dispatched by tool name with a dictionary of arguments. The result carries structured_content, which the README shows as {'result': 3} for the add call. Transports are stdio, Streamable HTTP and SSE, so the same server code can run as a local subprocess or as a deployed HTTP service.
Installing the MCP Python SDK and running a first server
The package name on PyPI is mcp, not python-sdk, and Python 3.10 or newer is required. The README gives two equivalent install lines, one for uv and one for pip:
uv add "mcp[cli]" # or: pip install "mcp[cli]"The cli extra pulls in typer and python-dotenv and installs the mcp command-line tool, which provides mcp dev, mcp run and mcp install. If you only need the library, install plain mcp. For a one-off command without a project, the README notes that uv run --with "mcp[cli]" mcp ... works.
A complete server is short enough to paste. Save this as server.py:
from mcp.server import MCPServer
mcp = MCPServer("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
"""Greet someone by name."""
return f"Hello, {name}!"Open it in the MCP Inspector with the dev command:
uv run mcp dev server.pyCalling add with a=1 and b=2 returns 3. To serve it over HTTP instead, the README uses the run command with an explicit transport:
uv run mcp run server.py --transport streamable-httpThat listens on localhost port 8000 at the path /mcp, which is the URL the README's client example passes to Client. The client then calls the tool by name and reads structured_content:
import asyncio
from mcp import Client
async def main() -> None:
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool("add", {"a": 1, "b": 2})
print(result.structured_content) # {'result': 3}
asyncio.run(main())One caveat on installation: pip install mcp now resolves to 2.x. That fact drives most of the friction described in the next section.
The v1 to v2 split is the sharpest edge here
The README opens with a note that this is v2, the current stable release line, and calls it a major rework both to support the 2026-07-28 MCP specification and to fix what it describes as long-standing architectural issues. A major rework means breaking changes, and the project documents them in a separate migration guide rather than in the README.
That creates a specific failure mode. A requirements file or lockfile that says mcp without an upper bound will silently move a v1 codebase onto v2 on the next install, because pip install mcp now installs 2.x. The README's own recommendation is to keep a <2 upper bound until you have migrated, and it gives mcp>=1.28,<2 as the example. If your CI installs without a lockfile, this is the first thing to check.
The v1 line is not abandoned: it lives on the v1.x branch, still receives critical bug fixes and security patches, and has its own documentation at py.sdk.modelcontextprotocol.io/v1/. So staying on v1 is a supported position, not a dead end. The trade-off is that you forgo the 2026-07-28 specification support, which the README frames as the primary reason v2 exists.
A second limitation is the language requirement. Python 3.10+ is a hard floor stated in both the README and pyproject.toml. Environments pinned to 3.9 or earlier cannot use this at all, and no backport is mentioned.
Where the documentation is thin
The README points at py.sdk.modelcontextprotocol.io for the Get started guide, the What's new in v2 tour, the API reference and the migration guide. It does not inline any of that content. If you are evaluating the SDK from the repository alone, you get one server example, one client example, and a list of transports. Details like authentication on a Streamable HTTP deployment, error handling when a tool raises, and how resource subscriptions behave are not covered in the README.
The repository layout suggests where those answers live. There is a docs/ directory, a docs_src/ directory of runnable snippets, an examples/ directory with subfolders for clients, mcpserver, servers, snippets and stories, and an i18n/ directory, which implies translated documentation. The FAQ-style material a new user wants is spread across those rather than consolidated.
One design choice worth flagging: the client example uses a bare URL string to select Streamable HTTP. That is convenient, but it means the transport is inferred from the argument type rather than named. The README says Client can also launch a local server as a stdio subprocess or take any custom transport, so the inference is a shorthand rather than a constraint. Still, when a connection fails, the first question is which transport you actually got.
How this compares to writing the protocol by hand
The obvious alternative is not another Python MCP library; it is implementing the protocol directly against the specification at modelcontextprotocol.io. That approach gives you exact control over framing, schema generation and transport behavior, and it adds no dependency to your project.
The difference in practice is the schema layer. Hand-rolling means writing JSON Schema for every tool, parsing incoming requests, validating argument types, and keeping all of that in sync when a function signature changes. The SDK derives the schema from the annotations, so add(a: int, b: int) is the schema and a signature change is a schema change. For a server with two tools that is a minor convenience. For a server with thirty tools and a team maintaining it, the hand-written schemas become a second source of truth that drifts.
The cost is coupling. You inherit the SDK's release cadence and its major-version breaks, which the v1 to v2 transition demonstrates. A hand-written implementation has no such migration, only the specification's own revisions to track. Teams with a very small, very stable tool surface may reasonably prefer that. Teams whose tool surface changes weekly will not want to maintain schemas by hand.
A second alternative is using an MCP server written in another language and connecting to it from Python as a client. That keeps the protocol implementation out of your codebase entirely, at the cost of running and deploying a separate process.
Licence, maintenance and upgrade cost
The project is MIT licensed, stated in the README and in pyproject.toml as license = { text = "MIT" }. MIT is permissive: it allows commercial use, modification and redistribution provided the copyright notice and licence text are retained. This is not legal advice, and if you redistribute the SDK inside a product you should read the LICENSE file yourself.
The repository is not archived, and the last push was on 2026-09-10. The most recent release listed is v2.2.0 on 2026-09-07, with v1.30.0 released the same day and v2.0.1 on 2026-08-26. The parallel v1 and v2 release lines are the notable maintenance fact: the project is maintaining two branches, and the README commits to critical bug fixes and security patches on v1.x.
Upgrade cost is dominated by the v2 migration. The project publishes a dedicated migration guide covering "every breaking change," which tells you the surface area is large enough to need one. Budget for reading it before you bump the pin, not after. On the v2 line itself, the pyproject.toml pins build constraint dependencies (hatchling, uv-dynamic-versioning, dunamai and others) to narrow what a fresh sync fetches, and declares required-version = ">=0.9.5" for uv, so contributors using uv should check their version first.
Editorial conclusion
Adopt it if you are writing an MCP server or client in Python and can run Python 3.10 or newer; the type hints and docstrings you already write become the protocol schema. Do not adopt it if you are on Python 3.9 or older, or if you need a non-Python implementation of the protocol. Before you commit, check whether your existing code targets v1 or v2, read the migration guide if it is v1, and pin an upper bound on mcp in your requirements until you have ported.
Frequently asked questions
How do I install the MCP Python SDK?
Install the mcp package with the cli extra: uv add "mcp[cli]" or pip install "mcp[cli]". The cli extra adds the mcp command-line tool; install plain mcp if you do not need it. Python 3.10 or newer is required.
How do I create an MCP server with the MCP Python SDK?
Create an MCPServer instance and decorate type-hinted functions with @mcp.tool() for tools or @mcp.resource() for templated resources. The README's example is a single file with one tool and one resource, opened with uv run mcp dev server.py.
What is the difference between an SDK and an API in this context?
The README describes MCP as "like a web API, but designed for LLM interactions." The API here is the Model Context Protocol itself, and the SDK is the Python package that implements it, so you call Python functions instead of handling protocol messages directly.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/modelcontextprotocol-python-sdk)
Community notes