MCP (Model Context Protocol) Explicado: La Nueva Arquitectura para Agentes de IA
MCP (Model Context Protocol) Explicado: La Nueva Arquitectura para Agentes de IA
Guía completa del Model Context Protocol (MCP) de Anthropic. Aprende qué es, cómo funciona, su arquitectura, implementación con código y casos de uso reales para desarrolladores.
¿Qué es el Model Context Protocol (MCP)?
El Model Context Protocol (MCP) es un estándar abierto desarrollado por Anthropic que define cómo los modelos de lenguaje grande (LLMs) pueden interactuar con herramientas, fuentes de datos y servicios externos de manera estandarizada y segura.
Lanzado oficialmente en noviembre de 2024 y adoptado masivamente durante 2025, MCP resuelve un problema fundamental que tenían todos los desarrolladores construyendo sistemas de IA: cada integración era ad hoc, propietaria y difícil de mantener. Con MCP, la integración entre un LLM y cualquier herramienta o servicio sigue un protocolo común, similar a cómo HTTP estandarizó la comunicación web.
En términos simples: MCP es al mundo de la IA lo que los adaptadores USB-C son a los dispositivos electrónicos. Un estándar universal que permite que cualquier modelo se conecte a cualquier herramienta.
El Problema que MCP Resuelve
Antes de MCP, construir un asistente de IA que pudiera acceder a bases de datos, APIs externas, sistemas de archivos y herramientas diversas requería:
- Implementar function calling diferente para cada modelo (OpenAI, Anthropic, Google)
- Escribir código de integración personalizado para cada herramienta
- Gestionar manualmente el contexto y estado entre llamadas
- No había forma estándar de descubrir qué herramientas estaban disponibles
El resultado era código espagueti costoso de mantener y actualizar. Cada cambio en la API de un proveedor podía romper toda la cadena de integraciones.
Arquitectura de MCP: Los Tres Componentes Fundamentales
MCP define tres tipos de participantes en cualquier sistema:
1. MCP Hosts (Anfitriones)
Son las aplicaciones que utilizan el protocolo para conectarse con servidores MCP. Ejemplos: Claude Desktop, IDEs con soporte IA, aplicaciones personalizadas.
2. MCP Clients (Clientes)
Son los componentes que mantienen conexiones con los servidores MCP dentro del host. Gestionan el ciclo de vida de las conexiones.
3. MCP Servers (Servidores)
Son los programas ligeros que exponen capacidades específicas: acceso a archivos, conexión a bases de datos, llamadas a APIs externas, etc.
┌─────────────────────────────────────────────┐
│ MCP Host │
│ ┌─────────────┐ ┌──────────────────────┐│
│ │ LLM/IA │ │ MCP Client ││
│ │ (Claude, │◄──►│ (gestiona protocolo)││
│ │ GPT, etc) │ └──────────┬───────────┘│
│ └─────────────┘ │ │
└───────────────────────────────┼────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Servidor│ │ Servidor│ │ Servidor│
│ MCP │ │ MCP │ │ MCP │
│(archivos)│ │ (DB) │ │ (APIs) │
└──────────┘ └──────────┘ └──────────┘
Las Tres Primitivas de MCP
MCP define tres conceptos fundamentales que los servidores pueden exponer:
1. Resources (Recursos)
Son fuentes de datos que el modelo puede leer. Similar a endpoints GET en REST. Pueden ser:
- Archivos del sistema
- Registros de base de datos
- Respuestas de APIs
- Datos en tiempo real
// Definición de un resource en un servidor MCP
{
uri: "file:///usuarios/datos/reporte.csv",
name: "Reporte de ventas Q1",
description: "Datos de ventas del primer trimestre",
mimeType: "text/csv"
}
2. Tools (Herramientas)
Son funciones que el modelo puede invocar para realizar acciones. Similar a endpoints POST en REST. Son la parte más potente de MCP.
// Definición de una tool en un servidor MCP
{
name: "ejecutar_query_sql",
description: "Ejecuta una consulta SQL en la base de datos de producción",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "La consulta SQL a ejecutar (solo SELECT)"
},
database: {
type: "string",
enum: ["ventas", "usuarios", "inventario"],
description: "Base de datos objetivo"
}
},
required: ["query", "database"]
}
}
3. Prompts (Plantillas)
Son plantillas de prompts reutilizables que pueden aceptar argumentos. Permiten estandarizar interacciones comunes.
// Definición de un prompt template
{
name: "analizar_codigo_pr",
description: "Plantilla para revisar código en un Pull Request",
arguments: [
{
name: "codigo_diff",
description: "El diff del PR a analizar",
required: true
},
{
name: "contexto_proyecto",
description: "Descripción del proyecto y guías de estilo",
required: false
}
]
}
Implementación Práctica: Crear tu Primer Servidor MCP
Vamos a construir un servidor MCP funcional que exponga herramientas para manipular archivos JSON. Esto se integra perfectamente con flujos de trabajo donde necesitas validar datos JSON (como los que puedes formatear con nuestro Formateador JSON).
Configuración del Proyecto
mkdir mi-servidor-mcp
cd mi-servidor-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"strict": true
}
}
Implementación del Servidor
// src/server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import * as fs from "fs/promises";
import * as path from "path";
// Crear el servidor MCP
const server = new Server(
{
name: "json-tools-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Definir las herramientas disponibles
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "validar_json",
description: "Valida si una cadena es JSON válido y retorna el resultado formateado",
inputSchema: {
type: "object",
properties: {
json_string: {
type: "string",
description: "La cadena JSON a validar",
},
pretty_print: {
type: "boolean",
description: "Si se debe formatear el JSON con indentación",
default: true,
},
},
required: ["json_string"],
},
},
{
name: "extraer_campo_json",
description: "Extrae un campo específico de un objeto JSON usando una ruta de acceso",
inputSchema: {
type: "object",
properties: {
json_string: {
type: "string",
description: "El JSON fuente",
},
ruta: {
type: "string",
description: "Ruta al campo (ejemplo: 'usuario.nombre' o 'items[0].precio')",
},
},
required: ["json_string", "ruta"],
},
},
{
name: "transformar_json",
description: "Aplica transformaciones a un objeto JSON según instrucciones",
inputSchema: {
type: "object",
properties: {
json_string: {
type: "string",
description: "El JSON a transformar",
},
operacion: {
type: "string",
enum: ["aplanar", "filtrar_nulls", "ordenar_keys", "minificar"],
description: "La transformación a aplicar",
},
},
required: ["json_string", "operacion"],
},
},
],
};
});
// Manejar las llamadas a herramientas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "validar_json") {
const { json_string, pretty_print = true } = args as {
json_string: string;
pretty_print?: boolean;
};
try {
const parsed = JSON.parse(json_string);
const resultado = pretty_print
? JSON.stringify(parsed, null, 2)
: JSON.stringify(parsed);
return {
content: [
{
type: "text",
text: `JSON válido. Resultado:\n\`\`\`json\n${resultado}\n\`\`\``,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `JSON inválido. Error: ${(error as Error).message}`,
},
],
isError: true,
};
}
}
if (name === "extraer_campo_json") {
const { json_string, ruta } = args as {
json_string: string;
ruta: string;
};
try {
const obj = JSON.parse(json_string);
const partes = ruta.split(".");
let valor = obj;
for (const parte of partes) {
const match = parte.match(/^(\w+)\[(\d+)\]$/);
if (match) {
valor = valor[match[1]][parseInt(match[2])];
} else {
valor = valor[parte];
}
}
return {
content: [
{
type: "text",
text: `Valor en '${ruta}': ${JSON.stringify(valor, null, 2)}`,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error al extraer campo: ${(error as Error).message}`,
},
],
isError: true,
};
}
}
throw new Error(`Herramienta no encontrada: ${name}`);
});
// Iniciar el servidor
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Servidor MCP de JSON Tools iniciado");
}
main().catch(console.error);
Configuración en Claude Desktop
Para usar tu servidor MCP con Claude Desktop, añade la configuración al archivo de configuración:
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"json-tools": {
"command": "node",
"args": ["/ruta/absoluta/a/mi-servidor-mcp/dist/server.js"],
"env": {}
}
}
}
Protocolo de Comunicación: Cómo Funciona Internamente
MCP usa JSON-RPC 2.0 como protocolo de mensajes. Esto significa que toda comunicación es mediante mensajes JSON estructurados:
// Mensaje de petición (Host → Servidor)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "validar_json",
"arguments": {
"json_string": "{\"nombre\": \"Juan\", \"edad\": 30}",
"pretty_print": true
}
}
}
// Mensaje de respuesta (Servidor → Host)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "JSON válido. Resultado:\n```json\n{\n \"nombre\": \"Juan\",\n \"edad\": 30\n}\n```"
}
]
}
}
Transporte Soportados
MCP soporta múltiples mecanismos de transporte:
| Transporte | Caso de Uso | Ventajas |
|---|---|---|
| stdio | Procesos locales | Simple, sin configuración de red |
| HTTP + SSE | Servidores remotos | Escalable, compatible con web |
| WebSockets | Conexiones bidireccionales en tiempo real | Baja latencia |
Casos de Uso Reales en Producción
Caso 1: Servidor MCP para Base de Datos
// Servidor MCP para consultas de base de datos seguras
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
// Tool para consultas de solo lectura
{
name: "consultar_base_datos",
description: "Ejecuta una consulta SELECT en la base de datos",
inputSchema: {
type: "object",
properties: {
query: { type: "string" },
parametros: { type: "array", items: { type: "string" } }
},
required: ["query"]
}
}
// Implementación segura
async function ejecutarConsulta(query: string, params: string[] = []) {
// Validar que solo sean consultas SELECT
if (!query.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("Solo se permiten consultas SELECT por seguridad");
}
const resultado = await pool.query(query, params);
return resultado.rows;
}
Caso 2: Servidor MCP para GitHub
Un servidor MCP puede dar a Claude acceso directo a repositorios de GitHub para revisar PRs, analizar issues y sugerir cambios:
import { Octokit } from "@octokit/rest";
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
// Tools disponibles:
// - listar_prs_abiertos(repo)
// - obtener_diff_pr(repo, numero_pr)
// - crear_comentario_pr(repo, numero_pr, comentario)
// - listar_issues(repo, etiquetas)
// - obtener_contenido_archivo(repo, ruta, rama)
Caso 3: Servidor MCP para Gestión de Secretos
// Integración con HashiCorp Vault o AWS Secrets Manager
{
name: "obtener_secreto",
description: "Obtiene un secreto del vault de manera segura",
inputSchema: {
type: "object",
properties: {
nombre_secreto: {
type: "string",
description: "El nombre del secreto a recuperar"
},
entorno: {
type: "string",
enum: ["desarrollo", "staging", "produccion"]
}
},
required: ["nombre_secreto", "entorno"]
}
}
Para gestionar los hashes de los secretos de manera segura, puedes usar nuestro Generador de Hash. Y para validar los JWTs de autenticación entre servicios, el Decodificador JWT es una herramienta útil.
Seguridad en MCP: Mejores Prácticas
Principio de Mínimo Privilegio
Cada servidor MCP debe exponer solo las capacidades estrictamente necesarias:
// MALO: Exponer operaciones de escritura innecesarias
tools: ["leer_archivo", "escribir_archivo", "eliminar_archivo", "ejecutar_comando"]
// BUENO: Solo las operaciones necesarias para el caso de uso
tools: ["leer_archivo_configuracion", "validar_configuracion"]
Validación de Inputs
import { z } from "zod";
const SchemaConsultaSQL = z.object({
query: z.string()
.min(1)
.max(1000)
.refine(q => q.trim().toUpperCase().startsWith("SELECT"), {
message: "Solo se permiten consultas SELECT"
}),
limite: z.number().int().min(1).max(100).default(10),
});
// Usar en el handler
const input = SchemaConsultaSQL.parse(args);
Auditoría y Logging
// Registrar todas las invocaciones de herramientas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const timestamp = new Date().toISOString();
const { name, arguments: args } = request.params;
console.error(JSON.stringify({
timestamp,
evento: "tool_invocada",
herramienta: name,
argumentos_keys: Object.keys(args || {}),
// NUNCA loggear los valores para evitar filtrado de datos sensibles
}));
// ... implementación
});
Diferencias entre MCP y Function Calling Tradicional
| Característica | Function Calling Tradicional | MCP |
|---|---|---|
| Estándar | Propietario por proveedor | Abierto y universal |
| Descubrimiento | Manual, hardcoded | Dinámico vía protocolo |
| Reutilización | Ninguna entre proveedores | Total entre cualquier host |
| Transporte | Generalmente HTTP | stdio, HTTP, WebSocket |
| Estado | Sin estado | Con gestión de estado |
| Seguridad | A implementar manualmente | Primitivas de seguridad integradas |
| Ecosistema | Fragmentado | Creciente y unificado |
El Ecosistema MCP en 2026
Desde su lanzamiento, el ecosistema MCP ha crecido enormemente. Los servidores disponibles públicamente incluyen integraciones con:
- Bases de datos: PostgreSQL, MySQL, SQLite, MongoDB, Redis
- Control de versiones: GitHub, GitLab, Bitbucket
- Productividad: Google Drive, Notion, Confluence, Jira
- Cloud: AWS, GCP, Azure (servicios principales)
- Comunicación: Slack, Discord, Microsoft Teams
- Observabilidad: Datadog, Grafana, PagerDuty
- Herramientas de desarrollo: Docker, Kubernetes, Terraform
El directorio oficial en modelcontextprotocol.io lista más de 500 servidores MCP disponibles.
Construyendo un Sistema Multi-Agente con MCP
MCP no es solo para un agente y sus herramientas. Se puede usar para orquestar múltiples agentes especializados:
import anthropic
import json
client = anthropic.Anthropic()
def agente_con_herramientas(tarea: str, herramientas: list, sistema: str) -> str:
"""Ejecuta un agente con herramientas específicas."""
messages = [{"role": "user", "content": tarea}]
while True:
response = client.messages.create(
model="claude-opus-4",
max_tokens=4096,
system=sistema,
tools=herramientas,
messages=messages
)
if response.stop_reason == "end_turn":
return response.content[-1].text
if response.stop_reason == "tool_use":
# Procesar uso de herramientas
tool_uses = [b for b in response.content if b.type == "tool_use"]
tool_results = []
for tool_use in tool_uses:
resultado = ejecutar_herramienta(tool_use.name, tool_use.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": json.dumps(resultado)
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
def ejecutar_herramienta(nombre: str, argumentos: dict) -> dict:
"""Enruta la llamada a la herramienta correcta."""
# En un sistema real, esto se comunicaría con servidores MCP
herramientas_disponibles = {
"buscar_web": lambda args: {"resultados": ["resultado1", "resultado2"]},
"ejecutar_python": lambda args: {"output": eval(args.get("codigo", ""))},
"leer_archivo": lambda args: {"contenido": open(args["ruta"]).read()},
}
if nombre in herramientas_disponibles:
return herramientas_disponibles[nombre](argumentos)
raise ValueError(f"Herramienta no encontrada: {nombre}")
Debugging y Testing de Servidores MCP
Usando el Inspector MCP
# Instalar el inspector oficial
npm install -g @modelcontextprotocol/inspector
# Inspeccionar tu servidor
mcp-inspector node /ruta/a/tu/servidor.js
El inspector proporciona una interfaz web para:
- Ver todas las tools, resources y prompts disponibles
- Llamar herramientas directamente con inputs de prueba
- Ver los logs de comunicación JSON-RPC en tiempo real
Tests Unitarios para Servidores MCP
import { describe, it, expect } from "vitest";
import { createTestClient } from "@modelcontextprotocol/sdk/testing.js";
describe("Servidor MCP JSON Tools", () => {
it("debe validar JSON correcto", async () => {
const client = await createTestClient("node", ["dist/server.js"]);
const resultado = await client.callTool("validar_json", {
json_string: '{"nombre": "test"}',
pretty_print: true,
});
expect(resultado.content[0].text).toContain("JSON válido");
expect(resultado.isError).toBeUndefined();
});
it("debe detectar JSON inválido", async () => {
const client = await createTestClient("node", ["dist/server.js"]);
const resultado = await client.callTool("validar_json", {
json_string: "{nombre: sin_comillas}",
});
expect(resultado.isError).toBe(true);
});
});
Para validar los patterns de regex usados en el servidor, el Testeador de Regex es muy útil durante el desarrollo.
Roadmap de MCP: ¿Hacia Dónde Va el Protocolo?
El equipo de Anthropic y la comunidad open source tienen planes ambiciosos para 2026-2027:
MCP 2.0 (esperado Q3 2026):
- Soporte nativo para streaming de resources
- Autenticación OAuth integrada en el protocolo
- Namespace de herramientas para evitar colisiones
- Mejor soporte para herramientas asíncronas de larga duración
Adopción por otros proveedores: OpenAI, Google y Microsoft han indicado intención de soportar MCP como estándar de interoperabilidad.
Certificación de servidores: Se está trabajando en un programa de certificación para garantizar que los servidores MCP cumplen estándares de seguridad.
Conclusión: Por Qué MCP Importa
MCP representa un cambio paradigmático en cómo construimos sistemas de IA. En lugar de integraciones frágiles y propietarias, tenemos un estándar abierto que permite construir ecosistemas robustos y reutilizables.
Para los desarrolladores, esto significa:
- Menos tiempo escribiendo código de integración boilerplate
- Herramientas que funcionan con cualquier modelo compatible
- Una base de código más mantenible y testeable
- La posibilidad de contribuir al ecosistema compartido
Si construyes herramientas o agentes de IA, aprender MCP hoy no es opcional. Es la base sobre la que se construirá la siguiente generación de software inteligente.
Explora nuestras herramientas de desarrollo: Formateador JSON para trabajar con datos de APIs MCP, Testeador de Regex para validar patterns en tus servidores, y Decodificador JWT para autenticación en sistemas MCP remotos.