MCP (Model Context Protocol): La Guía Definitiva para Entender el Protocolo que Invierte la Integración con IA
Guía completa de MCP (Model Context Protocol): qué es, sus tres primitivas, por qué stdio es superior a HTTP, y cómo implementar un servidor funcional en 80 líneas de código.
Toda integración con IA que has construido está mal. Y no es tu culpa.
Añadiste una capa de API, un framework de orquestación, lógica de reintentos y un esquema personalizado.
*El problema real no es que necesites más middleware. Es que el patrón que usas está invertido. *
El Model Context Protocol (MCP) demuestra que la solución cabe en 80 líneas con JSON-RPC 2.0 sobre stdio. Sin LangChain, sin AutoGen, sin CrewAI.
El 90% de los desarrolladores no entiende todavía qué es MCP ni por qué importa. Lo tratan como "otro estándar más de API". Y se equivocan.
La verdad incómoda: MCP no es un protocolo de API genérico. Es el sistema nervioso de tu agente de IA.
---
El problema que nadie está resolviendo bien
Hasta ahora, integrar una IA con herramientas externas seguía este patrón:
❌ Construyes una REST API.
❌ Añades autenticación, rate limiting, manejo de errores.
❌ Escribes un adaptador para que el LLM entienda el esquema.
❌ Repites por cada herramienta.
❌ Repites por cada cliente (Claude, OpenAI, Gemini, local).
El resultado: cada integración es un proyecto nuevo. Cada modelo requiere su propio adaptador. El código se duplica, los errores se multiplican, y el mantenimiento se vuelve inviable.
El dogma imperante dice: "usa LangChain, usa AutoGen, usa CrewAI".
Pero la evidencia dice lo contrario. MCP demuestra que el patrón fundamental es trivialmente simple: un servidor JSON-RPC 2.0 sobre stdio puede exponer recursos, herramientas y prompts sin ningún framework de por medio.
*La complejidad real no está en el protocolo de integración. Está en diseñar buenos límites de herramientas y esquemas de recursos. *
---
Qué es MCP realmente
El Model Context Protocol es un estándar abierto (licencia Apache 2.0, respaldado por Anthropic pero diseñado como protocolo comunitario) que define cómo los proveedores de contexto — bases de datos, sistemas de ficheros, APIs externas — se exponen a los modelos de lenguaje.
Pero esto es lo que la mayoría no entiende:
MCP invierte el patrón de integración tradicional.
En el mundo REST, la IA llama a una API. La API define un contrato rígido y el cliente se adapta.
En el mundo MCP, el servidor expone sus capacidades y el host negocia qué funciones usar en cada sesión. La IA no "llama a una API". El contexto se le presenta a la IA de forma estructurada y negociada.
Esto cambia todo.
Las tres primitivas de MCP
MCP define exactamente tres tipos de interacciones. Nada más. Y eso es suficiente para cualquier integración con IA:
1. Resources (get_context) → El patrón RAG. El host solicita datos estructurados y el servidor los inyecta en la ventana de contexto del modelo. Sirve para: leer ficheros, consultar bases de datos, obtener documentos.
2. Tools (execute_action) → El patrón function calling. El modelo invoca operaciones externas a través del servidor. Sirve para: ejecutar código, enviar emails, modificar datos.
3. Prompts (render_template) → El patrón instruction-following. El servidor proporciona plantillas de prompts estructuradas. Sirve para: dar instrucciones predefinidas, guiar el comportamiento del modelo, estandarizar interacciones.
Cada primitiva mapea directamente a un patrón de interacción con IA. No tienes que forzar todo por un mismo agujero.
✅ Resources para datos.
✅ Tools para acciones.
✅ Prompts para instrucciones.
---
Por qué stdio transport es una feature, no una limitación
La mayoría de los desarrolladores, instintivamente, buscan HTTP/SSE para sus integraciones.
Error.
El transporte stdio (estándar input/output) ofrece ventajas que HTTP no puede igualar para herramientas locales de agente:
Aislamiento de procesos: cada servidor MCP corre en su propio proceso. Si se cuelga, no arrastra al host.
Componibilidad vía Unix pipes: puedes encadenar servidores MCP como encadenas comandos en terminal.
Sandboxing natural: el sistema operativo controla el acceso a ficheros, red y permisos. No necesitas una capa adicional de seguridad.
Depuración trivial: `console.log` en el terminal. Sin Postman, sin curl, sin configurar CORS.
Para herramientas locales — acceso a ficheros, ejecución de código, consultas a bases de datos — stdio es superior a HTTP tanto en seguridad como en simplicidad.
*El transporte no es una limitación técnica. Es una decisión arquitectónica que simplifica todo. *
---
El ecosistema MCP en 2026: no es solo Claude
Si crees que MCP solo sirve para Anthropic, te estás perdiendo el 80% del valor.
El ecosistema MCP ha crecido mucho más allá de Claude Desktop:
VS Code extensions: Cursor, Continue.dev, CodeGPT ya soportan MCP nativamente.
Agent frameworks: LangChain tiene adaptador MCP. El SDK de OpenAI Agents también integra MCP.
Developer tools: Zed editor, Replit, y varias herramientas de desarrollo ya consumen servidores MCP.
Modelos locales: vía Ollama y adaptadores ligeros, cualquier modelo local puede consumir herramientas MCP.
Un solo servidor MCP que construyes hoy funciona en todos estos entornos sin cambiar una línea.
Eso es el network effect. Y es la razón por la que MCP no va a morir en seis meses. Está resolviendo un problema real y doloroso que toda aplicación con IA enfrenta.
---
Caso práctico: Servidor MCP en 80 líneas
Vamos a construir un servidor MCP en Python usando el SDK oficial. Este servidor expone un recurso de sistema de ficheros, una herramienta de búsqueda y una plantilla de prompt de resumen.
```python
server.py — MCP Server en 80 líneas
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types
import os, json, glob
1. Crear el servidor
server = Server("filesystem-server")
2. Recurso: listar ficheros de un directorio
@server.list_resources()
async def handle_list_resources():
resources = []
for f in glob.glob("./data/*.md"):
uri = f"file://{os.path.abspath(f)}"
resources.append(types.Resource(
uri=uri,
name=os.path.basename(f),
description=f"Markdown file: {os.path.basename(f)}",
mimeType="text/markdown"
))
return resources
@server.read_resource()
async def handle_read_resource(uri: str):
path = uri.replace("file://", "")
if not os.path.exists(path):
raise ValueError(f"File not found: {path}")
with open(path, "r") as f:
content = f.read()
return types.ReadResourceResult(
contents=[types.TextResourceContents(
uri=uri,
mimeType="text/markdown",
text=content
)]
)
3. Herramienta: buscar texto en ficheros
@server.list_tools()
async def handle_list_tools():
return [
types.Tool(
name="search_files",
description="Search for text across all markdown files",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string", "description": "Texto a buscar"}
},
"required": ["query"]
}
)
]
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict):
if name == "search_files":
query = arguments["query"].lower()
results = []
for f in glob.glob("./data/*.md"):
with open(f, "r") as fh:
lines = fh.readlines()
for i, line in enumerate(lines, 1):
if query in line.lower():
results.append(f"{os.path.basename(f)}:{i}: {line.strip()}")
return [types.TextContent(type="text", text="\n".join(results) or "No results")]
4. Prompt: plantilla de resumen
@server.list_prompts()
async def handle_list_prompts():
return [
types.Prompt(
name="summarize",
description="Resume un fichero markdown",
arguments=[
types.PromptArgument(
name="filename",
description="Nombre del fichero a resumir",
required=True
)
]
)
]
@server.get_prompt()
async def handle_get_prompt(name: str, arguments: dict):
if name == "summarize":
path = f"./data/{arguments['filename']}"
if not os.path.exists(path):
return types.GetPromptResult(messages=[])
with open(path, "r") as f:
content = f.read()
return types.GetPromptResult(
messages=[
types.PromptMessage(
role="user",
content=types.TextContent(
type="text",
text=f"Resume el siguiente documento markdown en 3 puntos clave:\n\n{content}"
)
)
]
)
5. Arrancar con stdio transport
async def main():
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="filesystem-server",
server_version="0.1.0"
)
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
```
---
Cliente MCP en TypeScript: el otro lado del handshake
Para consumir el servidor, necesitas un cliente que se conecte por stdio, negocie capacidades y ejecute tools. Aquí tienes un cliente mínimo en TypeScript:
```typescript
// client.ts — MCP Client sobre stdio
import { Client } from "@modelcontextprotocol/sdk";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { spawn } from "child_process";
async function main() {
// 1. Lanzar el server como subproceso
const proc = spawn("python3", ["server.py"], {
stdio: ["pipe", "pipe", "pipe"]
});
// 2. Crear transporte stdio
const transport = new StdioClientTransport({
stdin: proc.stdin,
stdout: proc.stdout,
stderr: proc.stderr
});
// 3. Conectar cliente
const client = new Client({
name: "demo-client",
version: "0.1.0"
});
await client.connect(transport);
// 4. Listar herramientas disponibles
const tools = await client.listTools();
console.log("Tools disponibles:", tools.map(t => t.name));
// 5. Ejecutar una búsqueda
const result = await client.callTool({
name: "search_files",
arguments: { query: "MCP" }
});
console.log("Resultado:", result.content[0].text);
// 6. Cerrar
await client.close();
proc.kill();
}
main().catch(console.error);
```
---
El framework: El Patrón de 3 Capas para MCP en Producción
No tires el código anterior a producción sin estructura. Necesitas el Patrón de 3 Capas para Servidores MCP.
Capa 1: Transporte (stdio o HTTP)
Decide el transporte según el caso de uso:
stdio → Herramientas locales (ficheros, DB local, ejecución de código). Siempre优先 stdio.
HTTP con SSE → Herramientas remotas (APIs externas, servicios cloud). Solo cuando el servidor no puede correr localmente.
Capa 2: Primitivas (Resources + Tools + Prompts)
No mezcles las tres primitivas. Cada una tiene un propósito distinto:
Resources: para datos que el modelo necesita leer (documentos, registros, configuraciones).
Tools: para acciones que el modelo necesita ejecutar (escribir, enviar, modificar).
Prompts: para instrucciones que el modelo necesita seguir (plantillas, guías, workflows).
Si estás usando Tools para devolver datos, lo estás haciendo mal. Usa Resources.
Capa 3: Validación y error handling
MCP no te salva de ti mismo. Cada tool debe:
1. Validar argumentos antes de ejecutar.
2. Devolver errores estructurados (no excepciones crudas).
3. Limitar el tamaño de las respuestas (el contexto no es infinito).
```python
Validación básica en tool
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict):
if name == "search_files":
if "query" not in arguments:
return [types.TextContent(
type="text",
text="Error: 'query' es requerido"
)]
query = arguments["query"].strip()
if len(query) < 2:
return [types.TextContent(
type="text",
text="Error: 'query' debe tener al menos 2 caracteres"
)]
... ejecutar búsqueda
```
---
Objeciones que seguro te estás haciendo
"MCP solo sirve para Claude/Anthropic"
Falso. MCP es protocolo-level, no model-specific. OpenAI function calling, Gemini tool use, y modelos locales vía Ollama consumen el mismo patrón subyacente. Construyes un servidor MCP hoy y lo conectas a cualquier modelo con un adaptador de unas pocas líneas.
"JSON-RPC 2.0 es demasiado simple para mi caso de uso"
La simplicidad está en el wire format, no en las capacidades. MCP soporta streaming (vía notificaciones), comunicación bidireccional (host y server pueden enviar mensajes), y patrones de suscripción a recursos. Si necesitas actualizaciones en tiempo real estilo WebSocket, el mecanismo de resource subscription de MCP lo maneja nativamente.
"Esto es otro estándar que morirá en seis meses"
MCP es open-source con licencia Apache 2.0. Está respaldado por Anthropic pero diseñado como protocolo comunitario. Ya tiene adopción más allá del ecosistema Anthropic: VS Code, agent frameworks, herramientas de desarrollo independientes. El patrón que codifica — provisión estructurada de contexto para LLMs — resuelve un problema real y doloroso que toda aplicación con IA enfrenta. Eso lo hace más parecido a HTTP que a un vendor play.
---
Por dónde empezar hoy
Si te llevas algo de esta guía, que sea esto:
1. No necesitas LangChain ni ningún framework de agentes para integrar IA con herramientas externas. Un servidor MCP con stdio transport y tres primitivas basta.
2. Diseña primero los límites de tus herramientas, no el protocolo. La calidad de tu integración depende de lo bien que definas qué hace cada tool, no de cuántas capas de abstracción le pongas.
3. Un servidor MCP que construyes hoy funciona en Claude Desktop, VS Code extensions, agent frameworks y modelos locales. Es la inversión con mayor retorno que puedes hacer en infraestructura de IA.
Instala el SDK, escribe tu primer servidor, y conéctalo al Inspector de MCP (`npx @modelcontextprotocol/inspector`). En una tarde tendrás tu primera integración funcionando.
*El futuro de la integración con IA no es más frameworks. Es menos. Y MCP es la prueba. *
Lee el artículo completo en brianmenagomez.com
Más sobre mis servicios en brianmenagomez.com
Herramientas: Conversor IAE CNAE · Gestorias cerca de ti · Calculadora IRPF

