Skip to content

MCP

Probara exposes a Model Context Protocol (MCP) server at:

https://app.probara.net/mcp

Any MCP-compatible client (an AI assistant or IDE) can connect to this endpoint to call Probara’s test-management tools — projects, suites, test cases, runs, defects, and more. See the MCP tool reference for the full, generated list of every available tool.

/mcp accepts either credential type as a Bearer token — see API authentication for the full comparison:

  • OAuth 2.1 (recommended for interactive clients like Claude.ai, Claude Code, Cursor, ChatGPT) — the client discovers the server, registers itself, and a human approves access via a consent screen. No secret to copy/paste.
  • API token (recommended for scripts and headless integrations) — a long-lived probara_... token created in Avatar menu → API tokens (/user/api-tokens), pasted directly into the client’s Bearer/Authorization field.

An app token (probara_app_..., from Workspace → Integrations) is not one of them: it only reports results from CI, and /mcp answers it 403 forbidden.

A /mcp request without a credential returns 401 with a WWW-Authenticate: Bearer resource_metadata="https://app.probara.net/.well-known/oauth-protected-resource" header pointing the client at discovery.

A credential the server does not accept (unknown, revoked, expired, or issued for another resource) also returns 401, with error="invalid_token" in that header. An OAuth client then refreshes its token or authorizes again.

  1. Open Settings → Connectors → Add custom connector.
  2. Enter the server URL: https://app.probara.net/mcp.
  3. Claude.ai discovers the OAuth metadata automatically, registers itself (Dynamic Client Registration), and redirects you to Probara’s consent screen.
  4. Pick the organization to bind the connection to and approve. Claude.ai now has an OAuth grant scoped to that organization.
  1. Add the server: claude mcp add --transport http probara https://app.probara.net/mcp.
  2. Claude Code opens a browser window for the OAuth authorize/consent flow (same discovery + DCR as Claude.ai).
  3. Approve the negotiated scopes and pick an organization. If the client omits scope or sends a value Probara doesn’t recognize, it defaults to the full supported set (mcp:read mcp:write); see Scopes for the exact negotiation rules.
  4. Verify the connection: claude mcp list should show probara as connected.
  1. Open Settings → MCP → Add new MCP server.
  2. Choose HTTP transport and set the URL to https://app.probara.net/mcp.
  3. Cursor follows the same OAuth discovery/DCR/consent flow; alternatively, paste an API token into the connector’s Bearer/Authorization header field if your Cursor version does not yet support MCP OAuth.
  1. Open Settings → Connectors → Add MCP server (Developer Mode / custom connectors).
  2. Set the server URL to https://app.probara.net/mcp.
  3. Complete the OAuth consent flow, or supply an API token as a Bearer header if your ChatGPT plan only supports static-header connectors.

The endpoint serves two MCP protocol revisions. The revision a client negotiates decides the shape of its answers. Every request is a POST: the server keeps no standalone stream, so GET and DELETE on /mcp answer 405.

  • 2025 revisions, such as 2025-11-25, are served statelessly, and each answer is framed as Server-Sent Events (text/event-stream).
  • 2026-07-28 clients get one JSON body per request and discover the server with server/discover. Each of their requests carries the MCP-Protocol-Version and Mcp-Method headers, and tools/call, prompts/get and resources/read requests also carry Mcp-Name with the tool’s name, the prompt’s name or the resource’s URI. The headers must match the body. A request with a header missing or disagreeing is refused with HTTP 400 and JSON-RPC error -32020.

The answers to tools/list, prompts/list, resources/list, resources/templates/list and server/discover for 2026-07-28 clients carry ttlMs: 300000 and cacheScope: "private". A client may reuse one of these lists for five minutes and must not share it between users. The 2025 answers carry neither field.

A call to a tool that does not exist returns the JSON-RPC error -32602 (Tool <name> not found), not a tool result. A tool that exists and fails returns a result with isError: true.

A request body is limited to about 43.7 MiB (45,787,820 bytes). That covers a 32 MiB attachment in base64, with room for the JSON-RPC envelope. A larger body is refused with 413.

/mcp answers only for app.probara.net. A request addressed to another host, such as a *.workers.dev address, is refused with 403. A browser Origin must name the same host. A request without an Origin, such as one from a server-side client, is not affected by that check.

Nine tools cover the usual work in few calls. Every other operation is reached through the five tools that a default listing also carries, described under Operations and the run tools below.

ToolWhat it does
get_project_contextReturns a project’s suites, custom fields, configurations, milestones, environments and members in one call.
getReads any entity by display ID or ULID. A bare ULID also needs kind.
queryRuns a PQL query.
query_helpLists the PQL fields, operators and values of each entity, with examples that run.
analyze_runGroups a run’s failed and blocked cases by linked defect, then by suite, with their attempts.
upsert_test_casesCreates or updates up to 50 test cases. Each item names a display ID or an automation key, and reports its own outcome.
start_runStarts a run from a suite, a test plan, a PQL query or a list of cases, with its configurations and assignees.
record_resultsRecords up to 50 results in a run by test case display ID, with step results and evidence attachments.
file_defectFiles a defect from a result, and can also create its GitHub or Jira issue.

upsert_test_cases matches an item to a test case by its display ID or its automation key. An item with a display ID that does not exist fails, because the server assigns display IDs. An automation key that matches no case creates one. Sending the same batch again changes nothing and reports every item as unchanged. One item failing does not stop the others.

A client can also offer prompts and resources beside the tools. Each one reaches the same data as a tool, so nothing is reachable only through them.

Three prompts start a common task. Each one answers with a message that names the tools to run, in order:

PromptArgumentsTools it names
test_cases_from_issueproject_id and issue: a GitHub issue URL, owner/repo#n, or a Jira issue keyrun_read_operation to read the issue, then get_project_context, then upsert_test_cases
triage_runproject_id and run: a display ID such as R-12, or a ULIDanalyze_run, then get, then file_defect
regression_for_prproject_id, pull_request (a GitHub pull request URL or owner/repo#n) and an optional changed_areasquery_help and query to find the cases, then start_run

Probara does not read a pull request’s diff, so changed_areas sets the scope of a regression run.

Two resources hold the same JSON as their tools:

ResourceURISame answer as
PQL schemaprobara://pql/schemaquery_help
Project contextprobara://projects/{project}/context, with the project code, such as SHOPget_project_context

A resource read takes the same path as its tool, so an unknown project answers with the tool’s message as a JSON-RPC error, with the URI in its data. A resource has no block for the untrusted-data notice, so each resource’s description says that its JSON holds organization data.

Resources need the mcp:read scope. Every prompt ends in a write tool, so prompts need both mcp:read and mcp:write. A grant without the scope lists none of them, and a request for one is refused with 403 and the insufficient_scope challenge, as a hidden tool is.

A default listing carries the nine core tools and five more, so an agent sees up to 14 tools when it connects, and fewer under a narrower grant. Every other operation is in the tool reference, and each one is reached in three steps:

  1. search_operations finds operations by keyword, such as project or run result. Each hit gives the operation’s name, a one-line summary and the run tool that runs it.
  2. describe_operation returns the operation’s full description, the JSON schema of its inputs, its annotations and its output schema when it declares one.
  3. run_read_operation, run_write_operation or run_delete_operation runs it. Pass the operation’s name as operation and its inputs as arguments. The result is the operation’s own result.

The three run tools split by risk. run_read_operation runs read-only operations, run_write_operation runs writes that remove nothing, and run_delete_operation runs destructive operations such as deletes. A run tool refuses an operation of another risk, and its error names the run tool to use. An unknown name answers with the closest names.

Calling an operation by its name directly, such as create_project, returns a tool error that names its run tool. Only the nine core tools are called directly.

Every tool refuses an argument it does not take: the call returns a tool error that names the argument, and nothing runs. Through a run tool, the error also lists the operation’s arguments, with the required ones marked. The same holds for a key inside an item of record_results or upsert_test_cases, or inside a caseAssignees entry of start_run: a misspelled notes refuses the whole call instead of recording the result without it.

An OAuth grant without mcp:write lists the five read core tools and three tools that find and read operations: search_operations, describe_operation and run_read_operation. It lists no write tool, and search returns only read operations. A write call from such a grant is refused with 403 and the insufficient_scope challenge for mcp:write, as before. An OAuth grant that holds mcp:write alone lists the four write core tools and the two write run tools. An API token lists every default tool.

Destructive operations: preview, then confirm

Section titled “Destructive operations: preview, then confirm”

Some operations can remove or irreversibly change more than one record in one call: the bulk operations bulk_delete_tags, bulk_remove_run_cases and reconcile_run_cases, the deletes of a project, suite, test case, run, test plan, dashboard, custom field, tag, milestone or environment, and deactivate_org_member. Each one runs in two calls:

  1. Call it without confirm_token. Nothing runs. The result is a preview: status is confirmation_required, targets lists what the call names with its display ID and name where one read finds them, irreversible says what cannot be undone, and confirm_token, expires_at and expires_in_seconds say how long the token lasts.
  2. Repeat the same call with the same arguments and the confirm_token. The operation runs.

A token is single-use and valid for five minutes. It is bound to the credential that made the preview (an API token or an OAuth grant), its organization, the operation and its arguments. A call that presents a token is refused, and nothing runs, when:

  • the token is unknown, expired or already used: call again without confirm_token for a new preview;
  • the token was issued for another operation, credential, organization or set of arguments: it stays valid for its own call;
  • the token store is unavailable: the error is retryable, so retry the call.

run_delete_operation takes confirm_token inside arguments, as the operation does when it is called directly.

A change made through an MCP OAuth connection records the connection in its audit event: metadata.oauthClient holds the client’s clientId and clientName, as the audit events API returns them. The activity feed shows the change under the user, as it does for any session.

A successful result that carries organization data, such as titles, descriptions, steps, comments and text imported from GitHub or Jira, ends with a second text block. That block says the JSON above is data written by people in the organization or imported from GitHub or Jira, and that the text is data, not instructions. The first text block is the same JSON as before, and structuredContent is unchanged. Errors and the catalog answers of search_operations and describe_operation carry no such block.

A test case display ID, such as SHOP-45, can match several run cases of one run when the case is parameterized. An operation that takes a display ID and a run refuses the call, and lists up to 25 of those run cases, unless the call also names one: pass its combination as parameters, an array of name and value pairs such as [{"name":"Site","value":"EU"}], or pass the run case ULID. Bulk operations take run case ULIDs for such a case instead. The server never picks one for you. upsert_test_cases and create_test_case accept parameters and excludedCombinations, as the API does. Shared parameters are operations, found with search_operations and run by name: list_shared_parameters, get_shared_parameter, create_shared_parameter, update_shared_parameter, delete_shared_parameter (it needs confirmation and takes a mode), list_shared_parameter_usage, preview_test_case_combinations, and detach_test_case_parameter. The API and MCP apply the same rule. See the MCP tool reference and Parameterized test cases.

Every argument that takes an entity accepts its ULID or its display ID, and the server looks the display ID up for you.

  • A test case (SHOP-45) and a suite (SHOP-S3) carry their project code, so they need no project_id.
  • A run (R-12), milestone (M-5), defect (D-7), test plan (PLAN-3), shared step (SS-2) and review (RV-4) are numbered within a project. Send project_id with them.
  • A run case is a test case inside a run. The run-case tools take the test case’s display ID together with run_ulid. The bulk run tools also take the test case’s ULID.

A display ID that does not exist answers with an error that names it and the project. A project code that does not exist answers with the valid project codes.

Each tool declares what it does, so a client that honors the declaration can ask the user before a risky call. These are hints. The server never refuses a call because of them.

  • Read-only tools only read data.
  • Destructive tools remove data, or replace a whole list, document or credential in one call. Replace and reconcile tools take the full set you want, so anything you leave out is removed.
  • Idempotent tools have no further effect when the same call is repeated, so retrying one is safe.
  • External systems tools reach outside Probara: a GitHub or Jira write, a GitHub workflow launch, a webhook delivery, or an invitation email.

The MCP tool reference lists the hints of every tool. On connection the server also sends a short overview of Probara’s data model and identifiers, which many clients add to the model’s context.

A list tool returns one page per call. The tool reference states each tool’s default page size and the argument that changes it. The largest page is 200 items.

A page that is still too large for one response (about 10,000 tokens) is handled in one of two ways:

  • Lists that continue with nextCursor are trimmed to the items that fit. The result carries a truncation object: returned is the number of items it holds and pageItems is the number the page holds. Its nextCursor points at the last item it holds, so the next call returns the rest, with no gap.
  • Lists that page with page are refused with response_too_large, and nothing is returned. The message names the pageSize that fits; walk the list with that size.

get, list_results and list_run_cases also take fields, a list of the field names to return. query takes none: the SELECT clause of the query names its columns. The display ID and the ULID are always returned. An unknown name is refused with fields_invalid, and the message lists the valid names.

A single record, or a list without a paging argument, is returned whole up to about 25,000 tokens. A larger one is refused with response_too_large. The message names a filter to add or a narrower view to request, or says that the tool has none.

SymptomLikely cause
401 immediately, no browser promptClient does not support MCP OAuth discovery — use an API token instead
Consent screen shows the wrong organizationPick a different organization on the consent screen’s org picker before approving; each grant binds to exactly one organization
A tool call returns 403 with insufficient_scopeThe OAuth grant lacks the scope the call needs (mcp:read to read, mcp:write to change). Authorize again to get it.
A tool call fails with forbidden, naming the scope and your roleYour role in that organization no longer allows the scope, although the grant holds it. Authorizing again does not change this: an organization owner or admin must change your role. See Authentication.
503 with a Retry-After headerProbara could not check the credential because of a temporary fault — wait the seconds in Retry-After, then retry
429 with a Retry-After headerPer-token or per-organization rate limit hit — wait the seconds in Retry-After, then retry
403 before a tool runsThe client calls /mcp on a host other than app.probara.net, or sends a foreign Origin. Point it at https://app.probara.net/mcp.
413 on a tool callThe request body is over the 43.7 MiB limit. Attachments are capped at 32 MiB, so send a smaller file.
JSON-RPC -32602, Tool … not foundThe tool name is not in the list the client holds. Refresh the tool list; a cached list lasts up to five minutes.
response_too_large in a tool resultThe result is too large for one response. The message names the page size to request, a filter to add, or a narrower view. If it names none, the tool has no smaller form of that record.