Módulo 5: MCP Server en Python

Módulo 5: MCP Server en Python

Módulo 5: MCP Server en Python

Descripción de la cápsula

Acabas de construir un MCP server completo en TypeScript. Implementaste tools con Zod, resources con URIs, configuraste transports, y viste a Claude Code usar tu server como si fuera una herramienta nativa. Ahora la pregunta es: ¿puedo hacer lo mismo en Python?

La respuesta corta: sí, y en muchos casos es más elegante.

El Python SDK para MCP tiene un enfoque diferente al de TypeScript. Donde TypeScript usa clases y métodos, Python usa decoradores. Donde TypeScript valida con Zod, Python valida con Pydantic y type hints nativos. Donde TypeScript requiere configuración explícita de tipos, Python infiere mucho del sistema de tipos.

Este módulo no es "el módulo de TypeScript traducido a Python." Es un módulo que aprovecha lo que Python hace bien — decoradores expresivos, type hints claros, asyncio maduro — para construir MCP servers que se sienten nativos del lenguaje.


¿Dónde estamos?

Contexto en la guía

Phase 1: Fundamentos MCP (Módulos 1-3)
  ✅ Módulo 1: Qué es MCP y por qué importa
  ✅ Módulo 2: Arquitectura Host-Client-Server
  ✅ Módulo 3: Tres Primitivas (Resources, Tools, Prompts)

Phase 2: Construir MCP Servers (Módulos 4-6)
  ✅ Módulo 4: MCP Server en TypeScript
  → Módulo 5: MCP Server en Python (ESTÁS AQUÍ)
  ○ Módulo 6: MCP Apps y UI Interactivo

Phase 3: Producción (Módulos 7-8)
  ○ Módulo 7: Testing, Debugging e Integración
  ○ Módulo 8: Proyecto — MCP Server Real

Lo que ya sabes

De los módulos anteriores traes:

  • MCP fundamentals — el protocolo, la arquitectura Host-Client-Server, el flujo de requests
  • Tres primitivas — Resources (datos), Tools (acciones), Prompts (templates)
  • MCP server en TypeScript completo — tools con Zod, resources con URIs, transports stdio/HTTP
  • Experiencia práctica — conectaste tu server a Claude Code y lo usaste end-to-end

Lo que falta

Sabes construir en TypeScript, pero Python es probablemente tu lenguaje principal. Necesitas:

  • Entender el SDK de Python y su filosofía (decoradores, no clases)
  • Usar Pydantic en lugar de Zod para validación
  • Manejar patrones async en Python (asyncio, context managers)
  • Construir un MCP server Python que conecte con una API REST externa

¿Por qué Python para MCP?

La decisión no es "Python vs TypeScript"

No estás eligiendo un bando. Estás agregando una herramienta a tu arsenal. La decisión de qué lenguaje usar para un MCP server específico depende del contexto:

¿Cuándo elegir Python?
├── Tu stack existente es Python
├── Necesitas librerías de ML/data science (pandas, numpy, scikit-learn)
├── El server procesa datos con herramientas del ecosistema Python
├── Tu equipo es más fuerte en Python
├── Necesitas integrar con frameworks Python (Django, FastAPI, Flask)
└── El MCP server envuelve un servicio que ya tienes en Python

¿Cuándo elegir TypeScript?
├── Tu stack existente es Node.js/TypeScript
├── Quieres el SDK más maduro (TS fue el primero)
├── Hay más MCP servers de referencia en TypeScript
├── Necesitas el ecosistema npm
├── Tu equipo es más fuerte en TypeScript
└── Necesitas SSE/HTTP transport con la implementación más probada

Ventajas concretas del SDK Python

1. Decoradores como interfaz principal

En TypeScript, registras tools con llamadas a métodos:

server.tool("greet", "Saluda al usuario", {
  name: z.string(),
}, async ({ name }) => {
  return { content: [{ type: "text", text: `Hola, ${name}!` }] };
});

En Python, usas decoradores — más conciso y Pythonic:

@mcp.tool()
async def greet(name: str) -> str:
    """Saluda al usuario."""
    return f"Hola, {name}!"

Menos código, misma funcionalidad. El decorador extrae el nombre del tool de la función, la descripción del docstring, y los tipos del input del type hint.

2. Pydantic en lugar de Zod

TypeScript usa Zod para definir schemas de validación:

const UserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().int().positive().optional(),
});

Python usa Pydantic — que muchos developers ya conocen de FastAPI:

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str = Field(min_length=1)
    email: str = Field(pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$')
    age: int | None = Field(default=None, gt=0)

Si ya usaste FastAPI, Pydantic te es familiar. Los type hints de Python hacen el código más legible.

3. Type hints nativos

Python 3.10+ tiene un sistema de tipos expresivo que el SDK aprovecha:

@mcp.tool()
async def search_files(
    directory: str,
    pattern: str,
    max_results: int = 10,
    include_hidden: bool = False
) -> str:
    """Busca archivos en un directorio que coincidan con un patrón."""
    ...

El SDK infiere el schema JSON automáticamente de los type hints. No necesitas definir el schema por separado.

4. FastMCP: el helper que simplifica todo

El SDK de Python incluye FastMCP, un helper de alto nivel que reduce el boilerplate:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-server")

@mcp.tool()
async def my_tool(param: str) -> str:
    """Descripción del tool."""
    return f"Resultado: {param}"

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

Compara esto con el setup de TypeScript — FastMCP maneja el transport, la inicialización, y el loop de eventos por ti.


Comparación directa: TypeScript vs Python

Tabla comparativa

AspectoTypeScript SDKPython SDK
EstiloClases y métodosDecoradores
ValidaciónZod schemasPydantic + type hints
AsyncPromises/async-awaitasyncio/async-await
Setupnpm + tsconfig + buildpip + virtualenv
HelperMcpServer classFastMCP helper
Nombre del toolExplícito en .tool()Inferido del nombre de la función
DescripciónExplícita como stringInferida del docstring
SchemaDefinido con ZodInferido de type hints
MadurezSDK más maduroSDK maduro y estable
EcosistemaMás servers de referenciaCreciendo rápidamente

Ejemplo lado a lado: el mismo server

TypeScript:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "calculator",
  version: "1.0.0",
});

server.tool(
  "add",
  "Suma dos números",
  { a: z.number(), b: z.number() },
  async ({ a, b }) => ({
    content: [{ type: "text", text: String(a + b) }],
  })
);

server.tool(
  "multiply",
  "Multiplica dos números",
  { a: z.number(), b: z.number() },
  async ({ a, b }) => ({
    content: [{ type: "text", text: String(a * b) }],
  })
);

server.resource(
  "history",
  "calc://history",
  { description: "Historial de operaciones" },
  async (uri) => ({
    contents: [{ uri: uri.href, mimeType: "application/json", text: "[]" }],
  })
);

const transport = new StdioServerTransport();
await server.connect(transport);

Python (equivalente):

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("calculator")

@mcp.tool()
async def add(a: float, b: float) -> str:
    """Suma dos números."""
    return str(a + b)

@mcp.tool()
async def multiply(a: float, b: float) -> str:
    """Multiplica dos números."""
    return str(a * b)

@mcp.resource("calc://history")
async def get_history() -> str:
    """Historial de operaciones."""
    return "[]"

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

El server Python tiene la mitad de líneas para la misma funcionalidad. No es que TypeScript sea malo — es que Python es más conciso para este tipo de código declarativo.

Lo que NO cambia entre lenguajes

Independientemente del lenguaje que elijas:

  • El protocolo MCP es el mismo — JSON-RPC 2.0 sobre transports
  • Las primitivas son las mismas — Resources, Tools, Prompts
  • La configuración en Claude Code es la misma — claude mcp add
  • El flujo Host-Client-Server es el mismo — nada cambia a nivel de arquitectura
  • MCP Inspector funciona igual — debuggeas de la misma forma

Lo que cambia es la ergonomía del desarrollo. El SDK de Python es más conciso; el de TypeScript es más explícito. Ambos producen MCP servers que se comportan idénticamente desde la perspectiva del host.


Objetivo del módulo

Al completar este módulo, serás capaz de:

  • ✅ Crear un proyecto MCP en Python desde cero con pip install mcp[cli]
  • ✅ Usar FastMCP para configurar un server con mínimo boilerplate
  • ✅ Implementar tools usando el decorador @mcp.tool() con type hints
  • ✅ Implementar resources usando el decorador @mcp.resource() con URIs
  • ✅ Usar Pydantic para validación de inputs complejos
  • ✅ Manejar patrones async: funciones async, context managers, asyncio
  • ✅ Conectar tu MCP server Python a una API REST externa real
  • ✅ Decidir con criterio cuándo elegir Python vs TypeScript para un MCP server
  • ✅ Tener un MCP server Python funcional conectado a Claude Code

Roadmap del módulo

CápsulaTemaQué aprenderás
02Setup: MCP PythonInstalar el SDK, crear estructura de proyecto, entender decoradores y FastMCP
03Tools y Resources en PythonImplementar tools y resources con decoradores, Pydantic para validación, diferencias con TS
04Patrones Async en MCPasyncio, async context managers, async generators, error handling async
05Proyecto: MCP Server PythonServer completo que conecta con API REST externa, testing, conexión con Claude Code

Flujo de aprendizaje

La progresión es deliberada:

  1. Setup (cápsula 02) — ambiente de desarrollo, dependencias, y tu primer server Python corriendo. Sin fricciones.
  2. Tools y Resources (cápsula 03) — la carne del módulo. Implementas primitivas con el estilo Pythonic: decoradores, type hints, Pydantic.
  3. Async patterns (cápsula 04) — el SDK es async-first. Dominas asyncio en el contexto de MCP: conexiones a APIs, databases, archivos.
  4. Proyecto (cápsula 05) — todo converge en un MCP server Python que conecta con una API REST real. End-to-end.

Cada cápsula construye sobre la anterior. No puedes implementar tools sin el setup, y no puedes conectar APIs sin dominar async.


Qué asume este módulo

Sobre tu conocimiento de Python

Este módulo no enseña Python. Asume que:

  • Escribes funciones, clases, y módulos en Python con fluidez
  • Entiendes decoradores (al menos cómo usarlos, si no cómo crearlos)
  • Has usado type hints (str, int, list[str], dict[str, Any])
  • Has visto async/await (no necesitas ser experto — lo profundizamos en cápsula 04)
  • Has usado pip y virtual environments

Sobre tu conocimiento de MCP

Asume que completaste los módulos 1-4:

  • Entiendes el protocolo MCP, la arquitectura, y las tres primitivas
  • Construiste un MCP server en TypeScript (módulo 4)
  • Sabes configurar MCP servers en Claude Code
  • Has usado MCP Inspector para debugging

Si saltaste directamente al módulo 5 sin hacer el 4, el módulo funciona — pero perderás las comparaciones con TypeScript que enriquecen la comprensión.


Conexión con el proyecto integrador

Mini-proyecto de este módulo (cápsula 05)

Vas a construir un MCP server Python que:

  • Conecta con una API REST externa (GitHub API o weather API)
  • Expone resources para consultar datos de la API
  • Expone tools para ejecutar acciones a través de la API
  • Expone prompts para estandarizar consultas comunes
  • Incluye error handling robusto para fallas de red y API
  • Se conecta a Claude Code y funciona end-to-end

Conexión con el módulo 8

El proyecto integrador del módulo 8 te pide un MCP server production-ready. Si eliges Python (una opción totalmente válida), este módulo te da todas las herramientas. Los patrones que aprendes aquí — decoradores, Pydantic, async patterns — se aplican directamente al proyecto final.

Lo que agregas en el módulo 8 que no cubres aquí:

  • Testing automatizado (módulo 7)
  • Error handling avanzado y retry logic
  • Documentación profesional
  • Configuración para producción

Prerequisitos técnicos

Para este módulo necesitas:

  • ✅ Python 3.10+ instalado (python --version para verificar)
  • ✅ pip actualizado (pip install --upgrade pip)
  • ✅ Claude Code instalado y funcionando
  • ✅ Un editor con soporte Python (VS Code, Cursor, PyCharm)
  • ✅ Conexión a internet (para instalar dependencias y conectar APIs)

Verificación rápida:

python --version    # Python 3.10+
pip --version       # pip 23+
claude --version    # Claude Code instalado

Si alguno falla, resuélvelo antes de continuar. La cápsula 02 cubre la instalación del SDK, pero Python y pip deben estar listos.


Límites: qué NO se cubre en este módulo

  • ❌ Transports avanzados (HTTP/SSE) — Cubierto en el módulo 4 con TypeScript; en Python se configura de forma similar
  • ❌ Testing automatizado — Eso viene en el módulo 7
  • ❌ MCP Apps y UI — Eso viene en el módulo 6
  • ❌ Deployment a producción — Fuera del scope de la guía
  • ❌ Python avanzado (metaclasses, descriptors) — No es necesario para MCP
  • ❌ Comparación exhaustiva de SDKs — Cubrimos las diferencias clave, no cada detalle

Este módulo es construcción práctica en Python. Entras sabiendo MCP en TypeScript, sales sabiendo MCP en Python.


Evidencia de éxito

Al terminar este módulo, sabrás que tuviste éxito si:

  • ✅ Puedes crear un MCP server Python desde cero con FastMCP
  • ✅ Implementas tools con @mcp.tool() y type hints para validación
  • ✅ Implementas resources con @mcp.resource() y URIs
  • ✅ Manejas patrones async sin errores (conexiones, APIs, archivos)
  • ✅ Tienes un MCP server Python conectado a una API REST real
  • ✅ Claude Code usa tu server Python y funciona end-to-end
  • ✅ Puedes articular cuándo elegir Python vs TypeScript para un MCP server
  • ✅ Te sientes preparado para el proyecto integrador del módulo 8

Mentalidad para este módulo

"Usa lo que ya sabes"

No estás aprendiendo MCP de nuevo — ya lo aprendiste en los módulos 1-4. Estás aprendiendo a expresar lo que ya sabes en Python. El protocolo es el mismo. Las primitivas son las mismas. Lo que cambia es la sintaxis y las herramientas.

"Python-nativo, no TypeScript traducido"

Vas a ver la tentación de escribir Python que se parece a TypeScript. Resiste. Python tiene su propio estilo:

# ❌ TypeScript traducido a Python
server.tool("greet", "Saluda al usuario", {"name": str}, lambda args: f"Hola, {args['name']}")

# ✅ Python nativo con decoradores
@mcp.tool()
async def greet(name: str) -> str:
    """Saluda al usuario."""
    return f"Hola, {name}!"

El SDK de Python está diseñado para que escribas Python idiomático. Aprovéchalo.

"Async no es opcional"

El SDK de Python es async-first. Si evitas async/await, pelearás con el SDK en lugar de aprovecharlo. La cápsula 04 está dedicada a patrones async — si async te intimida, esa cápsula te va a dar la confianza que necesitas.


Resumen

  • Este módulo te enseña a construir MCP servers en Python, usando el SDK oficial
  • Python usa decoradores (@mcp.tool(), @mcp.resource()) en lugar de clases
  • Pydantic reemplaza a Zod para validación de schemas
  • FastMCP es el helper que reduce boilerplate
  • El módulo es práctico: setup → tools/resources → async → proyecto
  • Al terminar tendrás un MCP server Python conectado a una API REST real
  • El protocolo MCP es el mismo — lo que cambia es la ergonomía del desarrollo

Recursos adicionales

  1. MCP Python SDK — Repositorio oficial del SDK
  2. MCP Python SDK — FastMCP — Documentación del helper FastMCP
  3. Pydantic Documentation — Validación y serialización en Python
  4. Python asyncio Documentation — Referencia oficial de asyncio
  5. MCP Specification — Especificación del protocolo (independiente del lenguaje)
  6. MCP TypeScript SDK — Para comparar con la implementación TypeScript

Siguiente cápsula: Setup — instalación del SDK, estructura de proyecto, y tu primer MCP server Python corriendo en menos de 5 minutos.