Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
MDX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200---category: Referencetitle: MCP Serverdescription: Connect openstatus to AI assistants via the Model Context Protocol---
The openstatus MCP server lets AI assistants (Claude Desktop, Cursor, and other [Model Context Protocol](https://modelcontextprotocol.io) clients) read and manage your status pages, status reports, and maintenance windows directly from a conversation.
## Endpoint
```https://api.openstatus.dev/mcp```
The transport is **Streamable HTTP** (stateless). The server speaks JSON-RPC 2.0 over a single endpoint that accepts `GET`, `POST`, and `DELETE`.
## Authentication
Every request must include your openstatus API key in the `x-openstatus-key` header โ the same key REST and ConnectRPC use. There is no separate MCP-only credential.
```httpx-openstatus-key: os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx```
Get a key from the dashboard's **Settings โ General โ API Keys**.
### Scopes
Each API key carries a scope that controls what tools the MCP server exposes:
- **Read-only** โ the server only registers read tools (`list_*` and `get_*`). Mutation tools (`create_*`, `update_*`, `add_*`, `resolve_*`) are not advertised in `tools/list` and cannot be called.- **Read & write** โ every tool is available.
Scope is set at key creation time and is **immutable**. To change a key's scope, revoke it and issue a new one.
For AI agents that should only observe state โ health summaries, paging on-call, drafting communication โ issue a **Read-only** key. The server gates writes at two layers (the `tools/list` filter is the visible UX; the service-layer scope check is the boundary), so a misconfigured client can't accidentally mutate.
## Tools
The server exposes 19 tools (17 on plans without the `audit-log` feature), grouped by resource and scoped to the workspace tied to your API key. Mutations write to the audit log with `actor_type = "mcp"` (see [Audit log](#audit-log)).
### Pages
| Tool | Type | Purpose ||------------------------|------|---------|| `list_status_pages` | read | List public status pages with their slug and id. Used to discover the `pageId` required by mutation tools. || `list_page_components` | read | List components on a status page with their id, name, type (`monitor` / `static`), and linked monitor. Used to discover the `pageComponentIds` accepted by `create_status_report`, `update_status_report`, and `create_maintenance`. |
### Status reports
| Tool | Type | Purpose ||----------------------------|----------|---------|| `list_status_reports` | read | List status reports newest-first. `filter: "active" \| "all"` (defaults to active = excludes resolved). Paginated via `page` (1-indexed) and `perPage`; response carries a `pagination` object with `page`, `perPage`, `totalSize`, and `totalPages`. || `create_status_report` | mutation | Create a new status report on a status page with an initial public update. || `add_status_report_update` | mutation | Append a public update to an existing status report and bump its status. || `update_status_report` | mutation | Edit a report's title, status, or affected components without posting a public update. || `resolve_status_report` | mutation | Mark a report resolved and post a final public update with the supplied message. |
### Maintenance
| Tool | Type | Purpose ||----------------------|----------|---------|| `list_maintenances` | read | List maintenance windows newest-first. Paginated via `page` (1-indexed) and `perPage`; response carries a `pagination` object with `page`, `perPage`, `totalSize`, and `totalPages`. || `create_maintenance` | mutation | Schedule a maintenance window (`from` / `to` are ISO 8601 strings). |
### Monitors
| Tool | Type | Purpose ||-----------------------|------|---------|| `list_monitors` | read | List monitors newest-first, including `activeIncidentCount`. Used to discover the numeric `monitorId` the other monitor tools require. || `get_monitor` | read | Full configuration for one monitor: URL, regions, periodicity, retry/timeout, notification channels, tags. Does not return latency or status. || `get_monitor_status` | read | Per-region current health (active / degraded / error). No time window. || `get_monitor_summary` | read | Aggregate success/degraded/error counts, p50โp99 latency, and `lastPingAt` over `1d` (default), `7d`, or `14d`. || `list_response_logs` | read | Recent per-region HTTP check results โ request status, status code, latency โ over `1d` (default), `7d`, or `14d`. HTTP monitors only; `limit` โค 100. || `get_response_log` | read | Full detail of one check: URL, timing breakdown (dns/connect/tls/ttfb/transfer), redacted response headers, error message, assertion results. |
### Notifications
| Tool | Type | Purpose ||----------------------|------|---------|| `list_notifications` | read | List notification channels and the monitors each one is wired to. Channel credentials are never exposed. |
### Private locations
| Tool | Type | Purpose ||--------------------------|------|---------|| `list_private_locations` | read | List the workspace's private locations with their name, status (`active` / `error`), metadata, and `lastSeenAt`. Agent tokens are never exposed. |
### Audit
Registered only when the workspace plan includes the `audit-log` feature โ otherwise these tools are absent from `tools/list`.
| Tool | Type | Purpose ||-------------------|------|---------|| `list_audit_logs` | read | List audit-log entries (mutating actions) newest-first, bounded to the last 14 days. Optional `entityType` + `entityId` filter. || `get_audit_log` | read | Full before/after snapshots and `changedFields` for a single audit-log entry. |
The MCP client gates every tool call behind your approval โ the server does not gate again. Each tool also carries [MCP annotations](https://modelcontextprotocol.io/specification/server/tools#tool-annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) so well-behaved clients can decide whether to confirm, cache, or surface differently.
### Notifying subscribers
Every mutation tool has a **required** `notify: boolean` field โ there is no default. The tool's input schema rejects calls that omit it, which forces the LLM to make an explicit choice (and therefore ask the user) before firing.
This required-field behaviour is specific to MCP. The dashboard AI assistant and the Slack agent wrap these same tools in an approval step that strips `notify` from the model-facing schema and injects it from a human toggle defaulting to `false`. MCP exposes the raw schema, so the caller must supply `notify` explicitly.
Notifications dispatch as part of the same call. There is no separate notify tool: if you create a status report or append an update with `notify: false`, that update will **never** reach subscribers โ you cannot retroactively notify the same update later. This matches the dashboard and Slack agent semantics.
The mutation and the notify dispatch are sequential, not transactional. The mutation persists first; if the notify step then throws (transient provider issue, partial outage of an integration), the response carries `notified: false` and the row stays.
`notified: true` means the dispatch call returned without throwing โ **not** that every subscriber received a message. If the workspace plan doesn't include subscriber notifications, the service is a silent no-op and the response will still report `notified: true`. Treat the field as "the dispatch ran cleanly," not as a delivery receipt.
| Tool | What `notify: true` sends ||----------------------------|---------------------------|| `create_status_report` | Notification for the initial update || `add_status_report_update` | Notification for the new update || `resolve_status_report` | Resolution notification || `create_maintenance` | Maintenance scheduled notification || `update_status_report` | n/a โ metadata-only edit, never has a notify path |
The required `notify` field, combined with the mandatory draft-and-confirm workflow in each tool's description, encodes the contract that LLMs must:
1. Draft the title/status/message/components.2. Show the draft to the user.3. Ask **explicitly** whether to notify subscribers.4. Only call the tool once both content and notify are confirmed.
The tool's response includes a `notified: boolean` field so the assistant can confirm what actually went out. If the workspace plan doesn't include subscriber notifications, `notify: true` is a no-op inside the service (no error, just nothing dispatched).
### Lookup-before-mutate
`create_status_report` and `create_maintenance` require a `pageId`, and they (plus `update_status_report`) accept an optional `pageComponentIds`. The tool descriptions instruct the model to call `list_status_pages` for the `pageId` and `list_page_components` for component ids first; **never** type a numeric id you don't know โ make the assistant resolve it. Ids that don't belong to the workspace (or, for components, to the supplied page) come back as `NOT_FOUND`.
## Configure Claude Desktop
Claude Desktop launches MCP servers as local stdio processes, so the remote HTTP server is bridged through [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) โ a small open-source proxy that translates Claude Desktop's stdio calls into HTTP requests against `https://api.openstatus.dev/mcp`. You'll need Node.js 18+ on your PATH so Claude Desktop can run `npx`.
Add the server to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):
```json{ "mcpServers": { "openstatus": { "command": "npx", "args": [ "mcp-remote", "https://api.openstatus.dev/mcp", "--header", "x-openstatus-key: ${API_KEY}" ], "env": { "API_KEY": "os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } } }}```
The API key is held in `env` and referenced via `${API_KEY}` in the `--header` value because `mcp-remote` parses header args before shell expansion โ inlining the key after the colon breaks parsing.
Fully quit and relaunch Claude Desktop (`Cmd+Q` on macOS, **File โ Quit** on Windows). The openstatus tools appear in the tool picker after restart.
## Configure Cursor
In Cursor, open **Settings โ MCP โ Add Server**:
```json{ "openstatus": { "type": "http", "url": "https://api.openstatus.dev/mcp", "headers": { "x-openstatus-key": "os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } }}```
## Errors
Errors map by severity:
- **Recoverable** (`NOT_FOUND`, `VALIDATION`, `CONFLICT`, `LIMIT_EXCEEDED`, `PRECONDITION_FAILED`) come back as a tool result with `isError: true`. The model can read the message and retry with corrected input.- **Transport-level** (`UNAUTHORIZED`, `FORBIDDEN`, `INTERNAL`, malformed input) come back as a JSON-RPC error.
Error messages are not redacted โ the consumer is an LLM that benefits from the detail.
## Limits
- `list_status_reports` and `list_maintenances` use offset pagination: `page` (1-indexed, default 1) and `perPage` (default 50, max 200). The response's `pagination.totalPages` tells the LLM whether more pages exist. `list_status_pages` is unpaginated (workspaces typically have a handful).- `list_monitors` and `list_audit_logs` page via `perPage` (max 50); `list_notifications` via `perPage` (max 200); `list_private_locations` via `perPage` (max 100); `list_response_logs` via `limit` (max 100) and `offset`.- No per-key rate limiting today. Treat MCP usage like REST: one server call per tool invocation.
## Audit log
Every mutation invoked through MCP appears in the workspace audit log with:
- `actor_type = "mcp"` โ slice by surface: `WHERE actor_type = 'mcp'`.- `actor_id` = the API key's stable identifier (not the workspace id) โ trace a specific key with `WHERE actor_id = '<keyId>'`.- `actor_user_id` = the openstatus user who created the API key (custom keys only) โ attribute mutations back to a person with a join to the `user` table.