Introducción a MCP
Hoy le pides a una IA un servidor MCP y te lo escribe. Este curso trata de lo que la IA no decide por ti: qué exponer, cómo describirlo para que el modelo lo use bien, qué tiene que confirmar una persona y cómo compruebas que funciona. El código está en cada lección, en TypeScript y Python, para que entiendas lo que te genera.
Objetivos de aprendizaje
Al terminar esta lección serás capaz de:
- Explicar qué coste de integración elimina MCP y cuál deja intacto
- Distinguir MCP del function calling y de una API REST, y situar cada uno en una llamada real
- Leer un intercambio tools/list y tools/call campo por campo
- Decidir cuándo un sistema justifica un servidor MCP y cuándo basta el function calling directo
- Clasificar una capacidad de un sistema interno como tool, resource o prompt
El problema
Nortia Logística es una empresa de logística y almacenes de unas 800 personas, con operaciones en España y
México. Es el caso que recorre todo el curso. Aquí importan cuatro de sus sistemas internos. Los pedidos y
envíos viven en PostgreSQL. La facturación tiene una API REST protegida con OAuth. Soporte trabaja con un
sistema de tickets, y los almacenes (MAD-01, BCN-02, MEX-01)
generan un flujo de eventos de inventario.
En un año han aparecido tres aplicaciones de IA. Soporte tiene un asistente que responde a "¿dónde está el
pedido PED-2026-004812?". Finanzas tiene un agente que concilia facturas con envíos y propone
abonos. La ingeniera de plataforma usa Claude Code para diagnosticar incidencias consultando esos mismos
datos. Cada equipo escribió su propia integración con cada sistema que necesitaba. Cada una lleva su
propia definición de funciones en el formato de su proveedor de modelos, su propio manejo de credenciales
y, si lo tiene, su propio registro de lo que se llamó.
Así que hay tres implementaciones de "buscar un pedido" con tres comportamientos distintos. Una filtra por inquilino (España y México deben estar separados), otra no. Cuando seguridad pregunta quién consultó datos personales de un cliente la semana pasada, la respuesta depende de qué aplicación lo hizo. Mientras tanto, la cuarta aplicación de IA ya está pedida.
N aplicaciones por M sistemas
Este coste sigue una forma conocida. Con N aplicaciones de IA y M sistemas, las integraciones punto a punto crecen como N × M. En Nortia son hasta 3 × 4 = 12, cada una con su código, sus credenciales y sus huecos.
flowchart LR
A1["Asistente de soporte"]
A2["Agente de conciliación"]
A3["Claude Code (plataforma)"]
S1[("PostgreSQL de pedidos")]
S2["API REST de facturación"]
S3["Sistema de tickets"]
S4["Eventos de inventario"]
A1 --> S1
A1 --> S2
A1 --> S3
A1 --> S4
A2 --> S1
A2 --> S2
A2 --> S3
A2 --> S4
A3 --> S1
A3 --> S2
A3 --> S3
A3 --> S4 MCP (Model Context Protocol) es un protocolo de especificación pública que fija el contrato entre una aplicación de IA y los sistemas que le aportan datos y acciones. Cada sistema se expone una sola vez mediante un servidor MCP, un programa que publica capacidades con un formato común. Cada aplicación incorpora un cliente MCP, el componente que habla el protocolo con un servidor. Las implementaciones pasan de N × M a N + M: tres clientes y cuatro servidores.
flowchart LR
A1["Asistente de soporte"]
A2["Agente de conciliación"]
A3["Claude Code (plataforma)"]
P{{"Contrato MCP<br/>tools/list · tools/call<br/>resources/read · prompts/get"}}
M1["nortia-pedidos"]
M2["nortia-facturacion"]
M3["nortia-soporte"]
M4["nortia-almacen"]
S1[("PostgreSQL de pedidos")]
S2["API REST de facturación"]
S3["Sistema de tickets"]
S4["Eventos de inventario"]
A1 --- P
A2 --- P
A3 --- P
P --- M1
P --- M2
P --- M3
P --- M4
M1 --> S1
M2 --> S2
M3 --> S3
M4 --> S4
Conviene leer la figura 2 con cuidado, porque es donde se suele exagerar. El nodo central es un contrato,
no un intermediario desplegado. En ejecución, cada aplicación sigue conectándose a cada servidor que usa.
Lo que desaparece es el trabajo repetido. La lógica de "buscar un pedido", su filtro por inquilino y su
registro de auditoría se escriben una vez, en nortia-pedidos, y las tres aplicaciones los
heredan. La cuarta aplicación no obliga a tocar ningún servidor.
Otro trabajo no desaparece. Alguien tiene que escribir y operar cuatro servidores, decidir qué aplicación accede a qué y con qué credenciales, y mantener el protocolo al día. Si en tu caso N es 1 y M es 2, la aritmética no sale a favor. Lo vemos más abajo.
Qué viaja entre cliente y servidor
En la práctica, MCP son mensajes JSON-RPC 2.0 con métodos de nombre fijo. El intercambio siguiente recorre el camino completo de la pregunta "¿dónde está el pedido PED-2026-004812?" en el asistente de soporte. Recórrelo paso a paso y fíjate en qué mensajes son MCP y cuáles no.
Figura 3. Del listado de tools al resultado de una llamada
Aplicación (cliente MCP) envía a nortia-pedidos: tools/list: qué sabes hacer
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "nortia-agente-soporte",
"version": "2.1.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
} No hay conexión previa que negociar. La petición lleva en _meta la versión del protocolo y las capacidades del cliente, que son obligatorias. clientInfo es recomendable y solo informativo.
nortia-pedidos envía a Aplicación (cliente MCP): definiciones de las tools
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"tools": [
{
"name": "buscar_pedido",
"title": "Buscar pedido",
"description": "Devuelve estado, almacén, transportista y fecha prevista de entrega de un pedido de Nortia. Úsala cuando el usuario dé un identificador PED-AAAA-NNNNNN. No busca por cliente ni por fecha.",
"inputSchema": {
"type": "object",
"properties": {
"pedido_id": {
"type": "string",
"description": "Identificador del pedido, por ejemplo PED-2026-004812"
}
},
"required": ["pedido_id"]
},
"annotations": { "readOnlyHint": true, "openWorldHint": false }
}
],
"ttlMs": 300000,
"cacheScope": "private",
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "nortia-pedidos",
"version": "1.4.0"
}
}
}
} Cada tool trae un nombre, una descripción pensada para el modelo y un JSON Schema de sus argumentos. ttlMs y cacheScope son obligatorios. Aquí la lista depende de los permisos del usuario, así que cacheScope es "private" y la lista no se comparte entre usuarios.
Aplicación (cliente MCP) envía a Modelo: la aplicación ofrece las tools al modelo
Este paso no es MCP. La aplicación convierte cada definición al formato de tools de la API de su proveedor de modelos y la envía junto con la conversación.
Modelo envía a Aplicación (cliente MCP): el modelo pide llamar a buscar_pedido
Tampoco es MCP: es el function calling del proveedor. El modelo no ejecuta nada. Emite una petición estructurada con el nombre de la tool y los argumentos, y la aplicación decide si la cursa.
Aplicación (cliente MCP) envía a nortia-pedidos: tools/call
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "buscar_pedido",
"arguments": {
"pedido_id": "PED-2026-004812"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "nortia-agente-soporte",
"version": "2.1.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
} La petición repite el _meta completo. El servidor no puede suponer nada de la anterior: quizá la atendió otra réplica.
nortia-pedidos envía a Aplicación (cliente MCP): resultado
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "{\"id\":\"PED-2026-004812\",\"estado\":\"en_reparto\",\"almacen\":\"MAD-01\",\"transportista\":\"TransIberia\",\"entregaPrevista\":\"2026-10-02\",\"clienteRef\":\"CLI-0931\"}"
}
],
"structuredContent": { "id": "PED-2026-004812", "estado": "en_reparto", "almacen": "MAD-01", "transportista": "TransIberia", "entregaPrevista": "2026-10-02", "clienteRef": "CLI-0931" },
"isError": false,
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "nortia-pedidos",
"version": "1.4.0"
}
}
}
} resultType "complete" indica que la petición terminó. El contenido son bloques pensados para entregarse al modelo. structuredContent repite los mismos datos como JSON tipado para el programa (lección 5). Un fallo de negocio, como un pedido inexistente, volvería como resultado con isError: true, no como error de protocolo.
Aplicación (cliente MCP) envía a Modelo: la aplicación entrega el resultado al modelo
De nuevo fuera de MCP. El modelo redacta la respuesta al agente de soporte con el dato real.
Tres hechos de este intercambio sostienen el resto del curso:
- El servidor se describe en ejecución. El cliente no trae compilada la lista de
operaciones, sino que la obtiene con
tools/list. Añadir una tool anortia-pedidosno exige desplegar de nuevo ninguna aplicación. - El modelo nunca toca el sistema. Entre la intención del modelo y PostgreSQL hay dos puntos de control que son código tuyo: la aplicación, que decide si cursa la llamada, y el servidor, que valida argumentos y permisos antes de ejecutar.
- Cada petición se explica sola. La versión 2026-07-28 del protocolo no tiene handshake ni
sesión. Por eso se repite el bloque
_meta. Y por eso también puedes poner un servidor MCP detrás de un balanceador, como cualquier servicio HTTP sin estado. La lección 3 lo desarrolla.
Qué es MCP y qué no es
Quien ya ha integrado modelos suele poner dos objeciones: "eso ya lo hago con function calling" y "eso ya lo tengo con mi API REST". Ambas se responden mirando entre qué dos piezas actúa cada contrato.
flowchart TB M["Modelo"] A["Aplicación de IA (contiene el cliente MCP)"] S["nortia-facturacion (servidor MCP)"] F["API REST interna de facturación"] M <-->|"function calling: API del proveedor del modelo"| A A <-->|"MCP: tools/list, tools/call"| S S <-->|"HTTP + OAuth: contrato propio de Nortia"| F
Frente al function calling
El function calling es el contrato entre el modelo y la aplicación. Fija cómo se le describen funciones al modelo y cómo expresa el modelo que quiere llamar a una. Lo define cada proveedor de modelos y no dice nada sobre dónde vive el código de la función ni quién lo mantiene. Con function calling directo, ese código vive dentro de la aplicación.
MCP no lo sustituye: lo usa. En los pasos 3 y 4 de la figura 3 sigue habiendo function calling. Lo que MCP cambia es el origen de las funciones: dejan de estar escritas en cada aplicación y pasan a publicarlas servidores independientes, con un formato que no depende del proveedor del modelo. Por eso, más que elegir entre "function calling o MCP", conviene preguntarse "¿dónde quiero que vivan las funciones y quién responde de ellas?".
Frente a una API REST
MCP tampoco sustituye a la API de facturación. nortia-facturacion es un consumidor más de esa
API. La diferencia está en para quién se diseña cada contrato. Una API REST la consume un programa cuyo
autor leyó la documentación y fijó en el código qué endpoint llamar. Un servidor MCP lo consume un modelo
que decide en cada conversación qué llamar, guiado únicamente por los nombres, descripciones y esquemas que
recibe de tools/list.
| Function calling directo | API REST | MCP | |
|---|---|---|---|
| Entre qué piezas | Modelo y aplicación | Dos programas cualesquiera | Aplicación de IA y servidor que expone un sistema |
| Quién define el formato | Cada proveedor de modelos | Cada API | Una especificación común |
| Dónde vive el código de la función | En cada aplicación | En el servicio | En el servidor MCP, una vez |
| Cómo se descubren las operaciones | Están escritas en la aplicación | Documentación leída por una persona | En ejecución, con tools/list |
| Quién elige qué operación llamar | El modelo | El programador | El modelo, con las definiciones que publica el servidor |
Lo que MCP no es
- No es un framework de agentes ni un modelo. No decide qué tool llamar ni en qué orden. Eso lo hacen el modelo y la aplicación.
- No es una capa de seguridad. La especificación obliga al servidor a validar entradas, controlar el acceso y limitar la tasa de llamadas, pero ese código lo escribes tú. La autorización es opcional en el protocolo. Cuando se usa sobre HTTP se basa en OAuth 2.1, y el curso la trata en el nivel Avanzado.
- No certifica lo que declara un servidor. Las anotaciones de una tool, como
readOnlyHint, son pistas que el servidor da sobre sí mismo. Lo mismo ocurre conclientInfo: es un dato autodeclarado que no sirve para decisiones de permisos. - No hace que una API mal diseñada sea útil para un modelo. Los servidores generados de forma automática, con una tool por cada endpoint, rinden peor que los diseñados a mano. El diseño de tools es trabajo aparte, y ocupa la primera lección del nivel Avanzado.
Las tres primitivas del servidor
Un servidor MCP puede exponer tres tipos de capacidad. El resto del nivel Básico dedica una lección a cada una; aquí basta con poder distinguirlas.
- Tools: operaciones con argumentos tipados que el modelo puede pedir que se ejecuten.
Pueden ser de lectura o de escritura, como
buscar_pedidooemitir_abono. - Resources: datos identificados por una URI que el cliente lee para aportarlos como contexto, como un artículo de la base de conocimiento de soporte.
- Prompts: plantillas de mensajes con argumentos que el servidor ofrece para arrancar una tarea de forma consistente, como la plantilla de respuesta a un retraso de entrega.
flowchart LR
C["Cliente MCP"]
subgraph SRV["nortia-soporte"]
T["Tools<br/>buscar_ticket, responder_ticket"]
R["Resources<br/>artículos de la base de conocimiento"]
P["Prompts<br/>plantillas de respuesta"]
end
K["Sistema de tickets"]
C -->|"tools/list, tools/call"| T
C -->|"resources/list, resources/read"| R
C -->|"prompts/list, prompts/get"| P
T --> K
R --> K
P --> K
La distinción tiene consecuencias de gobierno. Una tool puede cambiar datos, así que es donde se concentran
los permisos por rol, la aprobación humana y la auditoría. En Nortia, emitir_abono requiere
aprobación y buscar_pedido no. Un resource es una lectura con URI estable y su resultado se
puede cachear. Un prompt no ejecuta nada: solo devuelve mensajes.
Quién habla MCP hoy
Un protocolo vale lo que valga su adopción, así que aquí van solo los hechos comprobados en la documentación de cada producto el 2 de octubre de 2026. La versión actual de la especificación, 2026-07-28, se publicó el 28 de julio de 2026.
| Cliente | Transportes documentados | Versión del protocolo documentada |
|---|---|---|
| Claude Code | Streamable HTTP, stdio, WebSocket | 2026-07-28 (por defecto desde la v2.1.274) |
| claude.ai y Claude Desktop (conectores) | Streamable HTTP | No consta |
| API de Anthropic (MCP connector, en beta) | Streamable HTTP; solo tools | No consta |
| ChatGPT (modo desarrollador) | Streamable HTTP | No consta |
| API de OpenAI (Responses) y Codex | Streamable HTTP en la API; stdio y HTTP en Codex | No consta |
| Cursor | stdio, Streamable HTTP | No consta |
| VS Code (GitHub Copilot) | stdio, HTTP | No consta |
| Gemini CLI y API de Gemini | Streamable HTTP; el CLI también stdio | No consta |
El curso usa dos transportes: stdio para servidores locales lanzados como subproceso y Streamable HTTP para servidores remotos. La lección siguiente explica los dos.
De la tabla salen dos conclusiones y una cautela:
- El lado cliente está repartido entre proveedores que compiten. Un servidor como
nortia-pedidosno queda atado al proveedor de modelos que Nortia use hoy. - El lado servidor tiene soporte de plataforma. Cloudflare, Vercel, AWS, Google Cloud y Azure documentan cómo alojar servidores MCP. Según el anuncio de lanzamiento de la especificación, los SDK oficiales de TypeScript, Python, Go y C# soportan 2026-07-28. Existe además un MCP Registry oficial de metadatos de servidores públicos. Lo respaldan Anthropic, GitHub, PulseMCP y Microsoft, y sigue en preview.
- La cautela: solo Claude Code documenta que habla 2026-07-28. De los demás no consta qué versión usan, y para este curso no se ha probado ninguno contra un servidor 2026-07-28. No es un bloqueo, porque un mismo servidor puede atender la versión actual y las versiones con handshake. Aun así, es una decisión que tomar al desplegar, y el curso la trata en el nivel Avanzado.
En producción
Mapa del curso
El curso tiene tres niveles y 32 lecciones. Todos los ejemplos usan Nortia, así que los servidores crecen de una lección a otra en lugar de empezar de cero.
| Nivel | Qué sabrás hacer al terminar | Lecciones |
|---|---|---|
| Básico (14) | Entender el protocolo mensaje a mensaje y construir un servidor que funciona. | Arquitectura y transportes (2). Cómo viaja una petición (3). Recursos, herramientas y prompts (4 a 6). Interacción con el usuario y extensiones (7). Un caso completo mensaje a mensaje (8). Servidores en TypeScript y en Python (9 y 10). Agentes con MCP (11). MCP sin programar (12). Beneficios, desafíos y evolución del protocolo (13 y 14). |
| Avanzado (6) | Llevar un servidor a producción. | Diseño de tools. APIs externas y autorización con OAuth 2.1. Bases de datos. Operaciones largas y tiempo real. Testing y depuración. Despliegue con Cloudflare como plataforma guiada, comparada con las demás. |
| Experto (6) | Operar MCP a escala de empresa. | Gateways y arquitecturas distribuidas. Modelo de amenazas. Rendimiento y coste de contexto. Sistemas multi-agente. Multi-tenant, gobierno y cumplimiento. Caso de estudio: la plataforma MCP de Nortia. |
Las 17 lecciones del nivel Básico son gratuitas con tu cuenta. Si vienes de una versión anterior del protocolo, la lección 3 es la que concentra los cambios.
Recuerda
- MCP convierte N × M integraciones en N clientes y M servidores. Reduce implementaciones repetidas; no reduce las decisiones de acceso ni el trabajo de operar los servidores.
- MCP no sustituye al function calling ni a tu API REST. Actúa entre la aplicación de IA y el servidor que envuelve el sistema. Los otros dos contratos siguen ahí.
- El modelo no ejecuta nada. Emite una petición de llamada. La aplicación la convierte en
tools/cally el servidor decide si la ejecuta. - Un servidor expone tools (operaciones), resources (datos con URI) y prompts (plantillas de mensajes), y se describe en ejecución con los métodos
*/list. - En la versión 2026-07-28 no hay handshake ni sesión: cada petición lleva versión y capacidades en
_meta.
Desafío: inventario de integración de Nortia
Operaciones de Nortia quiere una cuarta aplicación de IA: un asistente para responsables de almacén. Debe poder:
- (a) consultar las existencias de un artículo en
MAD-01,BCN-02oMEX-01 - (b) abrir una incidencia de entrega sobre un pedido
- (c) leer el procedimiento interno de recuento de inventario, un documento que cambia un par de veces al año
- (d) redactar el aviso de rotura de stock a un cliente con el tono y los datos que exige el equipo de soporte.
Sin escribir código de servidor, entrega:
- Una tabla con las cuatro capacidades. Para cada una: en cuál de los cuatro servidores de Nortia vive, si es tool, resource o prompt, y si necesita aprobación humana o un permiso por rol, con el motivo.
- El recuento de trabajo: qué habría que implementar con integraciones punto a punto y qué con los servidores MCP ya existentes. Indica qué trabajo no desaparece en ninguno de los dos casos.
-
La petición
tools/callcompleta de la capacidad (a) para el almacénBCN-02, con todos los campos que has visto en la figura 3. La tool se llamaconsultar_existencias; los nombres de sus argumentos los decides tú. - Una frase que explique de dónde obtiene el servidor que el usuario pertenece al inquilino de España, y por qué no puede ser un argumento de la tool.
Criterio de éxito:
- Ninguna capacidad de solo lectura de un documento estable está modelada como tool sin justificarlo.
- La única escritura (b) tiene control de permisos razonado.
-
La petición del punto 3 incluye
jsonrpc,id,method,params.name,params.argumentsy un_metaconio.modelcontextprotocol/protocolVersionyio.modelcontextprotocol/clientCapabilities. - El punto 4 sitúa el inquilino en la credencial verificada por el servidor.