MCP reference
MCP tools
All successful tools return the same data as JSON text and structuredContent. Read tokens expose five tools, operator tokens add three mutations, and the secrets scope adds two more.
Response envelope
Clients should prefer structuredContent when available and fall back to parsing the text block.
{
"content": [{ "type": "text", "text": "{ ...pretty JSON... }" }],
"structuredContent": { "...": "tool-specific data" }
}{
"isError": true,
"content": [{ "type": "text", "text": "Run not found" }]
}list_runs
List recent runs in this token’s organization, newest first.
| Input | Type | Required | Contract |
|---|---|---|---|
repository | string | No | Exact owner/repository full name, 1–255 characters. |
status | enum | No | queued, in_progress, completed, success, failure, cancelled, skipped, timed_out, or infrastructure_failure. |
limit | integer | No | 1–100; default 30. |
{ "repository": "acme/api", "status": "failure", "limit": 10 }{
"runs": [{
"id": "run_uuid", "runNumber": 42, "runName": "CI",
"attempt": 1, "status": "completed", "conclusion": "failure",
"trigger": "pull_request", "sourceSha": "...", "sourceRef": "...",
"headBranch": "fix/cache", "actor": "octocat",
"createdAt": "...", "startedAt": "...", "completedAt": "...",
"workflowId": "workflow_uuid", "workflow": "CI",
"repositoryId": "repository_uuid", "repository": "acme/api"
}],
"count": 1
}get_run
Get one run with its repository, workflow, jobs, current attempts, and step results.
| Input | Type | Required | Contract |
|---|---|---|---|
runId | string | Yes | Non-empty Runnable run ID. |
{ "runId": "run_uuid" }{
"run": {
"id": "...", "runNumber": 42, "runName": "CI", "attempt": 1,
"status": "completed", "conclusion": "failure", "trigger": "push",
"sourceSha": "...", "sourceRef": "refs/heads/main", "headBranch": "main",
"actor": "octocat", "createdAt": "...", "startedAt": "...", "completedAt": "...",
"workflow": { "id": "...", "name": "CI", "path": ".runnable/workflows/ci.yml" },
"repository": { "id": "...", "fullName": "acme/api", "provider": "github" }
},
"jobs": [{
"id": "job_uuid", "key": "test", "name": "Test", "needs": [], "matrix": null,
"status": "completed", "conclusion": "failure", "currentAttempt": 1,
"queuedAt": "...", "startedAt": "...", "completedAt": "...",
"attempt": {
"id": "attempt_uuid", "status": "completed", "conclusion": "failure",
"lastHeartbeatAt": "...",
"steps": [{ "id": "...", "key": "test", "position": 2, "name": "npm test",
"status": "completed", "conclusion": "failure", "exitCode": 1,
"startedAt": "...", "completedAt": "..." }]
}
}]
}get_job_logs
Read a line- and byte-bounded masked tail from one job attempt. The operation is audit logged.
| Input | Type | Required | Contract |
|---|---|---|---|
jobId | string | Yes | Non-empty job ID from get_run. |
attempt | positive integer | No | Defaults to the job’s current attempt. |
tailLines | integer | No | 1–2,000; default 400. |
maxBytes | integer | No | 1,024–200,000; default 100,000. |
// input
{ "jobId": "job_uuid", "attempt": 1, "tailLines": 200, "maxBytes": 50000 }
// output
{
"job": { "id": "job_uuid", "name": "Test", "status": "completed", "conclusion": "failure" },
"attempt": 1,
"logs": "...masked log tail...",
"returnedBytes": 18432,
"truncated": true
}truncated is true when earlier chunks or lines/bytes were omitted. Expired log chunks are excluded and cannot be recovered by increasing the bounds.
wait_for_run
Long-poll one run without consuming runner compute or relying on an in-memory MCP session.
| Input | Type | Required | Contract |
|---|---|---|---|
runId | string | Yes | Non-empty run ID. |
afterCursor | string | No | Cursor from the previous call. The server returns early if state changed. |
timeoutSeconds | integer | No | 1–25; default 20. |
// first input
{ "runId": "run_uuid", "timeoutSeconds": 20 }
// output
{
"run": { "id": "run_uuid", "status": "in_progress", "conclusion": null,
"startedAt": "...", "completedAt": null },
"jobs": [{ "id": "job_uuid", "name": "Test", "status": "in_progress",
"conclusion": null, "currentAttempt": 1, "startedAt": "...", "completedAt": null }],
"cursor": "JgQX6pEo_s9...",
"terminal": false,
"timedOut": true
}
// next input
{ "runId": "run_uuid", "afterCursor": "JgQX6pEo_s9...", "timeoutSeconds": 20 }A terminal run returns immediately. timedOut: true means the bounded wait elapsed without a state change; it is not a workflow timeout.
list_workflows
List definition IDs available to the organization, optionally for one exact repository.
| Input | Type | Required | Contract |
|---|---|---|---|
repository | string | No | Exact full name, 1–255 characters. |
limit | integer | No | 1–100; default 50. |
// input
{ "repository": "acme/api", "limit": 20 }
// output
{
"workflows": [{
"id": "workflow_uuid", "name": "CI", "path": ".runnable/workflows/ci.yml",
"status": "active", "diagnostics": [], "lastSourceSha": "...",
"repositoryId": "repository_uuid", "repository": "acme/api",
"defaultBranch": "main", "updatedAt": "..."
}],
"count": 1
}rerun_run
Queue another run for the same workflow snapshot and source revision.
| Input | Type | Required | Contract |
|---|---|---|---|
runId | string | Yes | Source run ID. |
failedOnly | boolean | No | Default true. False queues a complete rerun. |
// input
{ "runId": "source_run_uuid", "failedOnly": true }
// output
{ "runId": "new_run_uuid", "sourceRunId": "source_run_uuid",
"failedOnly": true, "orchestration": { "started": true } }A rerun does not pick up new commits
cancel_run
Cancel all unfinished work in a run. A terminal run returns safely without mutation.
| Input | Type | Required | Contract |
|---|---|---|---|
runId | string | Yes | Run to cancel. |
// input
{ "runId": "run_uuid" }
// active output
{ "runId": "run_uuid", "cancelled": true, "alreadyTerminal": false }
// terminal output
{ "runId": "run_uuid", "cancelled": false, "alreadyTerminal": true }dispatch_workflow
Start a workflow that declares workflow_dispatch, then wait on the returned run ID.
| Input | Type | Required | Contract |
|---|---|---|---|
workflowId | string | Yes | ID from list_workflows. |
ref | string | Yes | Provider-accepted Git ref/revision, 1–255 characters. |
inputs | object | No | String-keyed values; default {}. Validated against workflow_dispatch definitions. |
// input
{ "workflowId": "workflow_uuid", "ref": "refs/heads/main",
"inputs": { "environment": "staging", "dry-run": false } }
// output
{ "runId": "run_uuid", "workflowId": "workflow_uuid",
"ref": "refs/heads/main", "orchestration": { "started": true } }list_secrets
List secret names and scopes. Values are never returned by any tool.
| Input | Type | Required | Contract |
|---|---|---|---|
repository | string | No | Exact full name. Organization-wide secrets are always included, because they apply to every repository. |
// input
{ "repository": "acme/api" }
// output — names and scopes only, never values
{ "secrets": [
{ "id": "secret_uuid", "name": "DATABASE_URL", "scope": "organization",
"repositoryId": null, "environmentId": null, "updatedAt": "2026-08-14T09:12:00.000Z" }
] }set_secret
Create a secret, or replace the value of one that already exists, for use as ${{ secrets.NAME }}.
| Input | Type | Required | Contract |
|---|---|---|---|
name | string | Yes | Upper-cased. Letters, digits, and underscores; must not start with a digit. |
value | string | Yes | 1–64,000 characters. Encrypted with the organization's workspace key and never returned. |
scope | string | No | organization (default), repository, or environment. |
repositoryId | uuid | Conditional | Required for repository and environment scope. |
environmentId | uuid | Conditional | Required for environment scope. |
// input
{ "name": "DATABASE_URL", "value": "postgresql://…", "scope": "organization" }
// output — acknowledges the write, echoes nothing of the value
{ "id": "secret_uuid", "name": "DATABASE_URL", "scope": "organization",
"repositoryId": null, "environmentId": null, "created": true }Writes are recorded as mcp.secret.created or mcp.secret.updated audit events, attributed to the token rather than a person. Because no tool reads a value back, call list_secrets first when you need to know whether you are creating or overwriting.
Tool errors and recovery
Input-schema violations are rejected by MCP validation. Service errors use isError and a text message.
| Message or symptom | Recovery |
|---|---|
| Run not found | Call list_runs in the same token organization and use its ID. |
| Job not found / Job attempt not found | Refresh get_run; use the current job ID and a returned attempt number. |
| Workflow not found | Call list_workflows; definitions can be replaced after source discovery. |
| Workflow not found or invalid / dispatch input error | Inspect workflow status/diagnostics and supply every required typed input. |
| Run watch cancelled | Client aborted the request; call wait_for_run again with the last good cursor. |
| Tool does not appear | The credential is read-only; issue a separately approved operator token if needed. |

