Antes de MCP, cada herramienta de IA tenía su propio sistema de plugins. Claude Code tenía uno. Cursor tenía otro. Tu herramienta de base de datos funcionaba en Claude Code pero no en Cursor, así que la escribías dos veces. Cambiar de herramienta significaba reescribir todas tus integraciones. Este era el estado de las herramientas de IA en 2024 —cada herramienta una isla, cada integración a medida.
MCP —el Model Context Protocol— cambió esto en 2025, y en 2026 está por todas partes. Claude Code lo usa. Cursor lo soporta. LangChain, LiteLLM y todas las plataformas de IA importantes han añadido soporte de MCP. La especificación oficial de MCP define el protocolo —es un estándar abierto (basado en JSON-RPC) que estandariza cómo los modelos de IA descubren y llaman herramientas. Escribe un servidor MCP. Úsalo con cualquier cliente compatible con MCP.
Qué es MCP —y por qué importa
El protocolo, no el marketing. MCP es un protocolo basado en JSON-RPC 2.0. Un servidor MCP expone tools, resources y prompts. Un cliente MCP (integrado en una aplicación de IA) se conecta al servidor, descubre qué hay disponible y llama herramientas en nombre del LLM. La capa de transporte es enchufable —stdio para herramientas locales, HTTP con SSE para servicios remotos.
MCP vs. function calling —complementarios, no competidores. Function calling: el LLM llama una herramienta dentro de un solo request de API. La definición de la herramienta se envía en la llamada de API. MCP: el LLM descubre las herramientas disponibles a través de un protocolo estandarizado y luego las llama —potencialmente a través de múltiples sesiones y herramientas. MCP estandariza el descubrimiento y la descripción de herramientas. El function calling las ejecuta. Puedes usar MCP para gestionar tu catálogo de herramientas y el function calling para invocarlas —trabajan juntos. Para una comparación detallada de las implementaciones de function calling en OpenAI, Anthropic, Google y DeepSeek, consulta nuestra guía de function calling y uso de herramientas.
Por qué MCP importa para los desarrolladores de API. Antes de MCP: escribías una herramienta de consulta de base de datos. Para usarla con Claude Code, escribías un plugin específico de Claude Code. Para usarla con Cursor, escribías una integración específica de Cursor. Para usarla con tu app personalizada, escribías código personalizado. Después de MCP: escribe un servidor MCP. Cualquier cliente compatible con MCP puede usarlo. Esta es la analogía del “USB-C para herramientas de IA” —no es perfecta, pero es el estándar que ganó.
Arquitectura de MCP: servidores, clientes y transportes
Servidor MCP. Expone tools, resources y prompts. Escrito en Python, Node.js o Go —lo que prefieras. Corre localmente (transporte stdio) o remotamente (transporte HTTP+SSE). Un servidor es un programa. Arranca. Escucha conexiones. Responde a los requests de llamada de herramientas. Se detiene cuando el cliente se desconecta.
Cliente MCP. Se conecta a los servidores MCP, descubre las herramientas disponibles, envía los requests de llamada de herramientas del LLM y devuelve los resultados. Integrado en las aplicaciones de IA —Claude Code, Cursor, tu app personalizada. El cliente es el puente entre la decisión del LLM (“necesito consultar la base de datos”) y la ejecución de la herramienta (SELECT * FROM users).
Transportes. stdio: el servidor corre como subproceso del cliente. Entrada/salida estándar para la comunicación. Ideal para herramientas de desarrollo locales —cero configuración de red, cero latencia. El transporte stdio añade menos de 1 ms de overhead por round-trip de mensaje en una máquina moderna. HTTP+SSE: el servidor corre como servicio remoto. HTTP POST para los requests, Server-Sent Events para las respuestas en streaming. Ideal para servicios de producción —pueden conectarse múltiples clientes, el servidor se puede actualizar de forma independiente sin reiniciar el IDE de cada desarrollador.
Diagrama de arquitectura:
LLM → MCP Client → Transport (stdio/HTTP) → MCP Server → External Resources (DB, API, Filesystem)
Construyendo tu primer servidor MCP
Un servidor MCP de clima y precio de acciones. 15 minutos. Dos tools.
# mcp_server.py
import json
import sys
from typing import Any
class MCPServer:
def __init__(self):
self.tools = {
"get_weather": {
"description": "Get current weather for a city. Returns temperature in Celsius.",
"inputSchema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name, e.g. 'Tokyo'"}
},
"required": ["city"]
}
},
"get_stock_price": {
"description": "Get current stock price for a ticker symbol.",
"inputSchema": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Stock ticker, e.g. AAPL"}
},
"required": ["symbol"]
}
}
}
def handle_request(self, request: dict) -> dict:
method = request.get("method")
if method == "tools/list":
return {"tools": list(self.tools.values())}
elif method == "tools/call":
tool_name = request["params"]["name"]
tool_args = request["params"]["arguments"]
result = self._execute_tool(tool_name, tool_args)
return {"content": [{"type": "text", "text": str(result)}]}
else:
return {"error": f"Unknown method: {method}"}
def _execute_tool(self, name: str, args: dict) -> Any:
if name == "get_weather":
return f"Weather in {args['city']}: 22°C, partly cloudy"
elif name == "get_stock_price":
return f"{args['symbol']}: $185.50"
else:
return f"Unknown tool: {name}"
# stdio transport —reads JSON-RPC from stdin, writes to stdout
if __name__ == "__main__":
server = MCPServer()
for line in sys.stdin:
request = json.loads(line)
response = server.handle_request(request)
sys.stdout.write(json.dumps(response) + "\n")
sys.stdout.flush()
Conéctate a Claude Desktop. El quickstart de MCP de Anthropic te guía por la configuración completa. Añade esto a tu claude_desktop_config.json:
{
"mcpServers": {
"my-tools": {
"command": "python",
"args": ["mcp_server.py"]
}
}
}
Reinicia Claude Desktop. Tus dos tools —get_weather y get_stock_price— ya están disponibles. Claude las descubre automáticamente. Prueba: “¿Qué tiempo hace en Tokio y cuál es el precio de las acciones de Apple?” Claude llamará ambas tools, en paralelo, y sintetizará una respuesta.
Para un recorrido completo de la API de Claude —autenticación, streaming, uso de herramientas y manejo de errores— consulta nuestra guía de desarrollador de la API de Claude.
Construyendo un servidor MCP real: herramienta de consulta de base de datos
El servidor de clima demuestra que MCP funciona en 50 líneas de Python. Las herramientas de producción necesitan más: queries parametrizadas, connection pooling y mensajes de error de los que el LLM pueda auto-corregirse. Aquí tienes un servidor MCP completo que consulta una base de datos SQLite, construido con el SDK oficial de MCP para Python (pip install mcp). Tres tools —query_users, get_user_by_id, create_user. Cópialo, adáptalo, despliégalo.
# db_mcp_server.py —production-grade MCP database server
import sqlite3
import asyncio
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationCapabilities
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
server = Server("database-tools")
# Database connection —created once, reused across all tool calls
_connection: sqlite3.Connection | None = None
def get_db():
global _connection
if _connection is None:
_connection = sqlite3.connect("app.db")
_connection.row_factory = sqlite3.Row
# WAL mode: concurrent reads without locking. Without this,
# two simultaneous query_users calls serialize —the second
# blocks until the first releases the read lock.
_connection.execute("PRAGMA journal_mode=WAL")
return _connection
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="query_users",
description="Run a SELECT query against the users table. "
"Use for searching, filtering, or counting users. "
"Returns results as JSON array. "
"Column names: id, name, email, role, status, created_at.",
inputSchema={
"type": "object",
"properties": {
"where_clause": {
"type": "string",
"description": "SQL WHERE clause without 'WHERE' keyword. "
"Example: \"age > 25 AND status = 'active'\". "
"Leave empty for all users."
},
"limit": {
"type": "integer",
"description": "Max rows to return. Default 50.",
"default": 50
}
}
}
),
Tool(
name="get_user_by_id",
description="Fetch a single user by primary key. Returns user object or null.",
inputSchema={
"type": "object",
"properties": {
"user_id": {
"type": "integer",
"description": "The user's ID in the database."
}
},
"required": ["user_id"]
}
),
Tool(
name="create_user",
description="Insert a new user into the database. "
"Returns the created user with their assigned ID.",
inputSchema={
"type": "object",
"properties": {
"name": {"type": "string", "description": "User's full name."},
"email": {"type": "string", "description": "Valid email address."},
"role": {
"type": "string",
"enum": ["admin", "editor", "viewer"],
"description": "User role. Default: viewer."
}
},
"required": ["name", "email"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
db = get_db()
if name == "query_users":
where = arguments.get("where_clause", "")
limit = arguments.get("limit", 50)
query = "SELECT * FROM users"
params = []
if where.strip():
query += " WHERE " + where
query += " LIMIT ?"
params.append(limit)
try:
rows = db.execute(query, params).fetchall()
except sqlite3.OperationalError as e:
# Return column names so the LLM can self-correct bad WHERE clauses
return [TextContent(
type="text",
text=f"Query failed: {e}. Valid columns: id, name, email, role, status, created_at."
)]
return [TextContent(
type="text",
text=str([dict(r) for r in rows])
)]
elif name == "get_user_by_id":
user_id = arguments["user_id"]
row = db.execute(
"SELECT * FROM users WHERE id = ?", [user_id]
).fetchone()
if row is None:
return [TextContent(type="text", text=f"No user found with id={user_id}")]
return [TextContent(type="text", text=str(dict(row)))]
elif name == "create_user":
name_val = arguments["name"]
email = arguments["email"]
role = arguments.get("role", "viewer")
try:
cursor = db.execute(
"INSERT INTO users (name, email, role) VALUES (?, ?, ?)",
[name_val, email, role]
)
db.commit()
new_id = cursor.lastrowid
except sqlite3.IntegrityError as e:
return [TextContent(
type="text",
text=f"Insert failed: {e}. Email may already exist."
)]
new_user = db.execute(
"SELECT * FROM users WHERE id = ?", [new_id]
).fetchone()
return [TextContent(type="text", text=str(dict(new_user)))]
return [TextContent(type="text", text=f"Unknown tool: {name}")]
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationCapabilities(
sampling={},
experimental={},
roots={}
),
notification_options=NotificationOptions()
)
if __name__ == "__main__":
asyncio.run(main())
Cuatro decisiones en este código que evitan alertas de guardia a las 3 AM.
Descripciones de tools con ejemplos. El LLM lee la descripción de tu tool para decidir cuál llamar. Un "description": "Query the database" desnudo no le da al modelo ninguna forma de distinguir entre tools —para una query SELECT COUNT(*) frecuentemente intentará get_user_by_id en su lugar. Sin instrucciones explícitas, los modelos frecuentemente eligen la tool equivocada cuando varias tools tienen descripciones similares. La descripción de arriba incluye qué hace la tool, qué devuelve y los nombres exactos de las columnas. Esa especificidad elimina la ambigüedad.
Queries parametrizadas —sin f-strings. db.execute("SELECT * FROM users WHERE id = ?", [user_id]) nunca se convierte en db.execute(f"SELECT * FROM users WHERE id = {user_id}"). Un f-string en un servidor MCP de base de datos, y un LLM que genera user_id = "1 OR 1=1" filtra cada fila de tu tabla users. Un LLM generará esa entrada. Ha pasado en producción. Las queries parametrizadas son un requisito estricto, no un lujo.
Mensajes de error con pistas de recuperación. Cuando query_users falla porque el LLM adivinó un nombre de columna que no existe, el error incluye la lista de columnas válidas: "Valid columns: id, name, email, role, status, created_at." El LLM lee esto, corrige su query y reintenta la llamada de tool —cero intervención humana. Un "OperationalError: no such column" desnudo produce un encogimiento de hombros en Claude y un usuario bloqueado.
Reutilización de conexiones con WAL journal mode. PRAGMA journal_mode=WAL habilita lecturas concurrentes sin bloqueos. Sin esto, dos llamadas query_users simultáneas se serializan —la segunda espera 50ms a que la primera libere el read lock. En una cadena de tools donde Claude llama query_users, lee los resultados y luego llama get_user_by_id para cada fila, esa espera por el lock se acumula a través de 5 llamadas secuenciales en 250ms de latencia visible para el usuario. El modo WAL elimina el cuello de botella.
MCP en los proveedores de LLM
El soporte de MCP varía drásticamente según el proveedor. Anthropic creó el protocolo y tiene la integración más profunda. Todos los demás están jugando a ponerse al día a distintas velocidades. Así está cada proveedor importante a mediados de 2026.
| Proveedor | Nivel de soporte MCP | Soporte de transporte | Preparación para producción | Calidad del SDK |
|---|---|---|---|---|
| Anthropic | Nativo —el originador | stdio + HTTP/SSE | Producción para ambos transportes | SDK oficiales de Python y TypeScript con cobertura completa de la especificación |
| OpenAI | Vía Agents SDK + adaptadores de la comunidad | stdio (Agents SDK), HTTP vía adaptadores | Agents SDK: producción. Adaptadores: calidad beta | Mantenidos por la comunidad; sin SDK MCP propio |
| Solo adaptadores de la comunidad | stdio, HTTP/SSE limitado | Solo desarrollo | Paquetes comunitarios en etapa temprana; documentación escasa | |
| DeepSeek | Ruta compatible con OpenAI | Vía el toolchain de adaptadores de OpenAI | Funciona, pero sin soporte | Sin SDK MCP dedicado; hereda las peculiaridades del adaptador de OpenAI |
| Plataformas de agregación (capa de infraestructura —enruta a todos los proveedores de abajo) | MCP gateway —conecta una vez, enruta a todas partes | HTTP/SSE con autenticación unificada | Producción con autenticación administrada, rate limits y logging | SDK de plataforma para Python, JavaScript, LangChain |
El patrón de MCP gateway. Una plataforma de agregación actúa como cliente MCP, se conecta a tus servidores MCP y expone las tools a cualquier LLM a través de un único endpoint de API. Escribes un servidor MCP. Lo usas con GPT-5.5, Claude Opus 4, Gemini 3 y DeepSeek V3 —todo a través de POST https://api.tokspan.com/v1/chat/completions con la misma API key. La plataforma maneja la traducción de protocolo para que tus tools MCP funcionen sin importar qué modelo esté activo. Una definición de servidor alimenta a más de 6 modelos. Consulta el quickstart de TokSpan para la configuración en 5 minutos.
MCP vs. Function Calling: cuándo usar cada uno
La decisión se reduce a una pregunta: ¿tus tools necesitan funcionar a través de múltiples clientes de LLM?
Usa solo function calling cuando llames directamente a una API de LLM —OpenAI, Anthropic o Google— y tus tools sean específicas de una sola aplicación. Pasas las definiciones de tools directamente en el arreglo tools del request de chat completions. La infraestructura es cero: sin proceso de servidor separado, sin capa de transporte, sin negociación de protocolo. Un bot de soporte al cliente que consulta el estado de un pedido a través de un endpoint REST interno en GET /orders/:id necesita function calling, no MCP. No sobre-ingenierías esto —MCP añade un proceso de servidor, un transporte y un handshake de protocolo para cero beneficio cuando tienes un solo cliente.
Usa MCP + function calling juntos cuando tengas múltiples clientes de IA —Claude Code en tu laptop, Cursor en la de tu compañero y un dashboard personalizado en tu servidor de staging— que necesiten las mismas tools. Tu herramienta de consulta de base de datos, tu herramienta de deploy y tu visor de logs se definen una vez en un servidor MCP. Cada cliente las descubre a través de tools/list y las llama mediante function calling en runtime.
Tu catálogo de tools está centralizado. Las actualizaciones a las descripciones o schemas de las tools se propagan instantáneamente a cada cliente sin redeploy. Un equipo de plataforma interna en una organización de ingeniería de 200 personas que usa este patrón redujo el mantenimiento de integración de tools de 8 horas por tool nueva a 30 minutos.
Usa MCP como gateway cuando enrutes llamadas de tools a múltiples proveedores de LLM a través de una plataforma de agregación. Una definición de servidor MCP alimenta tools a GPT-5.5, Claude Opus 4 y Gemini 3 simultáneamente. La plataforma traduce entre el protocolo de descubrimiento de tools de MCP y la API de function calling de cada proveedor. Nunca escribes definiciones de tools específicas de proveedor. Nunca depuras por qué una tool funciona con Claude pero falla silenciosamente con GPT-5.5. Una definición de servidor alimenta más de 6 modelos a través de un único endpoint —sin configuración de tools por proveedor requerida.
La elección equivocada —desde la experiencia. Considera un escenario típico: un desarrollador en una startup pequeña pasa dos semanas configurando servidores MCP con transporte HTTP/SSE, middleware de autenticación y connection pooling para tres tools internas usadas exclusivamente con Claude Code. El function calling habría tomado dos horas. Dos semanas de tiempo de ingeniería intercambiadas por una infraestructura que sirvió exactamente a un cliente. Empieza con function calling. Migra a MCP cuando llegues a tu segundo cliente —no antes.
MCP en producción: autenticación, rate limiting y manejo de errores
stdio es para desarrollo. HTTP+SSE es para producción. El transporte stdio corre tu servidor MCP como subproceso —sin autenticación, sin seguridad de red, un cliente por proceso de servidor. Está bien para claude_desktop_config.json en tu laptop. Está mal para un servicio que atiende a 50 desarrolladores de tu organización. El transporte HTTP+SSE te permite desplegar el servidor como un servicio independiente detrás de un load balancer, con autenticación apropiada, monitoreo y ciclos de deploy independientes.
Middleware de autenticación. La especificación del transporte HTTP de MCP todavía no define un mecanismo de autenticación estándar a mediados de 2026. Añades el tuyo propio. El patrón común: validar una API key en el header Authorization: Bearer <key> antes de que se procese cualquier mensaje MCP. Para un despliegue basado en TokSpan, la plataforma maneja la autenticación en la capa del gateway de API —tu servidor MCP recibe requests pre-autenticados en https://api.tokspan.com/v1/. Si auto-alojas, añade middleware de autenticación antes del handler de MCP.
Un token expirado en la profundidad 3 de una cadena de tools —donde tool_a llama a tool_b que llama a tool_c— produce un error JSON-RPC críptico que toma 45 minutos rastrear hasta la capa de autenticación. Haz bien la autenticación antes que cualquier otra cosa. Para una checklist de seguridad completa, consulta nuestra checklist de seguridad en producción.
# Auth middleware for MCP HTTP server (FastAPI pattern)
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
VALID_TOKENS = {"mcp-secret-abc123", "mcp-prod-xyz789"} # Replace with DB lookup
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
if request.url.path.startswith("/mcp/"):
token = request.headers.get("Authorization", "").removeprefix("Bearer ")
if token not in VALID_TOKENS:
raise HTTPException(status_code=401, detail="Invalid MCP API key")
return await call_next(request)
El rate limiting previene incidentes amplificados por LLM. Una tool descrita vagamente —una tool run_sql sin enforcement de LIMIT— y un LLM genera una query que escanea 10 millones de filas a las 2 AM porque un usuario pidió “muéstrame todo”. Un rate limiter de token bucket en el lado del servidor limita query_users a 60 llamadas por minuto y create_user a 10 llamadas por minuto. Usa Redis para el rate limiting distribuido a través de múltiples instancias de servidor —INCR + EXPIRE por nombre de tool por API key.
Sin rate limiting, un solo prompt de LLM entusiasta se convierte en la causa raíz de una interrupción de la base de datos de producción. Te van a llamar a las 3 AM. Vas a rastrearlo hasta una definición de tool que escribiste en 15 minutos y olvidaste hace seis sprints.
Manejo de errores que ayuda al LLM a recuperarse. No devuelvas "Error: something went wrong." El LLM lee tu mensaje de error e intenta de nuevo. Devuelve tres cosas: el tipo de error, el parámetro específico que falló y las alternativas válidas. Este error es peso muerto: "Invalid input." Este le permite a Claude auto-corregirse en un reintento: "create_user failed: role must be one of [admin, editor, viewer]. Received: 'superadmin'." La diferencia entre esos dos mensajes de error es la diferencia entre una cadena de tools auto-reparable y un usuario atascado mirando un spinner hasta que se rinde y abre un ticket.
Errores comunes de MCP: qué se rompe en la práctica
Estos son cuatro modos de falla que los desarrolladores de MCP encuentran en su primer mes. Cada uno es evitable si lo conoces antes de desplegar.
Descripciones de tools vagas. Esta es la causa número uno de bugs de selección de herramienta incorrecta. "description": "Fetch data" no le dice nada al LLM. Claude Opus 4 adivinará qué tool usar y adivinará mal frecuentemente cuando varias tools tienen descripciones superpuestas. Escribe las descripciones de tools como si le explicaras la tool a un desarrollador que nunca ha visto tu codebase. Incluye qué hace la tool, qué devuelve, un ejemplo de entrada válida y cuándo NO usarla.
La descripción de query_users en el servidor de base de datos de arriba no es verbosa —es exactamente lo suficientemente precisa para eliminar la ambigüedad.
Límites del buffer de stdio. El transporte stdio usa pipes del sistema operativo. Buffer de pipe por defecto en Linux: 64KB. Tu tool query_large_dataset devuelve 2MB de JSON. La llamada write() se bloquea. El cliente se cuelga. Miras un spinner durante 30 segundos y luego kill -9 el proceso.
Para cualquier tool que pueda devolver más de 64KB, implementa chunking de respuestas —divide los resultados grandes en páginas con parámetros page y page_size. O cambia al transporte HTTP, donde los límites de tamaño de respuesta son configurables a nivel del framework del servidor. Pon un límite duro de respuesta de 512KB en cada tool. Ninguna tool en un servidor MCP debería devolver más datos de los que un LLM puede procesar útilmente en una sola ventana de contexto.
Colisiones de nombres de tools entre servidores. Conectas dos servidores MCP: uno del equipo de base de datos (get_status —replication lag), otro del equipo de ops (get_status —salud del deploy). Ambos exponen una tool llamada get_status. Claude Code antepone un prefijo con el nombre del servidor: database-tools_get_status y ops-tools_get_status. Pero algunos clientes MCP, incluyendo versiones recientes de Cursor, eligen silenciosamente el servidor que responda primero a tools/list. El arreglo es vergonzosamente simple y universalmente ignorado: namespacea cada nombre de tool desde el primer día. db_query_users. ops_deploy_service. logs_search_errors. Un prefijo de dos caracteres previene una categoría entera de fallas silenciosas.
Brechas de validación de schema. Un LLM enviará "user_id": "42" (string) cuando tu schema dice "type": "integer". Enviará "limit": -5 cuando tu schema dice "minimum": 1. Enviará "role": "superadmin" cuando tu schema dice "enum": ["admin", "editor", "viewer"]. Tu handler call_tool debe validar cada argumento, coerzar los tipos donde sea seguro (int("42") —42) y devolver errores de validación específicos para todo lo demás. Nunca asumas que el LLM respeta tu JSON Schema. No lo hace. Tu servidor es la última línea de defensa entre un argumento de tool alucinado y tu base de datos de producción.
FAQ
¿Necesito MCP si ya uso function calling?
Son complementarios, no excluyentes. El function calling ejecuta tools dentro de una llamada de API. MCP estandariza el descubrimiento y la descripción de tools a través de aplicaciones. Usa MCP para definir tu catálogo de tools —la fuente única de verdad sobre qué tools existen y cómo llamarlas. Usa function calling en runtime para invocar esas tools. MCP es la capa de interfaz. El function calling es la capa de ejecución. Si tienes exactamente una aplicación cliente y tres tools, salta MCP y usa function calling directamente. Sabrás cuándo necesitas MCP: en el momento en que te encuentres copiando y pegando definiciones de tools entre los archivos de configuración de Claude Code y el arreglo tools de tu app personalizada.
¿Puedo usar MCP con modelos de OpenAI?
Sí —vía adaptadores o el OpenAI Agents SDK. El soporte nativo es menos maduro que el de Anthropic pero funcional para patrones de tools comunes. Si usas una plataforma de agregación con soporte de MCP gateway, la plataforma maneja la traducción: tu servidor MCP funciona con GPT-5.5 y GPT-5.5-mini sin ningún código MCP específico de OpenAI de tu lado. El trade-off: los adaptadores de la comunidad van unos 3 a 6 meses por detrás del SDK oficial de Anthropic en las características nuevas de la especificación MCP.
¿Está MCP listo para producción en 2026?
Para tools locales vía transporte stdio: sí, y el cliente stdio de Claude Code está probado en batalla a través de millones de horas de desarrolladores. Para servicios remotos vía HTTP: sí, con la advertencia de que debes añadir tu propio middleware de autenticación —el estándar de autenticación del transporte HTTP todavía está evolucionando. El núcleo del protocolo (formato de mensaje JSON-RPC, descubrimiento de tools, ejecución de tools) es estable y, al momento de escribir esto, no ha tenido un cambio que rompa compatibilidad desde la actualización de la especificación del 2025-03-26. Si auto-alojas un servidor MCP HTTP, presupuesta 2 a 3 días para la configuración de autenticación, rate limiting y logging.
¿Cómo se relaciona MCP con las plataformas de agregación de API?
Las plataformas de agregación pueden servir como gateways MCP: conectas tus servidores MCP a la plataforma una vez. La plataforma enruta las llamadas de tools a cualquier LLM —GPT-5.5, Claude Opus 4, Gemini 3, DeepSeek V3. Obtienes uso de tools multi-modelo sin configuración MCP por proveedor. Un servidor MCP. Todos los modelos. Para detalles sobre cómo las plataformas de agregación implementan el enrutamiento de MCP gateway en la práctica, consulta los docs de integración de MCP de TokSpan.
¿Puedo conectar múltiples servidores MCP a un solo cliente?
Sí. Claude Code, Cursor y la mayoría de los clientes MCP soportan conectarse a múltiples servidores simultáneamente —añade cada servidor a tu archivo de configuración con un nombre único, y todas las tools de todos los servidores aparecen en la lista de tools disponibles del LLM. El filo cortante: colisiones de nombres de tools entre servidores. Nombra tus tools con un prefijo de namespace (db_query, ops_deploy) desde el primer día. No confíes en que el cliente desambiguará —no todos lo hacen, y los que lo hacen lo manejan de forma inconsistente.
¿Qué pasa cuando dos servidores MCP exponen tools con el mismo nombre?
Depende del cliente, y ese es el problema. Claude Code añade el nombre del servidor para crear identificadores únicos: database-tools_get_status y ops-tools_get_status. Cursor deduplica silenciosamente —el primer servidor en responder a tools/list gana. No confíes en absoluto en la desambiguación del lado del cliente. Prefija cada nombre de tool con un namespace específico del servidor. db_get_status y ops_get_status eliminan la ambigüedad en la fuente.
¿Cómo depuro llamadas de tools MCP cuando algo sale mal?
Revisa tres lugares, en orden. Primero, los logs del cliente —Claude Code escribe los mensajes MCP en su directorio de logs. Segundo, el stderr de tu servidor —el transporte stdio envía toda la salida de stderr a la consola del cliente (stdin y stdout están reservados para los mensajes del protocolo MCP, pero stderr es libre para logging). Tercero, añade logging JSON estructurado a tu servidor: {"event": "tool_call", "tool": "query_users", "args": {...}, "duration_ms": 45, "error": null}. Los logs estructurados atrapan el 80% de los bugs de MCP que solo aparecen durante las rotaciones de guardia cuando llevas 15 minutos gestionando un incidente y no tienes idea de qué llamada de tool falló ni por qué.
¿MCP soporta respuestas en streaming de las tools?
No en la especificación actual. Las llamadas de tools MCP devuelven un único arreglo content —sin respuestas parciales, sin actualizaciones de progreso, sin Server-Sent Events desde la ejecución de la tool. Para operaciones de larga duración como migraciones de base de datos o generación de reportes, devuelve un job ID inmediatamente y expón una tool get_job_status separada. El LLM la consulta. Este patrón de job-ID-más-polling es el estándar de facto que usa todo servidor MCP de producción importante a mediados de 2026. El soporte de streaming directo está en el roadmap de la especificación MCP pero no tiene una fecha de entrega comprometida.
MCP unificó la integración de tools de IA en 2025–2026 —un servidor, cualquier cliente, todos los modelos. Pero la estandarización invita a la competencia. El Agent-to-Agent Protocol (A2A) de Google está ganando tracción entre los equipos empresariales que necesitan comunicación agente-a-agente más allá del simple llamado de tools. OpenAI está construyendo su propio ecosistema de agent SDK con integración de plataforma más profunda. La pregunta que vale la pena observar a través de 2027 no es si MCP sobrevive —el protocolo en sí es sólido y la especificación es estable— sino si “un protocolo para gobernarlos a todos” dura más que el apetito de la industria por integraciones específicas de plataforma que ofrecen acoplamiento más estrecho y mejor rendimiento a costa del lock-in.
El servidor MCP que construiste en la primera sección de este artículo funciona con un cliente —Claude Desktop. Un MCP gateway conecta ese mismo servidor a todos los LLM de tu stack, así que las definiciones de tools que escribes una vez alimentan todos los modelos que usas. Los docs de integración de MCP de TokSpan cubren la configuración del gateway, la configuración de autenticación y la checklist de producción de la sección de arriba —convirtiendo el servidor stdio de 50 líneas en una capa de tools multi-modelo que sobrevive cambios de proveedor sin tocar una línea de código de tools.