> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usenightowl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server

> Connect Claude Code, Codex, Cursor, and other AI assistants to NightOwl via the Model Context Protocol.

NightOwl ships two remote MCP servers so AI coding assistants can drive the full dashboard — browse telemetry, triage issues, provision apps, manage teams, configure alert channels. Every AI-initiated change is logged with `actor_type=mcp`, so human and AI edits stay visually distinct and a token can be revoked instantly.

## 1. Generate a personal access token

Sign in to the dashboard, open **Account → MCP Tokens**, and create a token with a memorable label (e.g. *"Laptop — Claude Code"*). The raw token is shown once — copy it immediately; only the label, creation date, and last-used timestamp are visible afterwards. Revoking a token blocks every client using it instantly.

Tokens are user-scoped, inherit your team membership, and carry the `mcp` ability — they only work against the MCP endpoints.

## 2. The two servers

NightOwl exposes two MCP endpoints. You'll usually register both.

| Server       | Endpoint        | Scope                                   | Typical use                                                                                                          |
| ------------ | --------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Platform** | `/mcp/platform` | Your account + every team you belong to | Provisioning apps, inviting teammates, rotating agent tokens, inspecting agent health                                |
| **Tenant**   | `/mcp/<app-id>` | A single connected app's telemetry      | Triage issues, browse requests / exceptions / queries / jobs / logs, configure alert channels, manage data retention |

The platform server has **25 tools**; the tenant server has **53**. Full coverage of the dashboard's CRUD surface.

## 3. Connect your client

### Claude Code

Register both servers:

```bash theme={null}
claude mcp add --transport http nightowl-platform \
  https://api.usenightowl.com/mcp/platform \
  --header "Authorization: Bearer <token>"

claude mcp add --transport http nightowl \
  https://api.usenightowl.com/mcp/<app-id> \
  --header "Authorization: Bearer <token>"
```

Run `/mcp` in Claude Code to verify both servers connected.

### Codex

Codex reads MCP servers from `~/.codex/config.toml` and resolves the bearer token from an environment variable. Edit the config:

```toml theme={null}
[mcp_servers.nightowl-platform]
url = "https://api.usenightowl.com/mcp/platform"
bearer_token_env_var = "NIGHTOWL_MCP_TOKEN"

[mcp_servers.nightowl]
url = "https://api.usenightowl.com/mcp/<app-id>"
bearer_token_env_var = "NIGHTOWL_MCP_TOKEN"
```

Then export the token in your shell profile (`~/.zshrc`, `~/.bashrc`, etc.):

```bash theme={null}
export NIGHTOWL_MCP_TOKEN="<token>"
```

Reload the shell (`source ~/.zshrc`) so Codex picks up the variable. Both servers can share the same env var, or use distinct ones if you'd rather scope tokens per server.

If you'd rather not edit `config.toml` by hand, the same registration works via the CLI (token must already be exported):

```bash theme={null}
codex mcp add nightowl-platform \
  --url https://api.usenightowl.com/mcp/platform \
  --bearer-token-env-var NIGHTOWL_MCP_TOKEN

codex mcp add nightowl \
  --url https://api.usenightowl.com/mcp/<app-id> \
  --bearer-token-env-var NIGHTOWL_MCP_TOKEN
```

### Cursor

Cursor speaks bearer-token HTTP MCP natively. Add to `.cursor/mcp.json` (project-scoped) or `~/.cursor/mcp.json` (global):

```json theme={null}
{
  "mcpServers": {
    "nightowl-platform": {
      "url": "https://api.usenightowl.com/mcp/platform",
      "headers": {
        "Authorization": "Bearer ${env:NIGHTOWL_MCP_TOKEN}"
      }
    },
    "nightowl": {
      "url": "https://api.usenightowl.com/mcp/<app-id>",
      "headers": {
        "Authorization": "Bearer ${env:NIGHTOWL_MCP_TOKEN}"
      }
    }
  }
}
```

The `${env:NIGHTOWL_MCP_TOKEN}` reference keeps the raw token out of the file — export it from your shell profile. Cursor reloads the file when you save it.

### Windsurf, Zed, and other stdio-only clients (via mcp-remote)

For clients that don't yet support remote HTTP MCP, the `mcp-remote` shim proxies a remote server as stdio:

```json theme={null}
{
  "mcpServers": {
    "nightowl": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://api.usenightowl.com/mcp/<app-id>",
        "--header",
        "Authorization: Bearer <token>"
      ]
    }
  }
}
```

<Note>
  Self-hosted NightOwl? Replace `https://api.usenightowl.com` with your own API URL. The paths are identical.
</Note>

## 4. What's available

### Platform server (`/mcp/platform`)

| Category         | Tools                                                                                                               |
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| **Apps**         | `list_apps`, `get_app`, `create_app`, `update_app`, `delete_app` ⚠, `test_app_connection`, `regenerate_app_token` ⚠ |
| **Agent health** | `app_health`, `app_health_history`, `app_health_diagnoses`                                                          |
| **Teams**        | `list_teams`, `get_team`, `create_team`, `update_team`, `leave_team`, `update_team_member`, `remove_team_member`    |
| **Invitations**  | `list_team_invitations`, `create_team_invitation`, `revoke_team_invitation`, `accept_team_invitation`               |
| **MCP tokens**   | `list_mcp_tokens`, `create_mcp_token`, `delete_mcp_token`                                                           |
| **Subscription** | `show_subscription` (read only — billing mutations use the dashboard)                                               |

### Tenant server (`/mcp/<app-id>`)

| Category            | Tools                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Overview**        | `dashboard_overview`                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **Issues**          | `list_issues`, `get_issue`, `get_stack_trace`, `get_issue_occurrences`, `update_issue_status`, `bulk_update_issues`, `add_issue_comment`                                                                                                                                                                                                                                                                                                                                       |
| **Telemetry**       | `list_requests`/`get_request`/`get_route_detail`, `list_exceptions`/`get_exception`, `list_queries`/`get_query`, `list_jobs`/`get_job`/`get_job_attempt`, `list_commands`/`get_command`/`get_command_attempt`, `list_scheduled_tasks`/`get_scheduled_task`/`get_scheduled_task_attempt`, `list_cache_events`, `list_logs`/`get_log`, `list_mail`/`get_mail`, `list_notifications`/`get_notification`, `list_outgoing_requests`/`get_outgoing_request`, `list_users`/`get_user` |
| **Alerts**          | `list_alerts`, `mark_alert_read`, `mark_all_alerts_read`                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **Alert channels**  | `list_alert_channels`, `create_alert_channel`, `update_alert_channel`, `delete_alert_channel`, `toggle_alert_channel`, `test_alert_channel`                                                                                                                                                                                                                                                                                                                                    |
| **Settings**        | `get_settings`, `update_settings`, `list_environments`, `list_thresholds`, `update_thresholds`, `list_threshold_targets`                                                                                                                                                                                                                                                                                                                                                       |
| **Data management** | `filter_options`, `preview_deletion`, `destroy_data` ⚠                                                                                                                                                                                                                                                                                                                                                                                                                         |

⚠ = destructive. These tools require an explicit `confirm: "YES"` argument and cannot be invoked accidentally.

## 5. Safety model

<CardGroup cols={2}>
  <Card title="Scoped tokens" icon="shield-check">
    Tokens can only access apps where the owning user is a team member. The URL's `app-id` is validated on every call.
  </Card>

  <Card title="Audit trail" icon="list">
    Every mutating call writes an activity record with `actor_type=mcp` and `actor_meta` carrying the token label and client user-agent.
  </Card>

  <Card title="Instant revoke" icon="ban">
    Deleting a token from Account → MCP Tokens blocks every client using it — no redeploy, no restart.
  </Card>

  <Card title="Confirmation gates" icon="lock">
    Destructive tools (`delete_app`, `regenerate_app_token`, `destroy_data`) refuse to execute without `confirm: "YES"`. Dry-run counterparts (`preview_deletion`) are always safe.
  </Card>

  <Card title="Webhook parity" icon="webhook">
    Status changes made via MCP fire the same Slack, Discord, email, and webhook channels that a human edit would.
  </Card>

  <Card title="Self-revoke protection" icon="shield">
    `delete_mcp_token` refuses to delete the token currently making the call. Revoke it from the dashboard instead.
  </Card>
</CardGroup>

## 6. Example workflows

Once both servers are connected, a single prompt can span NightOwl data, your codebase, and team operations:

```text theme={null}
> What are the top three open exceptions in production,
  and is any of them caused by code I changed in the last week?
```

The assistant calls `list_issues` on the tenant server, then `get_issue` on each hit, then runs `git log` locally to cross-reference authorship — root cause in one turn.

Close the loop:

```text theme={null}
> Mark issues #4812 and #4815 as resolved — both were fixed by
  the null check I just merged in OrderService.
```

A single `bulk_update_issues` call flips both statuses, writes activity rows, and fires the configured alert channels — attributed to MCP rather than to you directly.

Provision a new environment:

```text theme={null}
> Create a staging app in the Acme team, test the DB connection,
  and give me the agent token so I can add it to Render's env vars.
```

Two platform calls (`test_app_connection`, `create_app`) — the agent token comes back once in the response.

Retention cleanup:

```text theme={null}
> How much data would I free up by deleting requests older than
  90 days from the /api/legacy/* routes?
```

`preview_deletion` returns per-table row counts. Claude reads them, summarizes, and only invokes `destroy_data` (with `confirm: "YES"`) after you approve.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The client says the server failed to connect">
    Most common cause: a stale or mistyped token. Regenerate it in the dashboard and re-add the MCP server. Some clients cache server metadata — remove and re-add the server entry to force a refresh.
  </Accordion>

  <Accordion title="Tenant calls return 'App not found'">
    The `app-id` in the URL must match an app your user account has team access to. Copy the ID directly from the Apps page — it's the last segment of the app detail URL.
  </Accordion>

  <Accordion title="A destructive tool returned a 'refusing to X' error">
    Destructive tools require `confirm: "YES"` (exact string, uppercase, no punctuation). This is deliberate — it prevents a misinterpreted prompt from wiping an app.
  </Accordion>

  <Accordion title="Mutating calls succeed but the dashboard is stale">
    Tools flush the app cache, so the dashboard refreshes within its normal polling interval (30s for list pages, 10s for dashboards). If it lingers longer, hard-refresh the browser tab.
  </Accordion>

  <Accordion title="I don't see the activity in the timeline">
    The timeline supports filtering by `actor_type`. MCP-authored actions share the timeline with human ones and are only hidden if the filter excludes them.
  </Accordion>
</AccordionGroup>
