MCP Python SDK
raw JSON → 1.26.0 verified Tue May 12 auth: no python install: verified quickstart: stale
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.
pip install mcp Common errors
error ModuleNotFoundError: No module named 'mcp' ↓
cause The 'mcp' package is not installed in the active Python environment, or a local file or directory named 'mcp.py' is shadowing the installed package.
fix
Ensure the 'mcp' package is installed using
pip install mcp. If the issue persists, check for any local files or directories named 'mcp.py' in your project path and rename them. error ImportError: cannot import name 'mcp' from 'fastmcp' ↓
cause This error occurs when attempting to import the `mcp` object directly from the standalone `fastmcp` package. The `fastmcp` package exports `FastMCP` as its primary class, not `mcp`.
fix
Change the import statement to
from fastmcp import FastMCP and then instantiate the server with mcp = FastMCP("Server Name"). error AttributeError: module 'mcp.types' has no attribute 'ToolUseContent' ↓
cause This typically indicates a version incompatibility where the installed `mcp` package is older than required by the code, missing recently introduced types or attributes like `ToolUseContent`.
fix
Upgrade the
mcp package to a compatible version using pip install --upgrade mcp or pip install "mcp>=1.23.0" to ensure you have the necessary types. error MCP error -32000: Connection closed ↓
cause This is a generic error indicating that the MCP server, often running as a separate process, has malfunctioned, crashed, or unexpectedly terminated, causing the client to lose its connection.
fix
Troubleshoot the MCP server itself by checking its logs for specific errors. Ensure the server process is stable and configured correctly (e.g., verifying
command, args, cwd, and env in its configuration). Restarting the server or killing orphaned Python processes may also resolve the issue. 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). ↓
fix Replace mcp.run(transport='sse') with mcp.run(transport='streamable-http'). For production use stateless_http=True, json_response=True. SSE endpoint was at /sse; streamable-http endpoint is at /mcp.
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. ↓
fix Pin to mcp>=1.25,<2 for stable production use. Monitor GitHub releases for v2 GA.
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. ↓
fix Pick one and use it consistently. For simple local tools: mcp package + from mcp.server.fastmcp import FastMCP. For production/remote/auth: pip install fastmcp + from fastmcp import FastMCP.
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. ↓
fix Move transport config to run(): mcp.run(transport='streamable-http', host='0.0.0.0', port=8080)
gotcha mcp dev and mcp run CLI commands only work with FastMCP-based servers, not low-level Server class implementations. ↓
fix Use FastMCP for servers you want to run with the CLI. Low-level Server implementations must be run directly with Python.
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+). ↓
fix Use snake_case for all tool names. e.g. get_weather not get-weather.
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. ↓
fix Set cache_tools_list=True on client-side MCP server instances when tool definitions are stable.
breaking Running MCP servers on Python 3.13+ may encounter a `ValueError: I/O operation on closed file` during server startup. This occurs when Uvicorn's default `ColoredFormatter` attempts to access `sys.stdout.isatty()` in an environment where `sys.stdout` might be prematurely closed or not a TTY (e.g., certain container or CI/CD setups), likely exacerbated by Python 3.13's changes to standard stream lifecycle management. This error prevents the server from starting. ↓
fix Set the environment variable `NO_COLOR=1` before running the MCP server to disable colored logging, for example: `NO_COLOR=1 python your_script.py`. This tells Uvicorn not to attempt colored output, bypassing the `sys.stdout.isatty()` call that causes the error.
Install
pip install 'mcp[cli]' pip install fastmcp Install compatibility verified last tested: 2026-05-12
python os / libc variant status wheel install import disk
3.10 alpine (musl) cli - - 1.84s 68.6M
3.10 alpine (musl) fastmcp - - 1.84s 107.6M
3.10 alpine (musl) mcp - - 1.68s 55.7M
3.10 slim (glibc) cli - - 1.35s 68M
3.10 slim (glibc) fastmcp - - 1.39s 107M
3.10 slim (glibc) mcp - - 1.23s 55M
3.11 alpine (musl) cli - - 2.47s 74.7M
3.11 alpine (musl) fastmcp - - 2.48s 118.5M
3.11 alpine (musl) mcp - - 2.29s 60.5M
3.11 slim (glibc) cli - - 2.04s 74M
3.11 slim (glibc) fastmcp - - 2.10s 118M
3.11 slim (glibc) mcp - - 1.93s 60M
3.12 alpine (musl) cli - - 2.24s 65.6M
3.12 alpine (musl) fastmcp - - 2.23s 108.0M
3.12 alpine (musl) mcp - - 2.08s 51.7M
3.12 slim (glibc) cli - - 2.23s 65M
3.12 slim (glibc) fastmcp - - 2.38s 108M
3.12 slim (glibc) mcp - - 2.06s 51M
3.13 alpine (musl) cli - - 2.19s 65.3M
3.13 alpine (musl) fastmcp - - 2.15s 107.7M
3.13 alpine (musl) mcp - - 2.04s 51.4M
3.13 slim (glibc) cli - - 2.23s 65M
3.13 slim (glibc) fastmcp - - 2.22s 107M
3.13 slim (glibc) mcp - - 2.05s 51M
3.9 alpine (musl) cli - - - -
3.9 alpine (musl) fastmcp - - - -
3.9 alpine (musl) mcp - - - -
3.9 slim (glibc) cli - - - -
3.9 slim (glibc) fastmcp - - - -
3.9 slim (glibc) mcp - - - -
Imports
- FastMCP (bundled in mcp package) wrong
from mcp import FastMCPcorrectfrom 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) wrong
from mcp import Servercorrectfrom mcp.server import Server from mcp.server.stdio import stdio_server
Quickstart stale last tested: 2026-05-12
# 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())