← SCRAM AI Lab
Stdio sigue siendo la mejor opción para MCPs propios. HTTP solo si necesitas multi-cliente o auth. Una herramienta, un caso de uso atómico, schema Zod estricto.
May 21, 2026
9 lecturas
Cuando empiezas con MCP, la documentación oficial te empuja a HTTP/SSE como si fuera lo moderno. Para un MCP propio que vas a usar tú o tu equipo desde Claude Code, stdio es superior: arranca instantáneo (sin servidor escuchando), no expone puertos, hereda el entorno del proceso padre (variables, credenciales del shell), y debugear es console.error que aparece en los logs de Claude. HTTP tiene sentido en exactamente dos escenarios: (a) varios clientes consumen el mismo MCP simultáneamente, o (b) necesitas autenticación OAuth con flujo de redirect. Para todo lo demás, stdio.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
const server = new Server(
{ name: "scram-erp-mcp", version: "0.3.1" },
{ capabilities: { tools: {} } }
);
const QueryClienteSchema = z.object({
rfc: z.string().regex(/^[A-Z&Ñ]{3,4}\d{6}[A-Z0-9]{3}$/),
});
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: "lookup_cliente_by_rfc",
description: "Busca un cliente del ERP por RFC. Devuelve nombre, status, último pedido. Use cuando el usuario mencione un RFC mexicano.",
inputSchema: { type: "object", properties: { rfc: { type: "string" } }, required: ["rfc"] }
}]
}));
server.setRequestHandler(CallToolRequestSchema, async (req) => {
if (req.params.name !== "lookup_cliente_by_rfc") {
throw new Error("Unknown tool: " + req.params.name);
}
const { rfc } = QueryClienteSchema.parse(req.params.arguments);
const cliente = await fetchClienteFromERP(rfc);
return { content: [{ type: "text", text: JSON.stringify(cliente, null, 2) }] };
});
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("scram-erp-mcp ready");
La tentación es exponer query_erp con un parámetro action que multiplexa todo. No lo hagas. El modelo elige herramientas por nombre y descripción; si las colapsas en una sola, el clasificador pierde resolución y vas a debugear por qué Claude invoca acciones equivocadas. Mejor cinco herramientas con nombres explícitos: lookup_cliente_by_rfc, list_pedidos_pendientes, get_inventario_sku, create_cotizacion, find_factura_by_folio. Cada una con su schema Zod.
Los errores genéricos rompen al modelo. Si tu MCP responde "Internal server error" cuando un RFC no existe, Claude no sabe si reintentar, pedir aclaración o rendirse. Devuelve errores estructurados con intención:
return {
content: [{
type: "text",
text: JSON.stringify({
error: "cliente_not_found",
rfc: rfc,
hint: "Verifica el RFC. Si el cliente es nuevo, usa create_cliente primero."
})
}],
isError: true
};
El campo hint es oro: le dice al modelo qué hacer después sin que tengas que entrenarlo en el system prompt.
Loguea a stderr (stdout es para el protocolo MCP): timestamp, nombre de herramienta, latencia, código de salida. En producción enchúfalo a Loki. Sin esto, cuando alguien diga "el MCP está lento" no vas a tener cómo distinguir si el problema es tu MCP, el ERP, el modelo o la red.
fetch sin AbortController con timeout de 5-10s te deja MCPs colgados y conversaciones muertas.Publica tu MCP cuando funcione, no cuando esté perfecto. La primera versión que uses tres días seguidos te va a enseñar más sobre el diseño que dos semanas planeándolo. ¿Qué herramienta de tu día a día te ahorraría más tiempo si Claude pudiera invocarla?
Artículos relacionados
Multiagent en CC v2.1.130: lead delega a specialists
El patrón donde un lead agent delega a specialists usando el filesystem como bus de comunicación. Funciona cuando coordinar tres specialists cuesta menos que hacerlo serial.
Hooks: el patrón que sustituye 80% de validaciones manuales
PreToolUse y PostToolUse son el lugar correcto para bloquear commits a main, formatear código, ejecutar tests y validar comandos peligrosos. Sin pedirle permiso al modelo.
MCPs propios: cuándo construir vs adoptar
Adopta cuando hay un MCP mantenido por gente seria. Construye cuando tu lógica de negocio, credenciales o latencia no toleran un intermediario genérico.