Input schema, output schema y Zod: contratos claros para servidores MCP
Aprende a diseñar contratos útiles para tools MCP con `inputSchema`, `outputSchema`, Zod y anotaciones que ayuden al host sin convertir tu servidor en una caja negra difícil de usar.
Cuando un servidor MCP falla en uso real, muchas veces el problema no está en el transporte ni en el SDK, sino en el contrato. La tool existe, pero sus parámetros son ambiguos, su salida es imprevisible o sus anotaciones no ayudan a tomar decisiones.
En MCP, un schema no es burocracia. Es la forma de decirle al host y al modelo qué espera la operación, qué devuelve y qué comportamiento cabe esperar de ella.
Zod encaja especialmente bien en TypeScript porque permite definir validación y derivar la forma estructural del contrato en el mismo sitio donde desarrollas la lógica.
Un `inputSchema` útil no intenta cubrir todos los casos imaginables. Intenta reducir ambigüedad y evitar parámetros inventados, opcionales sin propósito o estructuras imposibles de explicar al modelo.
- Una buena tool se entiende antes de ejecutarse.
- Cuando el host descubre una tool, necesita algo más que un nombre. Necesita una descripción clara, un schema de entrada razonable y, si aplica, señales sobre si la operación es de solo lectura, destructiva o idempotente.
- Si el contrato es borroso, el modelo tendrá más margen para usar mal la herramienta: argumentos inventados, combinaciones absurdas o llamadas innecesarias.
- Por eso conviene diseñar el contrato antes de meterte en detalles de implementación.
- Cada parámetro debe tener una razón de existir.
Contrato primero
Una buena tool se entiende antes de ejecutarse.
Cuando el host descubre una tool, necesita algo más que un nombre. Necesita una descripción clara, un schema de entrada razonable y, si aplica, señales sobre si la operación es de solo lectura, destructiva o idempotente.
Si el contrato es borroso, el modelo tendrá más margen para usar mal la herramienta: argumentos inventados, combinaciones absurdas o llamadas innecesarias.
Por eso conviene diseñar el contrato antes de meterte en detalles de implementación.
Input schema
Cada parámetro debe tener una razón de existir.
En el SDK de TypeScript, una tool puede registrar `inputSchema` usando Zod. Ese paso no solo valida: también ayuda a describir la interfaz de la tool al cliente.
Un buen `inputSchema` suele ser pequeño, explícito y estable. Si una tool pide demasiados campos, muchas veces no está modelada al nivel correcto.
También conviene usar descripciones claras y evitar opcionales innecesarios. Si el parámetro no cambia la operación de forma real, probablemente sobra.
Output y respuesta
La salida debe ser útil para leer, validar y combinar.
Muchas tools principiantes devuelven solo texto libre. A veces basta, pero cuando el resultado va a reutilizarse, un `outputSchema` y una respuesta estructurada ahorran mucho dolor.
La idea no es volver rígida cada tool, sino hacer predecible lo importante: identificadores, estados, campos clave y errores comprensibles.
Una salida estructurada mejora tanto la depuración humana como la orquestación entre varias tools.
Annotations útiles
Las anotaciones no son seguridad, pero sí mejoran mucho la experiencia del cliente.
La especificación actual define hints como `readOnlyHint`, `destructiveHint`, `idempotentHint` y `openWorldHint`. Son pistas para el cliente sobre el comportamiento de la tool.
No deben tratarse como controles de seguridad, pero sí como una capa importante de claridad operativa y UX.
Una tool de consulta puede marcar `readOnlyHint: true`; una tool que crea registros quizá necesite `destructiveHint: false` y `idempotentHint: false` según su comportamiento.
Caso guiado
Imagina una tool llamada `create_note` que recibe diez campos opcionales y devuelve un texto genérico como 'hecho'. Ese contrato obliga al modelo a adivinar demasiado y al equipo a depurar a ciegas.
Ahora compárala con una versión que recibe `title` y `body`, devuelve `noteId`, `title` y `createdAt`, y además marca bien si es destructiva o no. La segunda no es solo más elegante: es más usable, más verificable y más mantenible.
Ese es el cambio de nivel que buscamos en MCP: contratos que ayudan a que el servidor trabaje con el modelo, no contra él.
Práctica
Diseña una tool de ejemplo con `inputSchema` breve, una salida estructurada mínima y una anotación coherente. La evidencia de logro observable es que otra persona pueda explicar la tool sin leer tu implementación interna.
El criterio de corrección es claro: nombre específico, inputs justificables, salida útil y ausencia de parámetros decorativos.