statusas docs
Reference

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/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

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.

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:

  1. The client registers itself once (dynamic client registration) and opens the authorization URL in your browser.
  2. You sign in to statusas if needed, pick the workspace to connect and the access level (read-only or read & write), and click Approve.
  3. The client exchanges the code for an access token (PKCE S256) and starts calling tools with Authorization: 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 tokenos_oat_ prefix, valid for 1 hour, refreshed automatically by the client
Refresh token90 days sliding, rotated on every refresh
Grantone live grant per client and user; connecting again replaces it
RevokeSettings > 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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Get 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_* and get_*). Mutation tools (create_*, update_*, add_*, resolve_*) are not advertised in tools/list and 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

ToolTypePurpose
list_status_pagesreadList public status pages with their slug and id. Used to discover the pageId required by mutation tools.
list_page_componentsreadList 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

ToolTypePurpose
list_status_reportsreadList 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_reportmutationCreate a new status report on a status page with an initial public update.
add_status_report_updatemutationAppend a public update to an existing status report and bump its status.
update_status_reportmutationEdit a report's title, status, or affected components without posting a public update.
resolve_status_reportmutationMark a report resolved and post a final public update with the supplied message.

Maintenance

ToolTypePurpose
list_maintenancesreadList maintenance windows newest-first. Paginated via page (1-indexed) and perPage; response carries a pagination object with page, perPage, totalSize, and totalPages.
create_maintenancemutationSchedule a maintenance window (from / to are ISO 8601 strings).

Monitors

ToolTypePurpose
list_monitorsreadList monitors newest-first, including activeIncidentCount. Used to discover the numeric monitorId the other monitor tools require.
get_monitorreadFull configuration for one monitor: URL, regions, periodicity, retry/timeout, notification channels, tags. Does not return latency or status.
get_monitor_statusreadPer-region current health (active / degraded / error). No time window.
get_monitor_summaryreadAggregate success/degraded/error counts, p50–p99 latency, and lastPingAt over 1d (default), 7d, or 14d.
list_response_logsreadRecent per-region HTTP check results — request status, status code, latency — over 1d (default), 7d, or 14d. HTTP monitors only; limit ≤ 100.
get_response_logreadFull detail of one check: URL, timing breakdown (dns/connect/tls/ttfb/transfer), redacted response headers, error message, assertion results.

Notifications

ToolTypePurpose
list_notificationsreadList notification channels and the monitors each one is wired to. Channel credentials are never exposed.

Private locations

ToolTypePurpose
list_private_locationsreadList 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.

ToolTypePurpose
list_audit_logsreadList audit-log entries (mutating actions) newest-first, bounded to the last 14 days. Optional entityType + entityId filter.
get_audit_logreadFull 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:

ResourceURIContents
openapi-specificationhttps://api.statusas.lt/openapi.jsonThe full OpenAPI document, served from the binary rather than fetched.
mcp-server-referencehttps://docs.statusas.lt/reference/mcp-serverThis page.
site-indexhttps://www.statusas.lt/llms.txtllms.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.

ToolWhat notify: true sends
create_status_reportNotification for the initial update
add_status_report_updateNotification for the new update
resolve_status_reportResolution notification
create_maintenanceMaintenance scheduled notification
update_status_reportn/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 Code

claude mcp add --transport http --scope user statusas https://api.statusas.lt/mcp

Run /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 statusas

The 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.

EndpointPurpose
GET /.well-known/oauth-authorization-serverAuthorization server metadata (RFC 8414)
GET /.well-known/oauth-protected-resource/mcpProtected resource metadata for /mcp (RFC 9728)
POST /oauth/registerDynamic client registration (RFC 7591)
GET /oauth/authorizeAuthorization request; redirects to the consent screen
POST /oauth/tokenauthorization_code and refresh_token grants; form or JSON body
POST /oauth/revokeToken revocation (RFC 7009); accepts either token of a grant
  • response_type=code with PKCE S256 is required. Scopes are read and write; an authorization request without a scope asks for write.
  • Clients are public (token_endpoint_auth_method: none). There are no client secrets.
  • Dynamic registration only accepts redirect URIs on loopback hosts, https URLs on statusas.lt, claude.ai, chatgpt.com, cursor.com and their subdomains, or the cursor://, vscode://, and vscode-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 https URL with a path as client_id. The document is fetched on every authorization request, must echo its own URL as client_id, and its redirect_uris are 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/consent

Outside 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 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.
  • 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 is oat_<grant id>. Trace a specific credential with WHERE 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 the user table.

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.

On this page