Skip to main content
Glama
orchestra-hq

Orchestra MCP Server

Official
by orchestra-hq
README.md
# Orchestra MCP Server

A Model Context Protocol (MCP) server for the [Orchestra API](https://docs.getorchestra.io/api/introduction). End users can connect directly to Orchestra's hosted MCP endpoint and authenticate with their Orchestra API key.

## Quick Start

Use Orchestra's hosted MCP endpoint:

- URL: `https://mcp.getorchestra.io/orchestra`
- Required header: `Authorization: Bearer <YOUR_ORCHESTRA_API_KEY>`
- API key location: [Orchestra workspace settings](https://app.getorchestra.io/settings/workspace)

## Available Tools

<!-- The table below is generated by scripts/update_readme.py — do not edit by hand. -->
<!-- available-tools:start -->
| Tool | Auth required | Purpose | Category |
|------|---------------|---------|------|
| `whats_broken` | Yes | Failing and warning pipeline runs in a window, pre-joined to the task runs that failed inside them, with messages, platform links and duration anomalies. | Triage |
| `diagnose` | Yes | Deep dive on one task run: parameters, upstream task statuses, log tail and artifact filenames. | Triage |
| `pipeline_context` | Yes | A pipeline's metadata, full definition, integrations, recent run outcomes and median succeeded duration. | Triage |
| `get_pipeline` | Yes | Fetch a single pipeline. Provide exactly one selector: pipeline_id, alias, or repository together with yaml_path (`GET /pipeline`). | Pipelines |
| `list_pipelines` | Yes | List pipelines (`GET /pipelines`). | Pipelines |
| `create_pipeline` | Yes | Create a pipeline (`POST /pipelines`). | Pipelines |
| `update_pipeline` | Yes | Update a pipeline by selector (`PUT /pipelines`). | Pipelines |
| `delete_pipeline` | Yes | Delete a pipeline. Provide exactly one selector: pipeline_id, alias, or repository together with yaml_path (`DELETE /pipelines`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Pipelines |
| `get_pipeline_data` | Yes | Get pipeline data (`GET /pipelines/data`). | Pipelines |
| `start_pipeline` | Yes | Start a pipeline run (`POST /pipelines/{pipeline_id_or_alias}/start`). | Pipelines |
| `pause_pipeline` | Yes | Pause or unpause a pipeline (`PUT /pipelines/{pipeline_id_or_alias}/pause`). | Pipelines |
| `move_pipeline` | Yes | Move a pipeline to a folder (`PUT /pipelines/{pipeline_id_or_alias}/folder`). | Pipelines |
| `validate_pipeline` | No | Validate pipeline schema (`POST /pipelines/schema`). | Pipelines |
| `migrate_pipeline` | Yes | Migrate an Orchestra-backed pipeline to git-backed storage. Identify it with pipeline_id or alias, and omit working_branch when it equals default_branch (`PATCH /pipelines/storage-settings`). | Pipelines |
| `import_pipeline` | Yes | Import a pipeline (`POST /pipelines/import`). | Pipelines |
| `get_pipeline_run` | Yes | Get a pipeline run (`GET /pipeline_runs/{pipeline_run_id}`). | Pipeline Runs |
| `list_pipeline_runs` | Yes | List pipeline runs with optional filters. status accepts comma-separated values: CREATED, QUEUED, RUNNING, SUCCEEDED, WARNING, FAILED, SKIPPED, CANCELLING, CANCELLED (`GET /pipeline_runs`). | Pipeline Runs |
| `cancel_pipeline_run` | Yes | Cancel a running or queued pipeline run by its ID (`POST /pipeline_runs/{pipeline_run_id}/cancel`). | Pipeline Runs |
| `get_pipeline_run_lineage_url` | No | Build the URL of a pipeline run's lineage graph in the Orchestra UI (derived from `ORCHESTRA_ENV`). | Pipeline Runs |
| `list_task_runs_for_pipeline_run` | Yes | List task runs for a pipeline run (`GET /pipeline_runs/{pipeline_run_id}/task_runs`). | Task Runs |
| `list_task_runs` | Yes | List task runs (`GET /task_runs`). | Task Runs |
| `get_task_run` | Yes | Get a task run (`GET /task_runs/{task_run_id}`). | Task Runs |
| `list_incidents` | Yes | List incidents (`GET /incidents`). | Incidents |
| `get_incident` | Yes | Get an incident (`GET /incidents/{incident_id}`). | Incidents |
| `update_incident` | Yes | Update an incident (`PATCH /incidents/{incident_id}`). | Incidents |
| `list_incident_events` | Yes | List an incident's timeline (`GET /incidents/{incident_id}/events`). | Incidents |
| `get_incident_external_event` | Yes | Get an external event's payload (`GET /incidents/{incident_id}/events/{incident_event_id}/external_event`). | Incidents |
| `merge_incidents` | Yes | Merge incidents (`POST /incidents/{incident_id}/merge`). | Incidents |
| `unmerge_incidents` | Yes | Unmerge incidents (`POST /incidents/{incident_id}/unmerge`). | Incidents |
| `mute_incident` | Yes | Mute an incident (`POST /incidents/{incident_id}/mute`). | Incidents |
| `unmute_incident` | Yes | Unmute an incident (`POST /incidents/{incident_id}/unmute`). | Incidents |
| `create_incident_comment` | Yes | Write to an incident's timeline (`POST /incidents/{incident_id}/comments`). | Incidents |
| `get_incident_settings` | Yes | Get incident settings (`GET /incident_settings`). | Incident settings |
| `update_incident_settings` | Yes | Update incident settings (`PATCH /incident_settings`). | Incident settings |
| `list_monitors` | Yes | List monitors (`GET /monitors`). | Monitors |
| `create_monitor` | Yes | Create a monitor (`POST /monitors`). | Monitors |
| `reorder_monitors` | Yes | Reorder monitors (`POST /monitors/reorder`). | Monitors |
| `get_monitor` | Yes | Get a monitor (`GET /monitors/{monitor_id}`). | Monitors |
| `update_monitor` | Yes | Update a monitor (`PUT /monitors/{monitor_id}`). | Monitors |
| `delete_monitor` | Yes | Delete a monitor (`DELETE /monitors/{monitor_id}`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Monitors |
| `list_operations` | Yes | List operations (`GET /operations`). | Operations |
| `list_assets` | Yes | List assets (`GET /assets`). | Assets |
| `get_asset_by_id` | Yes | Get an asset (`GET /assets/{asset_id}`). | Assets |
| `list_task_run_logs` | Yes | List task run logs (`GET /pipeline_runs/{pipeline_run_id}/task_runs/{task_run_id}/logs`). | Logs |
| `download_task_run_log` | Yes | Download a task run log (`GET /pipeline_runs/{pipeline_run_id}/task_runs/{task_run_id}/logs/download`). | Logs |
| `list_task_run_artifacts` | Yes | List task run artifacts (`GET /pipeline_runs/{pipeline_run_id}/task_runs/{task_run_id}/artifacts`). | Artifacts |
| `download_task_run_artifact` | Yes | Download a task run artifact (`GET /pipeline_runs/{pipeline_run_id}/task_runs/{task_run_id}/artifacts/download`). | Artifacts |
| `get_integration` | Yes | Get an integration (`GET /integrations/{integration}`). | Integrations |
| `list_integration_connections` | Yes | List integration connections (`GET /integrations/connections`). | Integration Connections |
| `get_integration_connection` | Yes | Get an integration connection (`GET /integrations/{integration}/auth/{connection_id}`). | Integration Connections |
| `update_integration_connection` | Yes | Update an integration connection (`PATCH /integrations/{integration}/auth/{connection_id}`). | Integration Connections |
| `delete_integration_connection` | Yes | Delete an integration connection (`DELETE /integrations/{integration}/auth/{connection_id}`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Integration Connections |
| `create_integration_connection` | Yes | Create an integration connection (`POST /integrations/{integration}/auth`). | Integration Connections |
| `list_environments` | Yes | List environments (`GET /environments`). | Environments |
| `create_environment` | Yes | Create an environment (`POST /environments`). | Environments |
| `get_environment` | Yes | Get an environment (`GET /environments/{environment_id}`). | Environments |
| `update_environment` | Yes | Update an environment (`PATCH /environments/{environment_id}`). | Environments |
| `delete_environment` | Yes | Delete an environment (`DELETE /environments/{environment_id}`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Environments |
| `get_integration_state_for_state_aware` | Yes | Get integration state (`GET /state/{integration}`). | State |
| `list_audit_events` | Yes | List audit events (`GET /audit_events`). | Audit |
| `list_accounts` | Yes | List workspaces (`GET /accounts`). | Accounts |
| `list_agent_avatars` | Yes | List agent avatars (`GET /agents/avatar-catalog`). | Agents |
| `create_agent` | Yes | Create an agent (`POST /agents`). | Agents |
| `list_agents` | Yes | List agents (`GET /agents`). | Agents |
| `get_agent` | Yes | Get an agent (`GET /agents/{agent_id}`). | Agents |
| `update_agent` | Yes | Update an agent (`PATCH /agents/{agent_id}`). | Agents |
| `delete_agent` | Yes | Delete an agent (`DELETE /agents/{agent_id}`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Agents |
| `list_agent_skills` | Yes | List an agent's skills (`GET /agents/{agent_id}/skills`). | Agents |
| `set_agent_skills` | Yes | Set an agent's skills (`PUT /agents/{agent_id}/skills`). | Agents |
| `list_agent_integrations` | Yes | List an agent's integrations (`GET /agents/{agent_id}/integrations`). | Agents |
| `set_agent_integrations` | Yes | Set an agent's integrations (`PUT /agents/{agent_id}/integrations`). | Agents |
| `get_agent_usage` | Yes | Get agent token usage (`GET /usage`). | Agents |
| `list_agent_sessions` | Yes | List agent sessions (`GET /sessions`). | Agent Sessions |
| `create_agent_session` | Yes | Start an agent session (`POST /sessions`). | Agent Sessions |
| `get_agent_session` | Yes | Get an agent session (`GET /sessions/{session_id}`). | Agent Sessions |
| `send_agent_session_message` | Yes | Send a message to an agent session (`POST /sessions/{session_id}`). | Agent Sessions |
| `get_agent_session_history_messages` | Yes | Read an agent session's messages (`GET /sessions/{session_id}/history/messages`). | Agent Sessions |
| `cancel_agent_session_prompt` | Yes | Cancel an agent session prompt (`POST /sessions/{session_id}/cancel`). | Agent Sessions |
| `list_skills` | Yes | List skills (`GET /skills`). | Skills |
| `create_skill` | Yes | Create a skill (`POST /skills`). | Skills |
| `get_skill` | Yes | Get a skill (`GET /skills/{skill_id}`). | Skills |
| `update_skill` | Yes | Update a skill (`PATCH /skills/{skill_id}`). | Skills |
| `delete_skill` | Yes | Delete a skill (`DELETE /skills/{skill_id}`). Only runs for a user signed in with OAuth; with an Orchestra API key it is refused. | Skills |
| `import_skill` | Yes | Import a skill from git (`POST /skills/import`). | Skills |
<!-- available-tools:end -->

### Cursor

Add this to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):

```json
{
  "mcpServers": {
    "orchestra": {
      "url": "https://mcp.getorchestra.io/orchestra",
      "headers": {
        "Authorization": "Bearer <YOUR_ORCHESTRA_API_KEY>"
      }
    }
  }
}
```

### Claude Code

Add the hosted server with:

```bash
claude mcp add --transport http --header "Authorization: Bearer <YOUR_ORCHESTRA_API_KEY>" orchestra https://mcp.getorchestra.io/orchestra
```

### Other MCP clients

Any MCP client that supports remote HTTP/SSE servers can connect with this shape:

```json
{
  "mcpServers": {
    "orchestra": {
      "url": "https://mcp.getorchestra.io/orchestra",
      "headers": {
        "Authorization": "Bearer <YOUR_ORCHESTRA_API_KEY>"
      }
    }
  }
}
```

## Managing Multiple Workspaces

If you need to connect to multiple Orchestra workspaces, you can set up separate MCP server connections with workspace-specific API keys:

```json
{
  "mcpServers": {
    "orchestra-data-quality-tests": {
      "url": "https://mcp.getorchestra.io/orchestra",
      "headers": {
        "Authorization": "Bearer <DATA_QUALITY_WORKSPACE_API_KEY>"
      }
    },
    "orchestra-sales-integrations": {
      "url": "https://mcp.getorchestra.io/orchestra",
      "headers": {
        "Authorization": "Bearer <SALES_WORKSPACE_API_KEY>"
      }
    }
  }
}
```

## Run Locally

This section discusses how to run the MCP server locally, and is mainly intended for contributors.

### Prerequisites

- Python 3.11 or higher
- [uv](https://github.com/astral-sh/uv) package manager
- Orchestra API key

### Install dependencies

```bash
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install project dependencies
uv sync
```

### Set API key

```bash
export ORCHESTRA_API_KEY="your-orchestra-api-key"
```

### (Optional) Select environment for local runs

For local development, the server defaults to `app`. You can override it with `ORCHESTRA_ENV`:

```bash
export ORCHESTRA_ENV="dev"
```

Valid values:

- `app` (default)
- `stage`
- `dev`

### (Optional) Disable destructive deletion

The delete tools are registered by default, but only run for a user signed in with OAuth to
the hosted endpoint: called with an Orchestra API key, including when running the server
locally, they are refused. To hide them, set `ORCHESTRA_ENABLE_DELETE` to anything other
than `true` (in any case) or `1` before starting the server:

```bash
export ORCHESTRA_ENABLE_DELETE="false"
```

### Run the server

```bash
python -m orchestramcp.server
```

The server fetches every Orchestra OpenAPI spec on startup and exposes the operations
each API flags for the MCP. Set `ORCHESTRA_OPENAPI_URL` (Orchestra API),
`ORCHESTRA_PLATFORM_OPENAPI_URL` (Orchestra Platform API) or
`ORCHESTRA_AGENTS_OPENAPI_URL` (Orchestra Agents API) to point at a specific spec
(e.g. a local file) instead of the environment default. Startup fails if any spec
cannot be fetched, rather than serving a partial set of tools.

### (Optional) Accept OAuth access tokens

The hosted Lambda can also accept OAuth 2.1 access tokens issued by Orchestra's
authorization server, alongside API keys. Set all three variables to turn it on —
with any of them unset, every bearer token is treated as an API key:

```bash
export ORCHESTRA_OAUTH_ISSUER="https://app.getorchestra.io"
export ORCHESTRA_OAUTH_JWKS_URI="https://app.getorchestra.io/oauth/jwks.json"
export ORCHESTRA_OAUTH_RESOURCE_URL="https://mcp.getorchestra.io/orchestra"
```

The issuer is per-environment — swap `app` for `stage` or `dev` — and the rest of its
metadata, `jwks_uri` included, is published at
`<issuer>/.well-known/oauth-authorization-server`.

`ORCHESTRA_OAUTH_RESOURCE_URL` must be the MCP URL exactly as a user types it into their
client, path included: it is published as the `resource` of the
[RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) metadata document, and it is the
audience every token is checked against. The authorization server has to serve that same
identifier — it mints a token only for a resource it is configured for, and stamps `aud`
with its own spelling of it. Verified tokens are forwarded to the Orchestra API unchanged.

### Testing the OAuth flow locally

`scripts/local_resource_server.py` fronts the real Lambda handler with an HTTP socket,
so an MCP client can run the whole flow against the production code path:

```bash
ORCHESTRA_ENV=dev \
ORCHESTRA_OAUTH_ISSUER=https://dev.getorchestra.io \
ORCHESTRA_OAUTH_JWKS_URI=https://dev.getorchestra.io/oauth/jwks.json \
ORCHESTRA_OAUTH_RESOURCE_URL=https://mcp-dev.getorchestra.io/orchestra \
    uv run python scripts/local_resource_server.py
```

```bash
claude mcp add --transport http orchestra-local http://127.0.0.1:8788/orchestra
```

Connecting should take you through discovery, client registration and a consent screen,
after which tool calls run as your user rather than as an account-wide API key.

The resource URL is the deployed dev identifier rather than the local address, because it
has to be one the authorization server serves *and* one the Orchestra API accepts as an
audience — a token minted for `127.0.0.1` is refused by both. The cost is that the
metadata pointer in the 401 names the deployed host, so a client that follows it lands
somewhere this server is not; discovery then depends on the client falling back to
probing the address it connected to. Testing against a deployed environment avoids that,
and is also the only way to exercise the edge routing `/orchestra/.well-known/*`.


## Development

- Run `uv run pytest` to run tests.
- Run `uv run ruff check .` and `uv run ruff format .` to check and format code.

PRs to main will trigger CI checks in GitHub, `main` branch merges release to the dev & stage environments, and Github releases relase to the production environment.

TDQS

B3.4/5.0

Scored across 84 tools

Disambiguation4/5

Most tools map to distinct resources and actions, and the descriptions clarify close pairs such as get_pipeline/get_pipeline_data/pipeline_context and list_task_runs vs list_task_runs_for_pipeline_run. A few adjacent areas remain, like pipeline-run listing vs whats_broken and workspace integrations vs agent integrations, but they are generally readable.

Naming Consistency4/5

The set is predominantly consistent snake_case verb_noun naming across resource families. Exceptions like diagnose, whats_broken, and pipeline_context are readable but break the otherwise predictable pattern.

Tool Count1/5

84 tools is far beyond the typical 3-15 range and creates an extremely heavy surface for an agent to navigate. Even though the domain is broad, the many CRUD and list variants across each resource family make this an extreme mismatch.

Completeness4/5

Coverage is extensive: pipelines, runs, task runs, incidents, monitors, agents, sessions, skills, environments, connections, assets, and audit events all have relevant lifecycle operations. Minor gaps remain, such as no obvious integration discovery/list tool and limited write coverage for assets or operations, likely by design.

Maintenance

ActivityActive
ResponsivenessNo issues