MCP Python SDK
Official Python SDK for the Model Context Protocol (MCP), maintained by Anthropic. Used to build MCP servers (exposing tools, resources, prompts to LLMs) and MCP clients. Two important ecosystem distinctions: (1) mcp package bundles FastMCP 1.0 via mcp.server.fastmcp; (2) standalone 'fastmcp' package on PyPI is a separate, more feature-rich framework that diverged from the bundled version. v2 of the mcp package is in pre-alpha on main branch — v1.x is stable.
Warnings
- breaking SSE transport (Server-Sent Events) is deprecated as of MCP spec 2025-03-26. Servers built with transport='sse' still work but emit deprecation warnings. The replacement is streamable-http (single /mcp endpoint).
- breaking mcp v2 is in pre-alpha development on the main branch with significant transport layer changes. Users on v1.x should pin: mcp>=1.25,<2. Unpinned installs that pull from main will get pre-alpha code.
- breaking mcp.server.fastmcp.FastMCP (bundled, v1.0) and fastmcp.FastMCP (standalone package, v2.x+) are two different classes with diverging behaviour. They are not interchangeable. The standalone fastmcp package has additional features (auth, middleware, proxy, composition) not in the bundled version.
- breaking Passing host= and port= to FastMCP() constructor is deprecated. These arguments now belong on run(). Passing them to the constructor raises TypeError with a migration hint.
- gotcha mcp dev and mcp run CLI commands only work with FastMCP-based servers, not low-level Server class implementations.
- gotcha Tool names must be valid identifiers: alphanumeric and underscores only. Names with hyphens, spaces, or special characters fail spec validation (SEP-986, enforced from mcp ~1.20+).
- gotcha MCP clients call list_tools() on every agent run by default. For remote servers this adds latency. Both the official SDK and standalone fastmcp support cache_tools_list=True on the client to skip redundant list calls.
Install
-
pip install mcp -
pip install 'mcp[cli]' -
pip install fastmcp
Imports
- FastMCP (bundled in mcp package)
from mcp.server.fastmcp import FastMCP mcp = FastMCP('My Server') @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b mcp.run(transport='stdio') - Low-level Server (legacy pattern)
from mcp.server import Server from mcp.server.stdio import stdio_server
Quickstart
# Server (stdio transport — for Claude Desktop, local agents)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('My Server')
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
@mcp.resource('data://{name}')
def get_data(name: str) -> str:
"""Fetch named data"""
return f'Data for {name}'
@mcp.prompt()
def review_code(code: str) -> str:
return f'Please review this code:\n\n{code}'
if __name__ == '__main__':
mcp.run() # defaults to stdio
# ---
# Server (streamable-http — for remote/production deployments)
mcp = FastMCP('My Server', stateless_http=True, json_response=True)
if __name__ == '__main__':
mcp.run(transport='streamable-http') # serves at /mcp by default
# ---
# Client (connecting to an MCP server)
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
import asyncio
async def main():
async with streamablehttp_client('http://localhost:8000/mcp') as (r, w, _):
async with ClientSession(r, w) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool('add', {'a': 1, 'b': 2})
print(result)
asyncio.run(main())