# MCP

> Conecta un cliente MCP al servidor MCP de Probara.

Probara expone un servidor **Model Context Protocol (MCP)** en:

```
https://app.probara.net/mcp
```

Cualquier cliente compatible con MCP (un asistente de IA o un IDE) puede conectarse a este endpoint para llamar a las herramientas de gestión de pruebas de Probara — proyectos, suites, casos de prueba, ejecuciones, defectos y más. Consulta la [referencia de herramientas MCP](https://docs.probara.net/es/developers/mcp-tools/) para ver la lista completa y generada de todas las herramientas disponibles.

## Autenticación

`/mcp` acepta cualquiera de los dos tipos de credencial como Bearer — consulta [Autenticación API](https://docs.probara.net/es/developers/authentication/) para la comparación completa:

- **OAuth 2.1** (recomendado para clientes interactivos como Claude.ai, Claude Code, Cursor, ChatGPT) — el cliente descubre el servidor, se registra a sí mismo y una persona aprueba el acceso mediante una pantalla de consentimiento. No hay que copiar/pegar ningún secreto.
- **Token API** (recomendado para scripts e integraciones sin interfaz) — un token de larga duración `probara_...` creado en **Menú del avatar → Tokens de API** (`/user/api-tokens`), pegado directamente en el campo Bearer/Authorization del cliente.

Un [token de aplicación](https://docs.probara.net/es/developers/authentication/#tokens-de-aplicación) (`probara_app_...`, desde **Workspace → Integraciones**) no es ninguno de los dos: solo envía resultados desde CI, y `/mcp` le responde `403 forbidden`.

Una petición a `/mcp` sin credencial devuelve `401` con una cabecera `WWW-Authenticate: Bearer resource_metadata="https://app.probara.net/.well-known/oauth-protected-resource"` que apunta al descubrimiento del cliente.

Una credencial que el servidor no acepta (desconocida, revocada, caducada o emitida para otro recurso) también devuelve `401`, con `error="invalid_token"` en esa cabecera. Entonces, un cliente OAuth renueva su token o vuelve a autorizarse.

## Claude.ai (conector personalizado)

1. Abre **Settings → Connectors → Add custom connector**.
2. Introduce la URL del servidor: `https://app.probara.net/mcp`.
3. Claude.ai descubre automáticamente los metadatos de OAuth, se registra a sí mismo (Dynamic Client Registration) y te redirige a la pantalla de consentimiento de Probara.
4. Elige la organización a la que vincular la conexión y aprueba. Claude.ai ahora tiene una concesión OAuth limitada a esa organización.

## Claude Code

1. Añade el servidor: `claude mcp add --transport http probara https://app.probara.net/mcp`.
2. Claude Code abre una ventana del navegador para el flujo de autorización/consentimiento de OAuth (mismo descubrimiento + DCR que Claude.ai).
3. Aprueba los scopes negociados y elige una organización. Si el cliente omite `scope` o envía un valor que Probara no reconoce, se aplica por defecto el conjunto completo soportado (`mcp:read mcp:write`); consulta [Scopes](https://docs.probara.net/es/developers/authentication/#scopes) para las reglas exactas de negociación.
4. Verifica la conexión: `claude mcp list` debería mostrar `probara` como conectado.

## Cursor

1. Abre **Settings → MCP → Add new MCP server**.
2. Elige el transporte **HTTP** y define la URL como `https://app.probara.net/mcp`.
3. Cursor sigue el mismo flujo de descubrimiento OAuth/DCR/consentimiento; alternativamente, pega un token API en el campo de cabecera Bearer/Authorization del conector si tu versión de Cursor aún no soporta MCP OAuth.

## ChatGPT

1. Abre **Settings → Connectors → Add MCP server** (Developer Mode / conectores personalizados).
2. Define la URL del servidor como `https://app.probara.net/mcp`.
3. Completa el flujo de consentimiento OAuth, o proporciona un token API como cabecera Bearer si tu plan de ChatGPT solo soporta conectores de cabecera estática.

## Protocolo

El endpoint sirve dos revisiones del protocolo MCP. La revisión que negocia cada cliente determina la forma de sus respuestas. Todas las peticiones son `POST`: el servidor no mantiene un stream propio, así que `GET` y `DELETE` sobre `/mcp` responden `405`.

- Las **revisiones de 2025**, como `2025-11-25`, se atienden sin estado, y cada respuesta va en formato Server-Sent Events (`text/event-stream`).
- Los clientes de **`2026-07-28`** reciben un cuerpo JSON por petición y descubren el servidor con `server/discover`. Cada una de sus peticiones lleva las cabeceras `MCP-Protocol-Version` y `Mcp-Method`, y `tools/call`, `prompts/get` y `resources/read` llevan además `Mcp-Name` con el nombre de la herramienta, del prompt o la URI del recurso. Las cabeceras deben coincidir con el cuerpo: una petición con una cabecera ausente o que no coincide se rechaza con HTTP `400` y el error JSON-RPC `-32020`.

Las respuestas a `tools/list`, `prompts/list`, `resources/list`, `resources/templates/list` y `server/discover` de los clientes `2026-07-28` incluyen `ttlMs: 300000` y `cacheScope: "private"`. Un cliente puede reutilizar una de estas listas durante cinco minutos, y no debe compartirla entre usuarios. Las respuestas de 2025 no incluyen ninguno de los dos campos.

Llamar a una herramienta que no existe devuelve el error JSON-RPC `-32602` (`Tool <nombre> not found`), no un resultado de herramienta. Una herramienta que existe y falla devuelve un resultado con `isError: true`.

El cuerpo de una petición está limitado a unos 43,7 MiB (45.787.820 bytes), lo justo para un adjunto de 32 MiB en base64 con el sobre JSON-RPC. Un cuerpo mayor se rechaza con `413`.

`/mcp` responde solo para `app.probara.net`. Una petición dirigida a otro host, como una dirección `*.workers.dev`, se rechaza con `403`. Un `Origin` del navegador debe nombrar el mismo host. Una petición sin `Origin`, como la de un cliente de servidor, no se ve afectada por esa comprobación.

## Herramientas principales

Nueve herramientas cubren el trabajo habitual con pocas llamadas. Cada otra operación se usa con las cinco herramientas que también incluye una lista predeterminada, descritas en Operaciones y herramientas de ejecución más abajo.

| Herramienta           | Qué hace                                                                                                                                      |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_project_context` | Devuelve en una llamada las suites, los campos personalizados, las configuraciones, los hitos, los entornos y los miembros de un proyecto.    |
| `get`                 | Lee cualquier entidad por su ID visible o su ULID. Con un ULID hay que indicar también `kind`.                                                |
| `query`               | Ejecuta una consulta PQL.                                                                                                                     |
| `query_help`          | Lista los campos, operadores y valores PQL de cada entidad, con ejemplos que funcionan.                                                       |
| `analyze_run`         | Agrupa los casos fallidos y bloqueados de una ejecución por defecto vinculado, y después por suite, con sus intentos.                         |
| `upsert_test_cases`   | Crea o actualiza hasta 50 casos de prueba. Cada elemento indica un ID visible o una clave de automatización e informa de su propio resultado. |
| `start_run`           | Inicia una ejecución desde una suite, un plan de pruebas, una consulta PQL o una lista de casos, con sus configuraciones y asignaciones.      |
| `record_results`      | Registra hasta 50 resultados en una ejecución por ID visible del caso de prueba, con resultados de pasos y adjuntos de evidencia.             |
| `file_defect`         | Registra un defecto a partir de un resultado y puede crear también su incidencia de GitHub o Jira.                                            |

`upsert_test_cases` asocia cada elemento a un caso de prueba por su ID visible o su clave de automatización. Un elemento con un ID visible que no existe falla, porque el servidor asigna los IDs visibles. Una clave de automatización que no coincide con ningún caso crea uno. Enviar el mismo lote otra vez no cambia nada e informa de cada elemento como `unchanged`. Si un elemento falla, los demás siguen.

## Prompts y recursos

Un cliente también puede ofrecer prompts y recursos junto a las herramientas. Cada uno llega a los mismos datos que una herramienta, así que nada es accesible solo a través de ellos.

Tres prompts inician una tarea habitual. Cada uno responde con un mensaje que nombra las herramientas que hay que ejecutar, en orden:

| Prompt                  | Argumentos                                                                                                           | Herramientas que nombra                                                                                 |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `test_cases_from_issue` | `project_id` y `issue`: una URL de incidencia de GitHub, `owner/repo#n` o una clave de incidencia de Jira            | `run_read_operation` para leer la incidencia, después `get_project_context` y luego `upsert_test_cases` |
| `triage_run`            | `project_id` y `run`: un ID visible como `R-12`, o un ULID                                                           | `analyze_run`, después `get` y luego `file_defect`                                                      |
| `regression_for_pr`     | `project_id`, `pull_request` (una URL de pull request de GitHub o `owner/repo#n`) y `changed_areas`, que es opcional | `query_help` y `query` para encontrar los casos, después `start_run`                                    |

Probara no lee el diff de un pull request, así que `changed_areas` define el alcance de una ejecución de regresión.

Dos recursos contienen el mismo JSON que sus herramientas:

| Recurso               | URI                                                                             | Misma respuesta que   |
| --------------------- | ------------------------------------------------------------------------------- | --------------------- |
| Esquema PQL           | `probara://pql/schema`                                                          | `query_help`          |
| Contexto del proyecto | `probara://projects/{project}/context`, con el código del proyecto, como `SHOP` | `get_project_context` |

Leer un recurso sigue el mismo camino que su herramienta: un proyecto desconocido responde con el mensaje de la herramienta como error JSON-RPC, con la URI en sus datos. Un recurso no tiene bloque para la nota de datos no confiables, así que la descripción de cada recurso indica que su JSON contiene datos de la organización.

Los recursos necesitan el alcance `mcp:read`. Cada prompt termina en una herramienta de escritura, así que los prompts necesitan `mcp:read` y `mcp:write`. Una concesión sin el alcance no lista ninguno, y una petición se rechaza con `403` y el desafío `insufficient_scope`, como ocurre con una herramienta oculta.

## Operaciones y herramientas de ejecución

Una lista predeterminada incluye las nueve herramientas principales y otras cinco, así que un agente ve hasta 14 herramientas al conectarse, y menos con una concesión más acotada. El resto de las operaciones está en la [referencia de herramientas](https://docs.probara.net/es/developers/mcp-tools/), y cada una se usa en tres pasos:

1. `search_operations` busca operaciones por palabra clave, como `proyecto` o `resultado de ejecución`. Cada resultado da el nombre de la operación, un resumen de una línea y la herramienta de ejecución que la ejecuta.
2. `describe_operation` devuelve la descripción completa de la operación, el esquema JSON de sus entradas, sus anotaciones y su esquema de salida cuando lo declara.
3. `run_read_operation`, `run_write_operation` o `run_delete_operation` la ejecuta. Pasa el nombre de la operación como `operation` y sus entradas como `arguments`. El resultado es el de la propia operación.

Las tres herramientas de ejecución se reparten por riesgo. `run_read_operation` ejecuta operaciones de solo lectura, `run_write_operation` ejecuta escrituras que no eliminan nada y `run_delete_operation` ejecuta operaciones destructivas, como los borrados. Una herramienta de ejecución rechaza una operación de otro riesgo, y su error indica la herramienta que debe usarse. Un nombre desconocido responde con los nombres más parecidos.

Llamar una operación por su nombre directamente, como `create_project`, devuelve un error de herramienta que indica su herramienta de ejecución. Solo las nueve herramientas principales se llaman directamente.

Toda herramienta rechaza un argumento que no recibe: la llamada devuelve un error de herramienta que nombra ese argumento, y no se ejecuta nada. A través de una herramienta de ejecución, el error también lista los argumentos de la operación y marca los obligatorios. Lo mismo vale para una clave dentro de un elemento de `record_results` o `upsert_test_cases`, o dentro de una entrada de `caseAssignees` de `start_run`: un `notes` mal escrito rechaza toda la llamada en vez de registrar el resultado sin él.

### Qué lista una concesión de solo lectura

Una concesión OAuth sin `mcp:write` lista las cinco herramientas principales de lectura y tres herramientas que buscan y leen operaciones: `search_operations`, `describe_operation` y `run_read_operation`. No lista ninguna herramienta de escritura, y la búsqueda devuelve solo operaciones de lectura. Una llamada de escritura desde esa concesión se rechaza con `403` y el desafío `insufficient_scope` que pide `mcp:write`, como antes. Una concesión OAuth que solo tiene `mcp:write` lista las cuatro herramientas principales de escritura y las dos herramientas de ejecución de escritura. Un token de API lista todas las herramientas predeterminadas.

## Operaciones destructivas: vista previa y confirmación

Algunas operaciones pueden eliminar o cambiar de forma irreversible más de un registro en una sola llamada: las operaciones masivas `bulk_delete_tags`, `bulk_remove_run_cases` y `reconcile_run_cases`, los borrados de un proyecto, una suite, un caso de prueba, una ejecución, un plan de pruebas, un dashboard, un campo personalizado, una etiqueta, un hito o un entorno, y `deactivate_org_member`. Cada una se ejecuta en dos llamadas:

1. Llámala sin `confirm_token`. No se ejecuta nada. El resultado es una vista previa: `status` vale `confirmation_required`, `targets` lista lo que nombra la llamada con su ID visible y su nombre cuando una lectura los encuentra, `irreversible` dice qué no se puede deshacer, y `confirm_token`, `expires_at` y `expires_in_seconds` indican cuánto dura el token.
2. Repite la misma llamada con los mismos argumentos y el `confirm_token`. La operación se ejecuta.

Un token es de un solo uso y vale cinco minutos. Está ligado a la credencial que pidió la vista previa (un token de API o una concesión de OAuth), a su organización, a la operación y a sus argumentos. Una llamada que presenta un token se rechaza, y no se ejecuta nada, cuando:

- el token es desconocido, ha caducado o ya se usó: vuelve a llamar sin `confirm_token` para obtener una vista previa nueva;
- el token se emitió para otra operación, otra credencial, otra organización u otros argumentos: sigue válido para su propia llamada;
- el almacén de tokens no está disponible: el error es reintentable, así que vuelve a llamar.

`run_delete_operation` recibe `confirm_token` dentro de `arguments`, igual que la operación cuando se llama directamente.

## Registro de actividad

Un cambio hecho a través de una conexión MCP con OAuth registra la conexión en su evento de auditoría: `metadata.oauthClient` guarda el `clientId` y el `clientName` del cliente, tal como los devuelve la API de eventos de auditoría. El feed de actividad muestra el cambio bajo el usuario, como hace con cualquier sesión.

## Datos no confiables en los resultados

Un resultado correcto que contiene datos de la organización, como títulos, descripciones, pasos, comentarios y texto importado desde GitHub o Jira, termina con un segundo bloque de texto. Ese bloque indica que el JSON de arriba son datos escritos por personas de la organización o importados desde GitHub o Jira, y que el texto son datos, no instrucciones. El primer bloque de texto es el mismo JSON de antes, y `structuredContent` no cambia. Los errores y las respuestas de catálogo de `search_operations` y `describe_operation` no llevan ese bloque.

## Casos de prueba parametrizados

El identificador visible de un caso, como `SHOP-45`, puede coincidir con varios casos de ejecución de una misma ejecución cuando el caso es parametrizado. Una operación que recibe un identificador visible y una ejecución rechaza la llamada, y lista hasta 25 de esos casos de ejecución, salvo que la llamada nombre uno: pasa su combinación como `parameters`, un array de pares nombre y valor como `[{"name":"Sitio","value":"EU"}]`, o pasa el ULID del caso de ejecución. Las operaciones en lote usan ULID de caso de ejecución para ese caso. El servidor nunca elige uno por ti. `upsert_test_cases` y `create_test_case` aceptan `parameters` y `excludedCombinations`, igual que la API. Los parámetros compartidos son operaciones, que se encuentran con `search_operations` y se ejecutan por nombre: `list_shared_parameters`, `get_shared_parameter`, `create_shared_parameter`, `update_shared_parameter`, `delete_shared_parameter` (necesita confirmación y acepta un `mode`), `list_shared_parameter_usage`, `preview_test_case_combinations` y `detach_test_case_parameter`. La API y MCP aplican la misma regla. Consulta [Casos de prueba parametrizados](https://docs.probara.net/es/guides/parameterized-test-cases/).

## Identificadores

Cada argumento que recibe una entidad acepta su ULID o su ID visible, y el servidor busca el ID visible por ti.

- Un caso de prueba (`SHOP-45`) y una suite (`SHOP-S3`) llevan el código de su proyecto, así que no necesitan `project_id`.
- Una ejecución (`R-12`), un hito (`M-5`), un defecto (`D-7`), un plan de pruebas (`PLAN-3`), un paso compartido (`SS-2`) y una revisión (`RV-4`) se numeran dentro de cada proyecto. Envía `project_id` con ellos.
- Un caso de ejecución es un caso de prueba dentro de una ejecución. Las herramientas de caso de ejecución reciben el ID visible del caso de prueba junto con `run_ulid`. Las herramientas masivas de ejecución también reciben el ULID del caso de prueba.

Un ID visible que no existe responde con un error que lo nombra junto con el proyecto. Un código de proyecto que no existe responde con los códigos de proyecto válidos.

## Anotaciones de las herramientas

Cada herramienta declara qué hace, para que un cliente que respeta esa declaración pueda pedir confirmación al usuario antes de una llamada arriesgada. Son indicaciones: el servidor nunca rechaza una llamada por ellas.

- **Solo lectura**: la herramienta solo lee datos.
- **Destructiva**: la herramienta elimina datos, o reemplaza en una sola llamada una lista, un documento o una credencial completa. Las herramientas de reemplazo y de conciliación reciben el conjunto completo que quieres, así que lo que omitas se elimina.
- **Idempotente**: repetir la misma llamada no tiene más efectos, así que reintentar una es seguro.
- **Sistemas externos**: la herramienta llega fuera de Probara: una escritura en GitHub o Jira, el lanzamiento de un flujo de trabajo de GitHub, una entrega a un webhook o un correo de invitación.

La [referencia de herramientas MCP](https://docs.probara.net/es/developers/mcp-tools/) lista las indicaciones de cada herramienta. Al conectarse, el servidor también envía un resumen breve del modelo de datos y de los identificadores de Probara, que muchos clientes añaden al contexto del modelo.

## Tamaño de las respuestas

Una herramienta de listado devuelve una página por llamada. La [referencia de herramientas MCP](https://docs.probara.net/es/developers/mcp-tools/) indica el tamaño de página por defecto de cada herramienta y el argumento que lo cambia. La página más grande tiene 200 elementos.

Una página que aun así es demasiado grande para una respuesta (unos 10.000 tokens) se trata de una de estas dos formas:

- **Los listados que continúan con `nextCursor`** se recortan a los elementos que caben. El resultado incluye un objeto `truncation`: `returned` es el número de elementos que trae y `pageItems` el número que tiene la página. Su `nextCursor` apunta al último elemento que trae, así que la siguiente llamada devuelve el resto, sin huecos.
- **Los listados que se recorren con `page`** se rechazan con `response_too_large` y no se devuelve nada. El mensaje indica el `pageSize` que cabe; recorre el listado con ese tamaño.

`get`, `list_results` y `list_run_cases` también reciben `fields`, una lista con los nombres de los campos que se devuelven. `query` no lo recibe: la cláusula `SELECT` de la consulta indica sus columnas. El ID visible y el ULID se devuelven siempre. Un nombre desconocido se rechaza con `fields_invalid`, y el mensaje lista los nombres válidos.

Un registro único, o un listado sin argumento de paginación, se devuelve completo hasta unos 25.000 tokens. Si es mayor, se rechaza con `response_too_large`. El mensaje indica un filtro que añadir o una vista más reducida que pedir, o dice que la herramienta no tiene ninguna.

## Solución de problemas

| Síntoma                                                                    | Causa probable                                                                                                                                                                                                                                       |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401` inmediato, sin ventana del navegador                                 | El cliente no soporta el descubrimiento OAuth de MCP — usa un token API en su lugar                                                                                                                                                                  |
| La pantalla de consentimiento muestra la organización equivocada           | Elige otra organización en el selector de la pantalla de consentimiento antes de aprobar; cada concesión se vincula a exactamente una organización                                                                                                   |
| Una llamada a herramienta devuelve `403` con `insufficient_scope`          | La concesión OAuth no tiene el scope que la llamada necesita (`mcp:read` para leer, `mcp:write` para cambiar). Vuelve a autorizar para obtenerlo.                                                                                                    |
| Una llamada a herramienta falla con `forbidden` y nombra el scope y tu rol | Tu rol en esa organización ya no permite el scope, aunque la concesión lo tenga. Volver a autorizar no cambia esto: un propietario o administrador de la organización debe cambiar tu rol. Consulta [Autenticación](https://docs.probara.net/es/developers/authentication/). |
| `503` con una cabecera `Retry-After`                                       | Probara no pudo comprobar la credencial por un fallo temporal — espera los segundos de `Retry-After` y reintenta                                                                                                                                     |
| `429` con una cabecera `Retry-After`                                       | Se alcanzó el límite de tasa por token o por organización — espera los segundos de `Retry-After` y reintenta                                                                                                                                         |
| `403` antes de ejecutar una herramienta                                    | El cliente llama a `/mcp` en un host distinto de `app.probara.net`, o envía un `Origin` ajeno. Apúntalo a `https://app.probara.net/mcp`.                                                                                                             |
| `413` en una llamada a herramienta                                         | El cuerpo de la petición supera el límite de 43,7 MiB. Los adjuntos admiten hasta 32 MiB; envía un archivo más pequeño.                                                                                                                              |
| JSON-RPC `-32602`, `Tool … not found`                                      | El nombre de la herramienta no está en la lista que tiene el cliente. Vuelve a cargar la lista de herramientas; la lista guardada en caché dura hasta cinco minutos.                                                                                 |
| `response_too_large` en un resultado de herramienta                        | El resultado es demasiado grande para una respuesta. El mensaje indica el tamaño de página que hay que pedir, un filtro que añadir o una vista más reducida. Si no indica ninguno, la herramienta no tiene una forma menor de ese registro.          |
