diff --git a/apps/dashboard/src/app/(dashboard)/agents/mcp/page.tsx b/apps/dashboard/src/app/(dashboard)/agents/mcp/page.tsx index e45329d2..fc58bea7 100644 --- a/apps/dashboard/src/app/(dashboard)/agents/mcp/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/agents/mcp/page.tsx @@ -287,9 +287,11 @@ export default function Page() { - Every client you authorize via OAuth shows up under{" "} - Settings > Integrations as a connected app. Check - which apps have access and revoke them at any time. +

+ Every client you authorize via OAuth shows up under{" "} + Settings > Integrations as a connected app. + Check which apps have access and revoke them at any time. +

View connected apps diff --git a/apps/dashboard/src/components/chat/chat-suggestions.tsx b/apps/dashboard/src/components/chat/chat-suggestions.tsx index c8fb6d3e..58713f9f 100644 --- a/apps/dashboard/src/components/chat/chat-suggestions.tsx +++ b/apps/dashboard/src/components/chat/chat-suggestions.tsx @@ -1,9 +1,13 @@ +import { ModelContextProtocolIcon } from "@openstatus/icons/brand"; import { Badge } from "@openstatus/ui/components/ui/badge"; import { Button } from "@openstatus/ui/components/ui/button"; +import NextLink from "next/link"; +import { Note, NoteButton } from "@/components/common/note"; import { Section, SectionDescription, + SectionGroup, SectionHeader, SectionTitle, } from "@/components/content/section"; @@ -21,33 +25,45 @@ type Props = { export function ChatSuggestions({ onSelect }: Props) { return ( -
- - openstatus assistant - - Ask about your workspace, draft status reports, or debug your failing - monitors.{" "} - - Test it out and share your feedback. - {" "} - - BETA - - - -
- {SUGGESTIONS.map((s) => ( - - ))} -
-
+ +
+ + openstatus assistant + + Ask about your workspace, draft status reports, or debug your + failing monitors.{" "} + + Test it out and share your feedback. + {" "} + + BETA + + + +
+ {SUGGESTIONS.map((s) => ( + + ))} +
+
+
+ + + Prefer your own tools? Connect Claude Code, Cursor or ChatGPT to this + workspace through the openstatus MCP server. + + Set up MCP + + +
+
); } diff --git a/apps/dashboard/src/components/common/note.tsx b/apps/dashboard/src/components/common/note.tsx index 243a0366..274fd2dd 100644 --- a/apps/dashboard/src/components/common/note.tsx +++ b/apps/dashboard/src/components/common/note.tsx @@ -4,7 +4,7 @@ import { cn } from "@openstatus/ui/lib/utils"; import { type VariantProps, cva } from "class-variance-authority"; const noteVariants = cva( - "flex items-center gap-2 rounded-lg border [&>svg]:shrink-0 [&>svg]:text-current", + "flex items-center gap-2 rounded-lg border [&_strong]:font-semibold [&>svg]:shrink-0 [&>svg]:text-current", { variants: { variant: { diff --git a/apps/web/public/.well-known/agent-skills/openstatus-mcp/SKILL.md b/apps/web/public/.well-known/agent-skills/openstatus-mcp/SKILL.md index fe04b948..41eeddba 100644 --- a/apps/web/public/.well-known/agent-skills/openstatus-mcp/SKILL.md +++ b/apps/web/public/.well-known/agent-skills/openstatus-mcp/SKILL.md @@ -1,15 +1,38 @@ --- name: openstatus-mcp -description: Use the openstatus MCP server to read and update status pages, status reports, and maintenance windows from any Model Context Protocol client (Claude, ChatGPT, Cursor, etc.). Use when an AI assistant needs to post an incident, append an update, resolve a report, or schedule maintenance for an openstatus workspace. +description: Use the openstatus MCP server to read monitors, notification channels, private locations and audit logs, and to read and update status pages, status reports, and maintenance windows from any Model Context Protocol client (Claude, ChatGPT, Cursor, Codex, opencode, etc.). Use when an AI assistant needs to check a monitor's health, post an incident, append an update, resolve a report, or schedule maintenance for an openstatus workspace. --- # openstatus MCP server -The openstatus MCP server is a remote, streamable-HTTP endpoint at `https://api.openstatus.dev/mcp`. It exposes 9 tools scoped to a single workspace. +The openstatus MCP server is a remote, streamable-HTTP endpoint at `https://api.openstatus.dev/mcp`. It exposes 19 tools (17 on plans without the `audit-log` feature) scoped to a single workspace. ## Connect -Add this to your MCP client config (Claude Desktop, Cursor, ChatGPT custom connector, etc.): +### OAuth (recommended for interactive clients) + +Point the client at the endpoint with no header. The server answers `401` with a `WWW-Authenticate` header, and any client implementing the MCP authorization spec (Claude.ai, Claude Desktop, Claude Code, ChatGPT, Cursor, Codex, opencode, VS Code) registers itself, opens the consent screen, and exchanges the code for an `os_oat_…` bearer token via PKCE. On the consent screen you pick the **workspace** and the **access** level (read-only or read & write). Nothing to copy. + +```json +{ + "mcpServers": { + "openstatus": { + "type": "http", + "url": "https://api.openstatus.dev/mcp" + } + } +} +``` + +```bash +claude mcp add --transport http --scope user openstatus https://api.openstatus.dev/mcp +``` + +Connected apps are listed under **Settings > Integrations > Connected apps**, where they can be revoked at any time. + +### API key (CI, cron, headless agents) + +Send an openstatus API key in the `x-openstatus-key` header. It is the same key used by the CLI, REST API, and Terraform provider; create one in **Settings > General**, in the **API Keys** card. When both credentials are present, the header wins. ```json { @@ -25,27 +48,62 @@ Add this to your MCP client config (Claude Desktop, Cursor, ChatGPT custom conne } ``` -The `x-openstatus-key` header is the same API key used by the CLI, REST API, and Terraform provider. Generate one in **Settings → API Tokens**. There is no separate MCP OAuth flow. +### Scopes + +Both credentials carry a scope. **Read-only** credentials only see `list_*` and `get_*` tools in `tools/list`; mutation tools are not registered and cannot be called. **Read & write** exposes every tool. An API key's scope is fixed at creation; an OAuth grant's scope is chosen on the consent screen. ## Tools -- `list_status_pages` — discover pages the workspace owns. +### Status pages + +- `list_status_pages` — discover pages the workspace owns. Resolves the `pageId` required by the mutation tools. - `list_page_components` — discover the components on a page (id, name, type, linked monitor). Resolves the `pageComponentIds` accepted by the create/update tools below. -- `list_status_reports` — read incidents on a page. -- `list_maintenances` — read scheduled maintenance windows. + +### Status reports + +- `list_status_reports` — read incidents on a page (`filter: "active" | "all"`, paginated). - `create_status_report` — open a new incident. - `add_status_report_update` — post an update on an open incident. -- `resolve_status_report` — close an incident. -- `update_status_report` — edit incident metadata. -- `create_maintenance` — schedule a maintenance window. +- `update_status_report` — edit incident metadata (title, status, components) without a public update. +- `resolve_status_report` — close an incident with a final update. + +### Maintenance + +- `list_maintenances` — read scheduled maintenance windows (paginated). +- `create_maintenance` — schedule a maintenance window (`from` / `to` as ISO 8601). + +### Monitors (read-only) + +- `list_monitors` — list monitors with `activeIncidentCount`. Resolves the numeric `monitorId` the other monitor tools require. +- `get_monitor` — full configuration: URL, regions, periodicity, retries, notification channels, tags. +- `get_monitor_status` — per-region current health (active / degraded / error). +- `get_monitor_summary` — success/degraded/error counts and p50–p99 latency over `1d`, `7d`, or `14d`. +- `list_response_logs` — recent per-region check results (status code, latency) over `1d`, `7d`, or `14d`. HTTP monitors only. +- `get_response_log` — one check in full: timing breakdown, redacted headers, error, assertion results. + +### Workspace (read-only) + +- `list_notifications` — notification channels and the monitors wired to each. Credentials are never exposed. +- `list_private_locations` — private locations with status and `lastSeenAt`. Agent tokens are never exposed. +- `list_audit_logs` — audit-log entries, last 14 days, optional `entityType` + `entityId` filter. Requires the `audit-log` plan feature. +- `get_audit_log` — before/after snapshots and `changedFields` for one entry. Requires the `audit-log` plan feature. + +### Resources + +The server also exposes three read-only resources on any credential: `openapi-specification`, `mcp-server-reference`, and `site-index` (`llms.txt`). + +## Rules for mutations -Every mutation tool requires an explicit `notify: true | false` argument. The model must decide whether subscribers are paged. There is no implicit default. +- Every publishing tool (`create_status_report`, `add_status_report_update`, `resolve_status_report`, `create_maintenance`) requires an explicit `notify: true | false` argument. There is no default; the model must ask the user whether subscribers are paged. `update_status_report` has no `notify` field. +- Notifications dispatch inside the same call. An update posted with `notify: false` can never be re-sent later. +- Never guess a numeric id. Call `list_status_pages` and `list_page_components` first; ids outside the workspace come back as `NOT_FOUND`. +- Draft the title, status, message and components, show the draft to the user, confirm `notify`, then call the tool. ## Audit -All MCP mutations are written to the workspace audit log with `actor_type = 'mcp'`, so any change can be traced back to a key, a user, and the MCP transport. +All MCP mutations are written to the workspace audit log with `actor_type = 'mcp'`, `actor_id` set to the credential (API key id or `oat_`), and `actor_user_id` set to the person behind it, so any change can be traced back to a key or OAuth grant, a user, and the MCP transport. ## Reference -- Full tool schemas and error codes: +- Full tool schemas, OAuth endpoints and error codes: - Product overview: