# MCP Python SDK v2: Building MCP Servers and Clients in Python

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

**modelcontextprotocol/python-sdk** — The official Python SDK for Model Context Protocol servers and clients

- Repository: https://github.com/modelcontextprotocol/python-sdk
- Website: https://py.sdk.modelcontextprotocol.io/
- Stars: 24,322 · Forks: 3,933
- Language: Python
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/modelcontextprotocol-python-sdk

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

```bash
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:

```python
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:

```bash
uv run mcp dev server.py
```

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

```bash
uv run mcp run server.py --transport streamable-http
```

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

```python
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.

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

## FAQ

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

## Sources

- [License: MIT](https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE)
- [modelcontextprotocol/python-sdk on GitHub](https://github.com/modelcontextprotocol/python-sdk)
- [Project website](https://py.sdk.modelcontextprotocol.io/)
- [README](https://github.com/modelcontextprotocol/python-sdk/blob/main/README.md)
- [Releases](https://github.com/modelcontextprotocol/python-sdk/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/modelcontextprotocol-python-sdk
