# MCP Python SDK Deep Dive

## What Is It?

The **MCP Python SDK** is the official Python implementation for building Model Context Protocol servers and clients. With **20.9k+ stars**, it provides high-level decorators (FastMCP) and low-level APIs for extending AI assistants with custom tools, resources, and prompts.

**Repository:** [modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk)

---

## The Problem It Solves

Building AI integrations requires:
- Custom protocols for each AI platform
- Complex message handling and state management
- Manual schema generation for tools
- Separate implementations for different transports

MCP Python SDK provides:
- **Standardized protocol** for all MCP hosts
- **Decorator-based API** (FastMCP) for rapid development
- **Automatic schema generation** from Python type hints
- **Multiple transports** (STDIO, HTTP, SSE)

---

## Key Statistics

| Metric | Value |
|--------|-------|
| **Stars** | 20,900 |
| **Forks** | 3,000 |
| **Latest Version** | 1.25.0 |
| **License** | MIT |
| **Python** | 3.10+ |

---

## Two API Levels

### FastMCP (High-Level)

Decorator-based, handles protocol complexity:

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

if __name__ == "__main__":
    mcp.run()
```

### Server (Low-Level)

Direct protocol access for full control:

```python
from mcp.server import Server

server = Server("example-server")

@server.call_tool()
async def handle_tool(name: str, arguments: dict):
    # Direct protocol handling
    pass
```

---

## Installation

```bash
# Basic
pip install mcp

# With CLI tools (recommended)
pip install "mcp[cli]"

# Or with uv
uv add "mcp[cli]"
```

---

## The Three Primitives

### 1. Tools (Model-Controlled Actions)

Like POST endpoints - execute code and produce side effects:

```python
@mcp.tool()
def search_database(query: str, limit: int = 10) -> list[dict]:
    """Search the database with a query"""
    return [{"id": 1, "name": "Result"}]
```

### 2. Resources (Data Endpoints)

Like GET endpoints - load information into context:

```python
@mcp.resource("config://app-settings")
def get_config() -> str:
    """Application configuration"""
    return "API_URL: https://api.example.com"

@mcp.resource("user://{user_id}")
def get_user(user_id: str) -> dict:
    """Get user by ID"""
    return {"id": user_id, "name": f"User {user_id}"}
```

### 3. Prompts (Reusable Templates)

Guide LLM interactions:

```python
@mcp.prompt()
def code_review(language: str) -> str:
    """Generate code review prompt"""
    return f"Review this {language} code for best practices"
```

---

## Transport Options

### STDIO (Local Development)

```python
if __name__ == "__main__":
    mcp.run()  # Defaults to STDIO
```

Best for: Claude Desktop, local testing

### Streamable HTTP (Production)

```python
if __name__ == "__main__":
    mcp.run(transport="streamable-http")
```

Best for: Remote servers, scalability

### FastAPI Integration

```python
from fastapi import FastAPI
from mcp.server.fastmcp import FastMCP

app = FastAPI()
mcp = FastMCP("My Server")

@mcp.tool()
def add(a: int, b: int) -> int:
    return a + b

# Mount MCP
app.mount("/mcp", mcp.streamable_http_app())
```

---

## Type Safety & Schemas

Python type hints automatically generate JSON schemas:

```python
from pydantic import BaseModel

class UserInput(BaseModel):
    name: str
    age: int
    email: str

@mcp.tool()
def create_user(input: UserInput) -> dict:
    """Create a new user"""
    return {"id": 1, **input.dict()}
```

The SDK generates proper JSON schema from the Pydantic model.

---

## Context Injection

Access session capabilities within tools:

```python
from mcp.server.fastmcp import Context

@mcp.tool()
async def process_data(data: str, ctx: Context) -> str:
    """Tool with context access"""
    ctx.info("Processing started")  # Logging

    # Access resources
    config = await ctx.read_resource("config://settings")

    # Report progress
    await ctx.report_progress(50, 100)

    return f"Processed: {data}"
```

---

## Lifespan Management

Initialize and cleanup resources:

```python
from contextlib import asynccontextmanager
from dataclasses import dataclass

@dataclass
class AppContext:
    db: DatabaseConnection

@asynccontextmanager
async def app_lifespan(server: FastMCP):
    # Startup
    db = await DatabaseConnection.create()
    yield AppContext(db=db)
    # Shutdown
    await db.close()

mcp = FastMCP("My Server", lifespan=app_lifespan)

@mcp.tool()
async def query(sql: str, ctx: Context) -> list:
    """Query database"""
    app = ctx.request_context
    return await app.db.query(sql)
```

---

## Testing with MCP Inspector

The official debugging tool:

```bash
# Launch inspector
mcp dev server.py

# With dependencies
mcp dev server.py --with pandas --with numpy
```

Features:
- Connect via STDIO, HTTP, or TCP
- Send test requests
- View responses in real-time
- Inspect server logs

---

## Complete Example

```python
from mcp.server.fastmcp import FastMCP, Context
from pydantic import BaseModel

class SearchResult(BaseModel):
    rank: int
    title: str
    url: str

mcp = FastMCP("Search Server")

# Tool
@mcp.tool()
def search(query: str, limit: int = 10) -> list[SearchResult]:
    """Search for documents"""
    return [
        SearchResult(rank=1, title="Result 1", url="https://example.com/1"),
        SearchResult(rank=2, title="Result 2", url="https://example.com/2"),
    ]

# Resource
@mcp.resource("search://history")
def get_history() -> str:
    """Get recent search history"""
    return "query1\nquery2\nquery3"

# Prompt
@mcp.prompt()
def research(topic: str) -> str:
    """Generate research prompt"""
    return f"Research {topic} thoroughly and provide key findings"

if __name__ == "__main__":
    mcp.run(transport="streamable-http")
```

---

## Comparison: Python vs TypeScript SDK

| Aspect | Python | TypeScript |
|--------|--------|------------|
| **API Style** | Decorators | Helper classes |
| **Type System** | Runtime (Pydantic) | Compile-time + Zod |
| **Ecosystem** | AI/ML focused | Web dev focused |
| **Learning Curve** | Lower | Moderate |

### When to Choose Python

- ML/data science team
- NumPy/pandas usage
- Rapid prototyping
- System automation

### When to Choose TypeScript

- Web development team
- Strong typing requirements
- Node.js ecosystem

---

## Best Practices

### Naming

```python
# Clear, descriptive names
@mcp.tool()
def fetch_user_by_id(user_id: int) -> dict:
    """Fetch user profile by ID"""
    pass
```

### Error Handling

```python
@mcp.tool()
async def process(data: str, ctx: Context) -> dict:
    """Process with error handling"""
    if not data:
        raise ValueError("Data cannot be empty")

    try:
        result = await expensive_operation(data)
    except TimeoutError:
        ctx.error("Operation timed out")
        raise

    return {"result": result}
```

### Resource URIs

```python
# Hierarchical, consistent
@mcp.resource("docs://python/asyncio")
@mcp.resource("config://database/primary")
@mcp.resource("user://{id}/profile")
```

### Logging

```python
import logging
import sys

# Log to stderr (visible in inspector)
logging.basicConfig(
    level=logging.DEBUG,
    stream=sys.stderr
)
```

---

## Common Pitfalls

| Pitfall | Solution |
|---------|----------|
| Printing to stdout | Use `logging` or `ctx.info()` |
| Missing type hints | Add full annotations |
| Blocking operations | Use async, report progress |
| No error handling | Wrap in try/except |

---

## Claude Desktop Configuration

```json
{
  "mcpServers": {
    "my-server": {
      "command": "python",
      "args": ["server.py"],
      "cwd": "/path/to/server"
    }
  }
}
```

## Claude Code Configuration

```bash
claude mcp add my-server python server.py
```

---

## Resources

- **Repository:** https://github.com/modelcontextprotocol/python-sdk
- **PyPI:** https://pypi.org/project/mcp/
- **MCP Specification:** https://modelcontextprotocol.io
- **Inspector:** https://github.com/modelcontextprotocol/inspector
- **Official Servers:** https://github.com/modelcontextprotocol/servers

---

*The MCP Python SDK is the fastest way to build AI integrations in Python. With FastMCP's decorator-based API, you can create production-ready MCP servers in minutes.*
