MCP Server
Connect statusas to AI assistants via the Model Context Protocol
The statusas MCP server lets AI assistants (Claude.ai, Claude Desktop, Claude Code, ChatGPT, Cursor, and other Model Context Protocol clients) read and manage your status pages, status reports, and maintenance windows directly from a conversation.
Endpoint
https://api.statusas.lt/mcpThe transport is Streamable HTTP (stateless). The server speaks JSON-RPC 2.0 over a single endpoint that accepts GET, POST, and DELETE.
Authentication
The MCP server accepts two credentials. OAuth is the default for interactive clients; the API key header stays for CI and headless agents.
For a guided walkthrough of registering, signing in, and verifying the connection, see Connect statusas to your coding agent.
OAuth (recommended)
Point your client at https://api.statusas.lt/mcp with no header. The server answers 401 with a WWW-Authenticate header pointing at its protected-resource metadata, and any client that implements the MCP authorization spec (Claude.ai, Claude Desktop, Claude Code, ChatGPT, Cursor, VS Code) takes it from there:
- The client registers itself once (dynamic client registration) and opens the authorization URL in your browser.
- You sign in to statusas if needed, pick the workspace to connect and the access level (read-only or read & write), and click Approve.
- The client exchanges the code for an access token (PKCE
S256) and starts calling tools withAuthorization: Bearer os_oat_….
There is nothing to copy. The token is scoped to the workspace you picked at consent, so a user in several workspaces connects each one as a separate app.
| Access token | os_oat_ prefix, valid for 1 hour, refreshed automatically by the client |
| Refresh token | 90 days sliding, rotated on every refresh |
| Grant | one live grant per client and user; connecting again replaces it |
| Revoke | Settings > Integrations > Connected apps; the next call fails with 401 |
A connection lives in Settings > Integrations > Connected apps with the client name, granted access, who connected it, and when it was last used. Members revoke their own connections, owners and admins revoke any. Removing a member from the workspace revokes their connections too.
API key (fallback)
Send an statusas API key in the x-statusas-key header. This is the same key the REST API, ConnectRPC, CLI, and Terraform provider use, and the right choice when no browser is available: CI pipelines, cron jobs, or an agent running on a server.
x-statusas-key: os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGet a key from the dashboard's Settings > General, in the API Keys card. When both credentials are present, the header wins.
Scopes
Both credentials carry a scope that controls what tools the MCP server exposes:
- Read-only — the server only registers read tools (
list_*andget_*). Mutation tools (create_*,update_*,add_*,resolve_*) are not advertised intools/listand cannot be called. - Read & write — every tool is available.
With OAuth you choose the scope on the consent screen; a client may request read & write and you can still downgrade it to read-only. On an API key the scope is set at creation time and is immutable: to change it, revoke the key and issue a new one.
For AI agents that should only observe state — health summaries, paging on-call, drafting communication — grant Read-only. 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 credential. Mutations write to the audit log with actor_type = "mcp" (see 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 (readOnlyHint, destructiveHint, idempotentHint) so well-behaved clients can decide whether to confirm, cache, or surface differently.
Resources
Alongside its tools, the server exposes a small set of read-only MCP resources — public
documents carrying no workspace data, so they are available on any credential and any scope.
List them with resources/list and fetch one with resources/read:
| Resource | URI | Contents |
|---|---|---|
openapi-specification | https://api.statusas.lt/openapi.json | The full OpenAPI document, served from the binary rather than fetched. |
mcp-server-reference | https://docs.statusas.lt/reference/mcp-server | This page. |
site-index | https://www.statusas.lt/llms.txt | llms.txt: product context, pricing, and a linked index of every page on statusas.lt. |
Remotely fetched resources are capped at a 5-second timeout and never resolve empty: on a failure the read returns a short pointer back to the same URI rather than a blank body.
Notifying subscribers
Every publishing tool — create_status_report, add_status_report_update, resolve_status_report, create_maintenance — has a required notify: boolean field, with 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. update_status_report edits metadata only and carries no notify field at all.
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:
- Draft the title/status/message/components.
- Show the draft to the user.
- Ask explicitly whether to notify subscribers.
- 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 Code
claude mcp add --transport http --scope user statusas https://api.statusas.lt/mcpRun /mcp inside Claude Code, select statusas, and choose Authenticate. Your browser opens the consent screen; approve, and the tools appear. Step-by-step in Connect statusas to Claude Code.
For a headless setup, pass the API key instead: --header "x-statusas-key: os_…".
Configure Claude.ai and Claude Desktop
Claude.ai and Claude Desktop share one connector list. Open Settings > Connectors > Add custom connector, enter https://api.statusas.lt/mcp as the URL, and click Connect. Approve on the consent screen and enable the connector in the chat's tool picker.
If you need an API key instead (Claude Desktop only), bridge the server through mcp-remote in claude_desktop_config.json:
{
"mcpServers": {
"statusas": {
"command": "npx",
"args": [
"mcp-remote",
"https://api.statusas.lt/mcp",
"--header",
"x-statusas-key: ${API_KEY}"
],
"env": {
"API_KEY": "os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
}The key is held in env and referenced via ${API_KEY} because mcp-remote parses header args before shell expansion. Fully quit and relaunch Claude Desktop afterwards.
Configure Cursor
Add the server to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"statusas": {
"url": "https://api.statusas.lt/mcp"
}
}
}Cursor shows the server as Needs login; click it to run the OAuth flow. To use an API key instead, add "headers": { "x-statusas-key": "os_…" } to the entry.
Configure opencode
Add the server to opencode.json (project) or ~/.config/opencode/opencode.json (global), then run opencode mcp auth statusas to complete the OAuth flow:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"statusas": {
"type": "remote",
"url": "https://api.statusas.lt/mcp",
"enabled": true
}
}
}To use an API key instead, add "headers": { "x-statusas-key": "{env:STATUSAS_API_KEY}" } and "oauth": false to the entry. Step-by-step in Connect statusas to opencode.
Configure Codex
codex mcp add statusas --url https://api.statusas.lt/mcp
codex mcp login statusasThe first command writes the server to ~/.codex/config.toml, which the Codex CLI, the Codex IDE extension, and the ChatGPT desktop app all share; the second opens the consent screen. For a headless setup, pass the API key instead: --header "x-statusas-key=os_…", or env_http_headers = { "x-statusas-key" = "STATUSAS_API_KEY" } in a committed .codex/config.toml. Step-by-step in Connect statusas to Codex.
Configure ChatGPT
In ChatGPT on the web, switch on Developer mode under Settings > Security and login, then open Settings > Connectors > Create, enter https://api.statusas.lt/mcp as the MCP server URL with OAuth authentication, and complete the consent screen. Enable the connector per chat from the + menu under Developer mode. Step-by-step in Connect statusas to ChatGPT.
OAuth endpoints
For client authors. statusas is an OAuth 2.1 authorization server for the /mcp resource, with public clients only.
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
GET /.well-known/oauth-protected-resource/mcp | Protected resource metadata for /mcp (RFC 9728) |
POST /oauth/register | Dynamic client registration (RFC 7591) |
GET /oauth/authorize | Authorization request; redirects to the consent screen |
POST /oauth/token | authorization_code and refresh_token grants; form or JSON body |
POST /oauth/revoke | Token revocation (RFC 7009); accepts either token of a grant |
response_type=codewith PKCES256is required. Scopes arereadandwrite; an authorization request without a scope asks forwrite.- Clients are public (
token_endpoint_auth_method: none). There are no client secrets. - Dynamic registration only accepts redirect URIs on loopback hosts,
httpsURLs onstatusas.lt,claude.ai,chatgpt.com,cursor.comand their subdomains, or thecursor://,vscode://, andvscode-insiders://schemes. Loopback redirects match on everything but the port (RFC 8252). - Any other client can skip registration and use a Client ID Metadata Document: pass a public
httpsURL with a path asclient_id. The document is fetched on every authorization request, must echo its own URL asclient_id, and itsredirect_urisare used as-is. Domain ownership replaces the allowlist. - Errors follow RFC 6749 (
{ "error", "error_description" }), not the statusas API envelope.
Self-hosting
The issuer is fixed by configuration, not derived from the request host, so metadata stays stable behind proxies. Set both on the API server:
OAUTH_ISSUER=https://api.example.com # origin of /mcp and /oauth/*
DASHBOARD_URL=https://app.example.com # serves /oauth/consentOutside production OAUTH_ISSUER defaults to http://localhost:3000 and DASHBOARD_URL to http://localhost:3001 — the ports of pnpm dev. The Docker stack binds different ports; see How to Self-Host statusas for the values that go with it.
Errors
Errors map by severity:
- Recoverable (
NOT_FOUND,VALIDATION,CONFLICT,LIMIT_EXCEEDED,PRECONDITION_FAILED) come back as a tool result withisError: 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_reportsandlist_maintenancesuse offset pagination:page(1-indexed, default 1) andperPage(default 50, max 200). The response'spagination.totalPagestells the LLM whether more pages exist.list_status_pagesis unpaginated (workspaces typically have a handful).list_monitorsandlist_audit_logspage viaperPage(max 50);list_notificationsviaperPage(max 200);list_private_locationsviaperPage(max 100);list_response_logsvialimit(max 100) andoffset.- Every tool invocation is one server call and counts against the rate limits below.
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 credential's stable identifier (not the workspace id). For an API key this is the key id; for an OAuth connection it isoat_<grant id>. Trace a specific credential withWHERE actor_id = '<id>'.actor_user_id= the statusas user behind the credential: who created the API key (custom keys only), or who approved the OAuth consent. Attribute mutations back to a person with a join to theusertable.
Connecting and revoking an app are audited too, as oauth_grant.create and oauth_grant.delete.
Rate limits
MCP requests share the per-token limits of the HTTP API. A rejected request gets a plain 429 with a Retry-After header rather than a JSON-RPC error; see API rate limits.