MCP para principiantes: Crea un servidor y un cliente, y luego úsalos en entornos empresariales.
MCP para principiantes: el problema N x M, las ideas clave explicadas de forma sencilla, un servidor y cliente de servicio de asistencia en TypeScript con Node.js, y el paso hacia despliegues seguros mediante HTTP.
Fuentes: MCP Tools Inside Enterprise Applications: A Beginner-Friendly Deep Dive
Cualquiera que haya trabajado recientemente con agentes de IA se ha encontrado con MCP, el Model Context Protocol. Aparece en Claude Desktop, en plugins para IDE, en proyectos de “portal de IA” internos de las empresas y, cada vez más, en software empresarial en producción.
Se trata de una guía para principiantes que no presupone experiencia previa con MCP. Comienza con el problema que resuelve el protocolo, aborda su arquitectura, crea un servidor y un cliente reales en TypeScript con Node.js, y luego analiza la seguridad, la gobernanza y la capacidad de observación que las empresas implementan alrededor de todo ello. Los diagramas están en formato ASCII de texto plano, por lo que se pueden pegar directamente en notas o documentación de código.
1. El problema que aborda MCP
Antes de MCP, hacer que un agente realizara una tarea concreta, como leer un registro de CRM, abrir un ticket de ITSM o consultar un almacén de datos, significaba exactamente una cosa: escribir código de integración personalizado y único para ese agente y ese sistema.
Eso es tolerable hasta que hay varios agentes (un bot de soporte, un asistente de programación, un ayudante interno de conocimientos) y varios sistemas (Salesforce, Jira, una base de datos de recursos humanos, un almacén). El resultado es una acumulación combinatoria de conectores creados a mano.
BEFORE MCP — the N x M integration problem
┌───────────┐ ┌─────────────┐
│ Agent A │───────▶│ CRM API │ (custom connector #1)
└───────────┘ └─────────────┘
┌───────────┐ ┌─────────────┐
│ Agent A │───────▶│ Ticketing │ (custom connector #2)
└───────────┘ └─────────────┘
┌───────────┐ ┌─────────────┐
│ Agent B │───────▶│ CRM API │ (custom connector #3 -
└───────────┘ └─────────────┘ yes, AGAIN, for a different agent)
┌───────────┐ ┌─────────────┐
│ Agent B │───────▶│ Data │ (custom connector #4)
└───────────┘ │ Warehouse │
└─────────────┘
N agents x M systems = N x M custom, non-reusable integrations.
Every new agent re-implements auth, retries, schemas, error handling.
USB resolvió el mismo tipo de problema para los periféricos de hardware, y ODBC y JDBC lo hicieron para las bases de datos: demasiados conectores personalizados y falta de un estándar común. MCP es la respuesta de Anthropic, publicada como un protocolo abierto y no como una función exclusiva de Claude, de modo que cualquier aplicación de IA y cualquier backend pueden comunicarse en un lenguaje común.
AFTER MCP — one protocol, many servers, many clients
┌───────────┐ ┌───────────────────┐
│ Agent A │──┐ ┌─▶│ MCP Server: CRM │
└───────────┘ │ ┌───────────┐ │ └───────────────────┘
├───▶│ MCP │───┤ ┌───────────────────┐
┌───────────┐ │ │ (shared │ ├─▶│ MCP Server: Ticket │
│ Agent B │──┘ │ protocol)│ │ └───────────────────┘
└───────────┘ └───────────┘ │ ┌──────────────────┐
└─▶│ MCP Server: DW │
└──────────────────┘
Any MCP-compatible agent can now talk to any MCP server.
Build the connector once, reuse it everywhere.
La idea se resume en una sola oración. MCP proporciona a las aplicaciones de IA una forma común de encontrar herramientas, llamarlas, leer datos y utilizar plantillas de prompts, de modo que la integración se escribe una sola vez y cualquier cliente que cumpla con los requisitos puede reutilizarla.
2. Conceptos básicos en términos sencillos
Se utilizan cuatro términos de manera aproximada, por lo que se definen con precisión antes de escribir cualquier código.
- Anfitrión. La aplicación impulsada por IA con la que interactúa realmente el usuario final, como un asistente de chat interno, un complemento de IDE o un copiloto de soporte, y es la parte que contiene el LLM.
- Cliente MCP. Un componente dentro del anfitrión que gestiona una única conexión a un único servidor MCP. Un anfitrión que se comunica con tres servidores backend suele ejecutar tres clientes, uno por servidor.
En esencia, todos los mensajes utilizan JSON-RPC 2.0, un formato sencillo y ampliamente adoptado para solicitudes, respuestas y notificaciones. La SDK lo genera por usted, pero conocer este formato explica por qué las herramientas de depuración de MCP se asemejan a las herramientas de API que ya utiliza, con un ID de solicitud, nombre del método, parámetros y un resultado o error.
Qué puede ofrecer un servidor: tres primitivas
- Herramientas son funciones llamables que permiten al modelo actuar o obtener resultados calculados, y es el modelo quien decide cuándo invocarlas, según lo que solicite el usuario. Ejemplos:
create_support_ticket,get_employee_details. - Recursos son datos de solo lectura que el servidor puede adjuntar como contexto, como archivos o registros. La aplicación o el usuario deciden qué adjuntar. Ejemplos: un artículo de la base de conocimientos, un PDF de políticas, un archivo de registro.
En la mayoría de las integraciones empresariales, las herramientas realizan aproximadamente el 90% del trabajo importante, por lo que se desarrollan primero.
3. La arquitectura: tres capas juntas
┌─────────────────────────── HOST APPLICATION ───────────────────────────┐
│ e.g. an internal AI assistant, IDE plugin, support copilot │
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ MCP Client 1 │ │ MCP Client 2 │ │ MCP Client 3 │ │
│ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │
└───────────┼────────────────────────┼───────────────────────┼───────────┘
│ JSON-RPC over │ JSON-RPC over │ JSON-RPC over
│ stdio / HTTPS │ stdio / HTTPS │ stdio / HTTPS
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ MCP Server │ │ MCP Server │ │ MCP Server │
│ wraps HR system │ │ wraps Ticketing │ │ wraps Data │
│ (tools: lookup, │ │ (tools: create, │ │ Warehouse │
│ update) │ │ status, close) │ │ (tools: query) │
└──────────────────┘ └──────────────────┘ └─────────────────┘
Cada servidor MCP está diseñado para ser pequeño y enfocado, con un servidor separado para cada sistema backend y sin un único servidor gigantesco que abarque todo. Este enfoque se toma de los microservicios, caracterizados por un radio de influencia reducido, despliegue independiente, escalabilidad independiente y responsabilidad del equipo que gestiona ese backend.
4. Creación de un primer servidor MCP (Node.js y TypeScript)
El ejemplo funcional es un servidor MCP de servicio de soporte técnico que cuenta con dos herramientas: una para crear un ticket de soporte y otra para verificar el estado de dicho ticket. Este modelo refleja un patrón muy común en las empresas, que consiste en utilizar una API interna de gestión de tickets o ITSM.
4.1 Configuración del proyecto
mkdir helpdesk-mcp-server && cd helpdesk-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript tsx @types/node
npx tsc --init
@modelcontextprotocol/sdk es el paquete oficial. Se encarga del JSON-RPC en la transmisión, de los transportes y de las primitivas, por lo que el JSON-RPC en bruto nunca se manipula a mano. zod es una biblioteca de validación de esquemas. Las entradas de las herramientas MCP se verifican contra un esquema antes de que se ejecute el código del manejador, lo cual es de gran importancia en entornos empresariales, ya que las llamadas mal formadas o maliciosas se detienen desde el inicio.
4.2 El código del servidor
// src/server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// --- A stand-in for a real internal ticketing API client ---
// In a real enterprise server this would call your ITSM system
// (ServiceNow, Jira Service Management, Zendesk, an internal API, etc.)
const ticketStore = new Map<string, { status: string; subject: string }>();
let nextId = 1000;
// 1. Create the server instance.
// "name" and "version" identify this server to any client that connects.
const server = new McpServer({
name: "helpdesk-mcp-server",
version: "1.0.0",
});
// 2. Register a tool: create_support_ticket
server.registerTool(
"create_support_ticket",
{
title: "Create Support Ticket",
description:
"Creates a new IT helpdesk ticket for the requesting employee.",
inputSchema: {
subject: z.string().describe("Short summary of the issue"),
priority: z.enum(["low", "medium", "high", "urgent"]),
employeeId: z.string().describe("Requesting employee's ID"),
},
outputSchema: {
ticketId: z.string(),
status: z.string(),
},
},
async ({ subject, priority, employeeId }) => {
const ticketId = `TCK-${nextId++}`;
ticketStore.set(ticketId, { status: "open", subject });
const output = { ticketId, status: "open" };
// MCP tool results return a "content" array (what a human/LLM reads)
// and, optionally, "structuredContent" (typed data other code can use).
return {
content: [
{
type: "text",
text: `Created ticket ${ticketId} (priority: ${priority}) for employee ${employeeId}.`,
},
],
structuredContent: output,
};
}
);
// 3. Register a second tool: get_ticket_status
server.registerTool(
"get_ticket_status",
{
title: "Get Ticket Status",
description: "Looks up the current status of an existing support ticket.",
inputSchema: {
ticketId: z.string(),
},
outputSchema: {
status: z.string(),
},
},
async ({ ticketId }) => {
const ticket = ticketStore.get(ticketId);
if (!ticket) {
// Returning isError lets the model know the call failed
// WITHOUT crashing the whole conversation.
return {
content: [{ type: "text", text: `No ticket found with ID ${ticketId}.` }],
isError: true,
};
}
return {
content: [{ type: "text", text: `Ticket ${ticketId} is currently "${ticket.status}".` }],
structuredContent: { status: ticket.status },
};
}
);
// 4. Wire the server to a transport and start listening.
// stdio is perfect for local development and desktop-hosted tools.
const transport = new StdioServerTransport();
await server.connect(transport);
4.3 Función de cada parte
- La instancia
McpServer. Este objeto es el corazón del servidor. Registra todas las herramientas, recursos y comandos disponibles, y se encarga del proceso de intercambio MCP (negociación de capacidades) cuando un cliente se conecta. Nunca se elabora manualmente una lista de herramientas, ya que el SDK la genera a partir de las llamadas aregisterTool. inputSchemacon Zod. Más que documentación: el SDK lo utiliza para generar un JSON Schema que indica al cliente y al LLM qué argumentos son válidos, y para verificar cada llamada que recibe. Un cliente que envíepriority: "banana"será rechazado antes incluso de llegar al procesador. Para una empresa, esta validación basada en esquemas es un verdadero control de seguridad y no solo una ventaja adicional.
outputSchema y structuredContent. Una herramienta puede devolver un resumen legible por humanos (content) y también un objeto legible por máquinas (structuredContent). El texto se muestra en la transcripción del chat, mientras que la aplicación que realiza la llamada puede analizar los datos estructurados para generar una interfaz de usuario o aplicar lógica adicional.isError: true. MCP cuenta con un concepto de primer nivel para los errores a nivel de herramienta, distinto de los errores a nivel de protocolo. Esto significa que la operación falló, pero la conversación debe continuar; por lo tanto, el modelo puede leer el error y decidir si intentarlo de nuevo, preguntarle al usuario o probar otra herramienta. No se desea que toda la sesión del agente se deteriore solo porque no existía un ID de ticket determinado.StdioServerTransport). La parte que mueve los bytes. Para herramientas locales como el IDE de un desarrollador o un asistente de escritorio, stdio es la opción más sencilla, ya que el host inicia al servidor como un proceso hijo. Cualquier aplicación que se ejecute de forma centralizada en una empresa utilizaría el transporte basado en HTTP, el cual se explica en la Sección 6.4.4 Ejecutarlo
npx tsx src/server.ts
Por sí solo, el servidor no muestra nada, ya que está esperando a que un cliente se conecte a través de stdin y stdout. Ahora viene el cliente.
5. Un cliente dentro de una aplicación empresarial
Los principiantes suelen crear un servidor y luego se preguntan qué es lo que realmente se comunica con él. Aquí hay un cliente mínimo, imaginado como parte de un backend interno de Node.js que impulsa al asistente de IA de una empresa.
// src/client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function main() {
// 1. Describe how to launch the server. Here we spawn it as a
// local subprocess - in production you'd more commonly point
// this at a remote HTTP-based server instead (see Section 6).
const transport = new StdioClientTransport({
command: "npx",
args: ["tsx", "src/server.ts"],
});
// 2. Create a client and connect. This performs the MCP
// handshake and capability negotiation automatically.
const client = new Client({ name: "internal-ai-assistant", version: "1.0.0" });
await client.connect(transport);
// 3. Discover what tools this server offers - this is the same
// mechanism an LLM uses to "learn" what it can do.
const { tools } = await client.listTools();
console.log("Available tools:", tools.map((t) => t.name));
// 4. Call a tool, just like the LLM would.
const result = await client.callTool({
name: "create_support_ticket",
arguments: {
subject: "VPN keeps disconnecting",
priority: "high",
employeeId: "E-4821",
},
});
console.log(result.content);
await client.close();
}
main();
Por qué es importante conceptualmente
La idea central es el descubrimiento. El cliente llama a listTools() y recibe un catálogo legible por máquinas de todo lo que ofrece el servidor, con cada herramienta y su esquema correspondiente. Eso es lo que hace que MCP sea dinámico: un host impulsado por un LLM no necesita herramientas integradas en su prompt. Al establecer la conexión, pregunta al servidor qué puede hacer, y la respuesta se convierte en parte de lo que se le indica al modelo sobre sus posibilidades en esa conversación.
La gobernanza empresarial se basa exactamente en este mecanismo. Si una herramienta no debe estar disponible para un usuario o entorno específico, el control más eficaz es excluirla de lo que devuelve listTools(), en lugar de confiar en que el modelo decida no utilizarla.
6. Pasando de un prototipo local a una implementación empresarial
La configuración de stdio es adecuada para el aprendizaje y las herramientas de desarrollo locales, pero no se ajusta a la forma en que la mayoría de las empresas gestionan su infraestructura: alojada de forma centralizada, detrás de mecanismos de autenticación, con registro de actividades y accesible al mismo tiempo por muchas aplicaciones host. Ahí es donde entran en juego el transporte Streamable HTTP y una pasarela de API.
Aquí está el mismo servidor de servicio al cliente adaptado para funcionar mediante HTTP y detrás de una aplicación Express sencilla:
// src/httpServer.ts
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
const app = express();
app.use(express.json());
app.post("/mcp", async (req, res) => {
// In a real enterprise deployment, authentication middleware would
// run BEFORE this point - verifying a bearer token, checking scopes,
// and attaching the caller's identity to the request.
const server = buildHelpdeskServer(); // same registerTool calls as before
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined, // stateless mode: simplest to scale horizontally
});
res.on("close", () => transport.close());
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000, () => console.log("MCP server listening on :3000"));
El cambio significativo tiene que ver menos con el código y más con donde reside la responsabilidad. Tres aspectos que eran implícitos en stdio se convierten en consideraciones empresariales explícitas a través de HTTP.
- La autenticación se realiza antes del servidor, generalmente en un middleware o una pasarela, lo que permite al servidor asumir que
reqya contiene una identidad verificada. - La falta de estado es una decisión consciente. Con
sessionIdGenerator: undefinedel transporte no mantiene ninguna sesión por conexión, por lo que cualquier instancia detrás del balanceador de carga puede responder a cualquier solicitud, y se puede escalar como cualquier API sin estado. - La observabilidad deja de ser opcional. Cada llamada a una herramienta constituye una solicitud de red real, por lo que debe registrarse, rastrearse y limitarse en cuanto a frecuencia de la misma manera que cualquier llamada a una API interna.
7. Lista de verificación de consideraciones empresariales
Hacer que un servidor MCP funcione es solo la quinta parte sencilla del trabajo. Las cuatro quintas partes restantes consisten en garantizar su seguridad frente a sistemas de producción que albergan datos reales de empleados o clientes, y esa parte se presenta de la siguiente manera.
- Autenticación y autorización. Utilice OAuth2 u OIDC en la pasarela. Asocie la identidad del usuario que realiza la llamada o de la cuenta de servicio con permisos específicos y delimitados, de modo que no todas las herramientas estén disponibles para todos los usuarios.
- Diseño de herramientas con mínimo privilegio. Prefiera herramientas específicas como
get_ticket_statusen lugar de herramientas generales comorun_sql_query. Una herramienta que realiza una tarea bien definida es mucho más fácil de comprender y auditar.
8. Donde aparece esto en empresas reales
- TI y soporte interno. Ejemplo del servicio de atención al cliente: crear y consultar tickets, restablecer contraseñas, verificar el estado del sistema.
- Asistentes de ventas y CRM. Obtener el historial de cuentas y redactar correos de seguimiento basados en datos reales del CRM y no en suposiciones del modelo.
- Asistentes de datos y análisis. Un conjunto de herramientas de consulta de solo lectura y previamente aprobado para acceder a un almacén de datos, en lugar de SQL sin restricciones.
- Flujos de trabajo en el sector sanitario. Herramientas que buscan horarios de cita, verifican la elegibilidad del seguro o identifican deficiencias en la coordinación de la atención médica, siempre bajo un estricto control de acceso basado en roles y registros de auditoría, dada la sensibilidad de los datos. Aquí, los principios de uso de herramientas específicas, intervención humana y registro completo de auditorías del Apartado 7 suelen ser un requisito de cumplimiento.
- Herramientas para desarrolladores. Asistentes de IDE que consultan documentación interna, inician pipelines de CI o verifican quién está de guardia para un servicio.
Lo que tienen en común: MCP no hace que un modelo sea más inteligente. Lo que cambia es que la IA obtiene un acceso fundamentado y auditable a sistemas reales y ya no necesita inventar respuestas que suenen plausibles.
9. Errores comunes entre los principiantes
- Un servidor gigante que hace “de todo”. Dividido por sistema backend o dominio. Esto refleja buenas fronteras entre microservicios y mantiene el alcance de los efectos negativos reducido.
- Omitir los campos
description. El modelo depende en gran medida de las descripciones de herramientas y parámetros para decidir cuándo y cómo llamar a algo. Las descripciones vagas llevan al uso de la herramienta incorrecta o de la herramienta adecuada con argumentos equivocados. - Olvidar
isError. Una excepción bruta lanzada desde un manejador de herramientas puede interrumpir toda la conexión del cliente, cuando lo que debería ocurrir es informar al modelo de que hubo un fallo y que intente algo distinto. - Usar stdio en entornos de producción. Stdio es adecuado para el desarrollo local y los hosts de escritorio. Los entornos de producción multiinquilino requieren el transporte HTTP detrás de una pasarela real.
10. La versión breve
Una vez eliminados los términos técnicos, la idea central de MCP es sorprendentemente sencilla: un método compartido que permite a las aplicaciones de IA encontrar e invocar herramientas, obtener datos y reutilizar plantillas de prompts, lo que significa que el trabajo de integración realizado una sola vez sirve a todos los clientes que cumplan con los requisitos. Para las empresas, esa estandarización es lo que convierte a los agentes de IA de simples demostraciones llamativas en algo que puede ser gestionado, protegido y ejecutado en producción junto con todo lo demás.
Para quienes están comenzando, un enfoque sensato es:
- Construir un pequeño servidor MCP localmente mediante stdio, como en el ejemplo del servicio de atención al cliente.
- Agregar un cliente que invoque esas herramientas, de modo que todo el proceso sea visible.
- Coloque el servidor detrás de HTTP con autenticación o con una pasarela delante.
- Solo entonces recurra al registro de auditoría, a límites de velocidad y a la aprobación humana para cualquier acción destructiva.
Comience con algo pequeño y local, e incorpore las consideraciones empresariales una por una. Tratar de diseñar el servidor de producción perfecto desde el primer día es una forma mucho más arriesgada de lograrlo.
Leer más
- Notas prácticas: MCP para laboratorios de investigación: un contrato para herramientas, datos y — Guía paso a paso de las Notas prácticas: MCP para laboratorios de investigación: un contrato para herramientas, datos y: contratos, verificaciones y espacios de código listos para usar para los equipos que implementan este patrón.
- Notas prácticas: Protocolo de Contexto de Modelo (MCP) explicado: Guía para principiantes — Guía paso a paso de las Notas prácticas: Protocolo de Contexto de Modelo (MCP) explicado: Guía para principiantes: contratos, verificaciones y espacios para código reutilizable para los equipos que implementan este patrón.