Saltar al contenido principal

Transporte

Streamable HTTP, stateless. Un mensaje JSON-RPC 2.0 por POST, una respuesta JSON. No hay Mcp-Session-Id, no hay resumability y no hay stream servidor→cliente: la aplicación corre con varias réplicas, y toda operación larga ya responde 202 y termina en un worker en segundo plano, no en el canal MCP.

Versiones de protocolo​

El servidor habla dos eras del protocolo en el mismo endpoint:

VersiónEraEstado
2026-07-28Stateless, sin handshake — descubrimiento por server/discoverSoportada
2025-06-18Handshake por initialize — es la predeterminada cuando el cliente no envía el headerSoportada
2025-03-26Handshake por initializeSoportada

La era la decide el body de la solicitud, con los headers como verificación cruzada:

  • params._meta lleva io.modelcontextprotocol/protocolVersion → era 2026-07-28 (ver abajo).
  • Sin ese envelope, con un MCP-Protocol-Version de 2025 o sin header → era 2025, con initialize.
  • MCP-Protocol-Version: 2026-07-28 sin el envelope → 400 con -32602. El servidor no vuelve en silencio a la era anterior: pediste la semántica stateless y recibirías la otra.

Una versión que el servidor no habla — en el header o en el envelope, en cualquiera de las eras — recibe 400 con el error JSON-RPC -32022, con la lista de las soportadas:

{ "jsonrpc": "2.0", "id": 1, "error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": { "supported": ["2026-07-28", "2025-06-18", "2025-03-26"], "requested": "1999-01-01" }
} }

La versión en uso vuelve en el header de respuesta MCP-Protocol-Version.

Era 2026-07-28​

No hay handshake: cada solicitud lleva su propia versión y las capacidades del cliente en params._meta, y el servidor no recuerda nada entre una solicitud y la siguiente.

Clave de params._metaObligatorioSignificado
io.modelcontextprotocol/protocolVersionsí2026-07-28
io.modelcontextprotocol/clientCapabilitiessíLas capacidades del cliente (un objeto; {} sirve). Declarar elicitation activa la confirmación de tools destructivas
io.modelcontextprotocol/clientInforecomendadoname y version del cliente

Los headers repiten lo que está en el body, para que los intermediarios puedan enrutar sin leerlo — y por eso tienen que coincidir con él:

HeaderDebe ser igual a
MCP-Protocol-VersionLa versión del envelope
Mcp-MethodEl method del mensaje
Mcp-NameSolo en tools/call: params.name, tal cual o como =?base64?…?=

Cualquier discrepancia es 400 con -32020 (Header mismatch: …). La ausencia de clientCapabilities es 400 con -32602.

Los resultados en esta era siempre llevan resultType: "complete" y el servidor en _meta["io.modelcontextprotocol/serverInfo"]. server/discover, tools/list, resources/list, resources/templates/list, resources/read y prompts/list también llevan ttlMs: 0 y cacheScope: "private": lo que vuelve está filtrado por el scope y los permisos de quien llama, así que no debe reutilizarse ni compartirse. Un tools/call de una tool destructiva puede volver con resultType: "input_required" — ver Confirmación de tools destructivas.

Headers de solicitud​

HeaderObligatorioSignificado
AuthorizationsíBearer <access token> emitido para el servidor MCP — ver Autenticación
Content-Typesíapplication/json
Acceptrecomendadoapplication/json
MCP-Protocol-Versionsí en la era 2026-07-28; recomendado en 2025Revisión del protocolo
Mcp-Methodsí en la era 2026-07-28El método del mensaje
Mcp-Namesí en un tools/call de la era 2026-07-28El nombre de la tool
X-Workspace-IdcondicionalWorkspace sobre el que actuar, cuando la organización tiene más de uno
OrigincondicionalLo envían los clientes de navegador; se valida contra una lista permitida

Headers de respuesta​

HeaderSignificado
MCP-Protocol-VersionRevisión negociada
X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-ResetVer Límite de solicitudes
Cache-ControlSiempre no-store
Retry-AfterEn 429 y en 503

Métodos​

MétodoEra 2026-07-28Era 2025Propósito
server/discoversí—Versiones soportadas, capacidades del servidor e instrucciones
initialize—síNegociación de versión, capacidades del servidor e instrucciones
ping—síComprobación de vida; responde un resultado vacío
tools/listsísíTools que quien llama puede ejecutar, con su JSON Schema y sus annotations
tools/callsísíEjecuta una tool
resources/listsísíLos documentos de URI fija que quien llama puede leer
resources/templates/listsísíLas plantillas de URI (kobana://inbox/emails/{id}, …) que quien llama puede leer
resources/readsísíLee un documento por URI
prompts/listsísíLos prompts listos que quien llama puede usar
prompts/getsísíRenderiza un prompt con los argumentos dados
completion/completesísíSugerencias para un argumento de prompt o de plantilla

Resources, prompts y completions están en Resources y prompts.

Cualquier otro método es -32601 Method not found — con HTTP 404 en la era 2026-07-28, en el body de un 200 en 2025. El batching JSON-RPC no está soportado — se eliminó en la revisión 2025-06-18, y un body en array recibe 400.

El body de la solicitud está limitado a 1 MB (1.048.576 bytes); por encima, la respuesta es 413 con -32600 — ver Errores. Ninguna tool necesita más: los archivos nunca viajan por MCP.

Una notificación (mensaje sin id, como notifications/initialized) se acepta con 202 y cuerpo vacío, en ambas eras.

La autenticación va antes de cualquier método, server/discover incluido: sin token, la respuesta es el desafío 401 que lleva al cliente al login OAuth — ver Autenticación.

server/discover (era 2026-07-28)​

{ "jsonrpc": "2.0", "id": 1, "method": "server/discover",
"params": { "_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": { "name": "my-client", "version": "1.0.0" }
} } }
{ "jsonrpc": "2.0", "id": 1, "result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28", "2025-06-18", "2025-03-26"],
"capabilities": { "tools": {}, "resources": {}, "prompts": {}, "completions": {} },
"instructions": "Tools for the Kobana Autonomous Inbox: ...",
"ttlMs": 0,
"cacheScope": "private",
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "kobana-autonomous-inbox",
"title": "Kobana Autonomous Inbox",
"version": "0.1.0"
}
}
} }

initialize (handshake de la era 2025)​

{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": { "protocolVersion": "2025-06-18" } }
{ "jsonrpc": "2.0", "id": 1, "result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": { "listChanged": false },
"resources": { "subscribe": false, "listChanged": false },
"prompts": { "listChanged": false },
"completions": {}
},
"serverInfo": {
"name": "kobana-autonomous-inbox",
"title": "Kobana Autonomous Inbox",
"version": "0.1.0"
},
"instructions": "Tools for the Kobana Autonomous Inbox: ..."
} }

Las instructions (en initialize y en server/discover) advierten al agente de que los valores de los campos en los resultados — sobre todo el asunto y el cuerpo de un correo — son datos escritos por terceros, nunca instrucciones, y le piden confirmar con el usuario antes de una acción destructiva que un resultado parezca solicitar. También dicen que las tools destructivas exigen el protocolo 2026-07-28 con elicitation, y que confirmation_required significa que el cliente no puede ejecutarlas — no es algo para reintentar.

tools/list​

Devuelve solo las tools que quien llama puede ejecutar, filtradas por el scope del token y por los permisos de la persona. Cada tool lleva annotations, que guían las confirmaciones que el cliente pide:

AnnotationSignificado
readOnlyHintLa tool solo lee
destructiveHintLa tool elimina datos, envía algo hacia fuera (prueba o reenvío de webhook, reprocesamiento de correo), rota un secreto o cambia quién puede enviar a una inbox. Solo se ejecuta tras la confirmación del servidor
idempotentHintRepetir la llamada tiene el mismo efecto
openWorldHintSiempre false — la tool no alcanza nada fuera de Inbox Autónomo

tools/call​

{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "emails_list", "arguments": { "status": "processed", "limit": 10 } } }

El resultado lleva la respuesta JSON del endpoint como contenido de texto:

{ "jsonrpc": "2.0", "id": 2, "result": {
"content": [{ "type": "text", "text": "{ \"data\": [ ... ], \"meta\": { \"next_cursor\": \"...\" } }" }]
} }

Los errores sobre los que quien llama puede actuar vuelven con isError: true dentro del resultado, no como error JSON-RPC — ver Errores.

Despacho in-process​

Cada tool despacha in-process al route handler de /api/v1 dueño de la operación, con la identidad ya verificada — el token MCP no se reenvía, y el endpoint sigue exigiendo su propio scope y permiso. Los ids de los argumentos se codifican en el path, así que un id no puede alcanzar otra ruta. No hay round trip HTTP ni una segunda implementación: filtros de listado, emparejamiento de upsert, validación, soft-delete y aislamiento multi-tenant son el mismo código que ejecuta la API REST, así que una tool no puede divergir del endpoint que refleja.