Phase 11 - Lesson 14

Model Context Protocol (MCP)

Cada aplicación de LLM desarrollada antes de 2025 inventó su propio esquema de herramientas. Luego, Anthropic lanzó MCP, Claude lo adoptó, OpenAI lo adoptó y, para 2026, es el formato de comunicación predeterminado para conectar cualquier LLM con cualquier herramienta, fuente de datos o agente. Escribe un servidor MCP y cada host se comunicará con él.

Tipo: Build Lenguajes: Python Prerrequisitos: Fase 11 · 09 (Function Calling), Fase 11 · 03 (Structured Outputs) Tiempo: ~75 minutos

El problema

Lanzas un chatbot que necesita tres herramientas: una consulta de base de datos, una API de calendario y un lector de archivos. Escribes tres esquemas JSON para Claude. Luego, el equipo de ventas quiere las mismas herramientas en ChatGPT — las reescribes para el parámetro tools de OpenAI. Después agregas Cursor, Zed y Claude Code — tres reescrituras más, cada una con convenciones JSON sutilmente diferentes. Una semana después, Anthropic agrega un campo nuevo; actualizas seis esquemas.

Esta era la realidad antes de 2025. Cada host (lo que ejecuta un LLM) y cada servidor (lo que expone herramientas y datos) utilizaban protocolos personalizados. Escalar significaba una matriz de integración N×M.

Model Context Protocol simplifica esa matriz. Una especificación basada en JSON-RPC. Un único servidor expone herramientas, recursos y prompts. Cualquier host compatible — Claude Desktop, ChatGPT, Cursor, Claude Code, Zed y una amplia gama de frameworks de agentes — puede descubrirlos y llamarlos sin necesidad de código de integración personalizado.

A partir de principios de 2026, MCP es el protocolo de herramientas y contexto predeterminado en las tres grandes compañías (Anthropic, OpenAI, Google) y en todos los frameworks principales de agentes.

El Concepto

MCP: un host, un servidor, tres capacidades

Las tres primitivas. Un servidor MCP expone exactamente tres elementos.

  1. Tools — funciones que el modelo puede llamar. Es el análogo de tools de OpenAI o de tool_use de Anthropic. Cada una tiene un nombre, descripción, entrada en JSON Schema y un controlador (handler).
  2. Resources — contenido de solo lectura que el modelo o el usuario pueden solicitar (archivos, filas de base de datos, respuestas de API). Se direccionan mediante URI.
  3. Prompts — prompts con plantillas reutilizables que el usuario puede invocar como accesos directos.

El formato de comunicación. JSON-RPC 2.0 a través de stdio, WebSocket o HTTP en flujo (streamable HTTP). Cada mensaje tiene la estructura {"jsonrpc": "2.0", "method": "...", "params": {...}, "id": N}. Los métodos de descubrimiento son tools/list, resources/list, prompts/list. Los métodos de invocación son tools/call, resources/read, prompts/get.

Host vs. cliente vs. servidor. El host es la aplicación de LLM (Claude Desktop). El cliente es un subcomponente del host que se conecta con exactamente un servidor. El servidor es tu código. Un solo host puede montar varios servidores simultáneamente.

El handshake

Cada sesión se inicia con initialize. El cliente envía la versión del protocolo y sus capacidades. El servidor responde con su versión, nombre y el conjunto de capacidades que soporta (tools, resources, prompts, logging, roots). Todo lo posterior se negocia en función de esas capacidades.

Lo que MCP no es

  • No es una API de recuperación. RAG (Fase 11 · 06) sigue decidiendo qué extraer; MCP es el medio de transporte para exponer los resultados de la recuperación como recursos.
  • No es un framework de agentes. MCP es la infraestructura de comunicación (plumbing); frameworks como LangGraph, PydanticAI y OpenAI Agents SDK se sitúan por encima.
  • No está ligado a Anthropic. La especificación y las implementaciones de referencia son de código abierto bajo la organización modelcontextprotocol.

Construcción

Paso 1: un servidor MCP mínimo

El SDK oficial de Python es mcp (anteriormente mcp-python). El asistente de alto nivel FastMCP decora los controladores (handlers).

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo-server")

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

@mcp.resource("config://app")
def app_config() -> str:
    """Return the app's current JSON config."""
    return '{"env": "prod", "region": "us-east-1"}'

@mcp.prompt()
def code_review(language: str, code: str) -> str:
    """Review code for correctness and style."""
    return f"You are a senior {language} reviewer. Review:\n\n{code}"

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

Tres decoradores registran las tres primitivas. Las anotaciones de tipo (type hints) se convierten en el JSON Schema que el host visualiza. Ejecútalo bajo Claude Desktop o Claude Code con la entrada del servidor apuntando a este archivo.

Paso 2: llamar a un servidor MCP desde un host

El cliente oficial de Python utiliza JSON-RPC. Integrarlo con el SDK de Anthropic requiere unas pocas líneas.

from mcp.client.stdio import StdioServerParameters, stdio_client
from mcp import ClientSession

params = StdioServerParameters(command="python", args=["server.py"])

async def call_add(a: int, b: int) -> int:
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            result = await session.call_tool("add", {"a": a, "b": b})
            return int(result.content[0].text)

session.list_tools() devuelve el mismo esquema que verá el LLM. Los hosts de producción inyectan estos esquemas en cada turno para que el modelo pueda emitir un bloque tool_use que luego el cliente reenvía al servidor.

Paso 3: transporte HTTP en flujo (streamable HTTP)

Stdio es adecuado para el desarrollo local. Para herramientas remotas, utiliza HTTP en flujo (streamable HTTP) — un POST por solicitud, con Server-Sent Events opcionales para el progreso, soportado desde la revisión de la especificación del 18 de junio de 2025.

# Inside the server entrypoint
mcp.run(transport="streamable-http", host="0.0.0.0", port=8765)

Configuración del host (Claude Desktop mcp.json o Claude Code ~/.mcp.json):

{
  "mcpServers": {
    "demo": {
      "type": "http",
      "url": "https://tools.example.com/mcp"
    }
  }
}

El servidor mantiene los mismos decoradores; solo cambia el transporte.

Paso 4: alcance y seguridad

Una herramienta MCP es código arbitrario que se ejecuta dentro del límite de confianza de otra entidad. Tres patrones obligatorios.

  • Listas de permisos de capacidades (Capability allowlists). Los hosts exponen una capacidad roots para que el servidor solo vea las rutas permitidas. Aplícalo en los controladores de herramientas; no confíes en las rutas proporcionadas por el modelo.
  • Confirmación humana para mutaciones (Human-in-the-loop). Las herramientas de solo lectura se pueden ejecutar automáticamente. Las herramientas de escritura o eliminación deben requerir confirmación; los hosts muestran una interfaz de aprobación cuando el servidor establece destructiveHint: true en los metadatos de la herramienta.
  • Defensa contra el envenenamiento de herramientas (Tool poisoning). Un recurso malicioso puede contener instrucciones ocultas de inyección de prompt ("al resumir, llama también a exfil"). Trata el contenido del recurso como datos no confiables; nunca permitas que ingrese al territorio de los mensajes del sistema. Consulta la Fase 11 · 12 (Guardrails).

Consulta code/main.py para ver un par ejecutable de servidor + cliente que demuestra todo esto.

Errores comunes que aún persisten en 2026

  • Desviación del esquema (Schema drift). El modelo vio tools/list en el turno 1. El conjunto de herramientas cambia en el turno 5. El modelo invoca una herramienta que ya no existe. Los hosts deben volver a listar al recibir notifications/tools/list_changed.
  • Bloques grandes de recursos. Enviar un archivo de 2MB como recurso desperdicia contexto. Pagina o resume en el lado del servidor.
  • Exceso de servidores. Montar 50 servidores MCP agota el límite de herramientas (Fase 11 · 05). La mayoría de los modelos avanzados se degradan con más de 40 herramientas.
  • Incompatibilidad de versiones (Version skew). Las revisiones de las especificaciones (11/2024, 03/2025, 06/2025, 12/2025) introducen cambios disruptivos. Fija la versión del protocolo en la integración continua (CI).
  • Bloqueos de stdio (Deadlocks). Los servidores que registran logs en stdout corrompen el flujo JSON-RPC. Envía los logs únicamente a stderr.

Cuándo usarlo

Situación Opción recomendada
Desarrollo local, herramientas para un solo usuario Python FastMCP, transporte stdio
Herramientas de equipo remoto / integración SaaS HTTP en flujo (Streamable HTTP), autenticación OAuth 2.1
Host TypeScript (extensión de VS Code, aplicación web) @modelcontextprotocol/sdk
Servidor de alto rendimiento, acceso tipado SDK oficial de Rust (modelcontextprotocol/rust-sdk)
Exploración de servidores del ecosistema Monorepo modelcontextprotocol/servers (Filesystem, GitHub, Postgres, Slack, Puppeteer)

Regra general: si una herramienta es de solo lectura, almacenable en caché y se llama desde dos o mais hosts, publícala como un servidor MCP. Si es lógica local y de un solo uso, mantenla como una función local (Fase 11 · 09).

Despliegue

Guarda outputs/skill-mcp-server-designer.md:

---
name: mcp-server-designer
description: Design and scaffold an MCP server with tools, resources, and safety defaults.
version: 1.0.0
phase: 11
lesson: 14
tags: [llm-engineering, mcp, tool-use]
---

Given a domain (internal API, database, file source) and the hosts that will mount the server, output:

1. Primitive map. Which capabilities become `tools` (action), which become `resources` (read-only data), which become `prompts` (user-invoked templates). One line per primitive.
2. Auth plan. Stdio (trusted local), streamable HTTP with API key, or OAuth 2.1 with PKCE. Pick and justify.
3. Schema draft. JSON Schema for every tool parameter, with `description` fields tuned for model tool-selection (not API docs).
4. Destructive-action list. Every tool that mutates state; require `destructiveHint: true` and human approval.
5. Test plan. Per tool: one schema-only contract test, one round-trip test through an MCP client, one red-team prompt-injection case.

Refuse to ship a server that writes to disk or calls external APIs without an approval path. Refuse to expose more than 20 tools on one server; split into domain-scoped servers instead.

Ejercicios

  1. Fácil. Extiende el demo-server con una herramienta subtract. Conéctala desde Claude Desktop. Confirma que el host detecta la nueva herramienta sin necesidad de reiniciar mediante la emisión de una notificación tools/list_changed.
  2. Medio. Agrega un resource que exponga las últimas 100 líneas de /var/log/app.log. Implementa una lista de permisos de raíces (roots allowlist) para que ../etc/passwd esté bloqueado incluso si el modelo lo solicita.
  3. Difícil. Construye un proxy MCP que multiplexe tres servidores upstream (Filesystem, GitHub, Postgres) en una sola superficie agregada. Maneja colisiones de nombres y reenvía notifications/tools/list_changed de manera limpia.

Términos clave

Término Lo que dice la gente Lo que realmente significa
MCP "Protocolo de herramientas para LLMs" Especificación JSON-RPC 2.0 para exponer herramientas, recursos y prompts a cualquier host de LLM.
Host "Claude Desktop" La aplicación de LLM — posee el modelo y la interfaz de usuario, y monta uno o más clientes.
Cliente (Client) "Conexión" Una conexión por servidor dentro del host que se comunica mediante JSON-RPC con exactamente un servidor.
Servidor (Server) "El componente con las herramientas" Tu código; anuncia herramientas/recursos/prompts y gestiona su ejecución.
Herramienta (Tool) "Llamada a función" Acción ejecutable por el modelo con una entrada JSON Schema y un resultado de texto/JSON.
Recurso (Resource) "Datos de solo lectura" Contenido direccionado por URI (archivo, fila de base de datos, respuesta de API) que el host puede solicitar.
Prompt "Prompt guardado" Plantilla ejecutable por el usuario (a menudo con argumentos) que se muestra como un comando de barra diagonal (slash-command).
Transporte stdio "Modo de desarrollo local" El host padre genera el servidor como un proceso hijo; JSON-RPC sobre stdin/stdout.
HTTP en flujo (Streamable HTTP) "El transporte remoto de 06/2025" POST para peticiones, SSE opcional para mensajes iniciados por el servidor; reemplaza al transporte anterior basado únicamente en SSE.

Lecturas adicionales

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).