Skip to content

MCP Server (AI Integration) ​

The Model Context Protocol (MCP) lets AI assistants like Claude, Claude Code, Cursor, and other MCP-compatible clients query your Hoppla monitoring data directly. Ask "Are all my monitors healthy?" or "What incidents happened this week?" and get answers grounded in your live data.

Most tools are read-only. A small, explicitly listed set of write actions is also available — each needs a token scope ending in :write, and they are the only way MCP can change anything. Nothing deletes.

How it works ​

Hoppla exposes a Streamable HTTP MCP endpoint at:

https://app.hoppla.dev/mcp

There are two ways to connect, and which you use depends on your client:

  • OAuth — for clients with a "connector" UI that sign you in through a browser (claude.ai, Claude Desktop). You paste the URL, approve a consent screen, and you're done. No token to copy or store. This is the recommended path where your client supports it.
  • API token — for headless or command-line clients (Claude Code, Cursor, mcp-remote, CI, your own scripts). You create a token once and send it as a Bearer header.

Both reach the same endpoint and behave identically once connected. What a client can see and do is decided by scopes, not by how it authenticated: a token or grant only reads the data its scopes allow, and only performs the write actions its :write scopes allow.

Custom portal domains ​

If your team uses a custom portal domain (e.g. monitoring.yourcompany.com), use it in place of app.hoppla.dev for either method:

https://monitoring.yourcompany.com/mcp

Useful for reseller-managed teams whose users may not know app.hoppla.dev. Authentication, tenant isolation, and the available tools are identical on both. OAuth discovery is relative to whichever domain you connect to, so a token granted on your portal is bound to that portal and cannot be replayed against app.hoppla.dev, or the reverse.

Point your client at https://app.hoppla.dev/mcp and let it handle the sign-in. Nothing to copy.

claude.ai (web and desktop) ​

  1. Open Settings → Connectors and choose Add custom connector.
  2. Enter the URL: https://app.hoppla.dev/mcp.
  3. Claude sends you to Hoppla's consent screen. Sign in if you aren't already (your normal login, including passkey or 2FA).
  4. On the consent screen you choose:
    • Read-only (preselected) or Read and act. Read-only can query everything; "Read and act" additionally allows the write tools (acknowledge/update incidents, snooze and run checks, schedule maintenance, publish status-page updates). It never grants team, billing, or settings changes.
    • Which teams the connector may reach. Tick individual teams, or "including any team I am added to later" for an all-teams grant that picks up new teams automatically.
  5. Approve. The window tells you it's connected and you can close it.

Claude Desktop (connector UI) ​

Recent Claude Desktop has the same custom-connector flow as claude.ai — add the connector with the URL above and approve the consent screen. If your Claude Desktop has no connector UI, use the API-token method below with mcp-remote.

What OAuth does for you ​

  • Access renews itself. The access token lasts 8 hours and is refreshed silently in the background (refresh window: 30 days). You won't be asked to sign in again during normal use. If a connector sits unused for more than 30 days, you reconnect once.
  • Least privilege by default. The consent screen preselects read-only, whatever the client requested, so acting access is always a deliberate choice.
  • Revoke any time. Open the Developers section of your dashboard: every connected app is listed with a Disconnect button. Disconnecting ends the whole grant immediately — the live access token and its refresh token — so the connector stops working at once, not in 8 hours.

Connect with an API token ​

For clients that don't drive OAuth themselves. Create a token in Settings → API Tokens (see API Tokens), give it the scopes you need, and send it as a Bearer header.

TIP

Use a dedicated token for each integration, so you can revoke MCP access without disturbing your other API clients. Grant only the scopes you need — read scopes for a read-only assistant.

Claude Code ​

bash
claude mcp add hoppla \
  --transport http \
  --url https://app.hoppla.dev/mcp \
  --header "Authorization: Bearer YOUR_TOKEN"

Cursor ​

Add to your Cursor MCP configuration (.cursor/mcp.json in your project, or global settings):

json
{
  "mcpServers": {
    "hoppla": {
      "url": "https://app.hoppla.dev/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN"
      }
    }
  }
}

Claude Desktop without a connector UI (mcp-remote) ​

Older Claude Desktop speaks only the stdio transport, so it needs a bridge. mcp-remote (requires Node.js) forwards to the HTTP endpoint. Edit the config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
json
{
  "mcpServers": {
    "hoppla": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://app.hoppla.dev/mcp",
        "--header",
        "Authorization: Bearer YOUR_TOKEN"
      ]
    }
  }
}

Restart Claude Desktop after saving.

TIP

If npx is slow to start, install it once (npm install -g mcp-remote) and set "command": "mcp-remote" with "args": ["https://app.hoppla.dev/mcp", "--header", "Authorization: Bearer YOUR_TOKEN"].

Any other client ​

Any client that speaks Streamable HTTP can connect:

SettingValue
URLhttps://app.hoppla.dev/mcp
TransportStreamable HTTP
AuthAuthorization: Bearer YOUR_TOKEN, or OAuth if the client supports it

Working across several teams ​

A token or OAuth grant can be authorized for one team or for several at once (with OAuth you pick this on the consent screen; for an API token it's set when the token is created).

When a connection can reach more than one team, the list and dashboard tools fan out automatically and return one block per team under a by_tenant field, so every row says which team it belongs to. To work within a single team, pass a tenant_id argument (get the ids from list-accessible-tenants) and the result is scoped to that team alone.

You can only ever reach the teams the connection is authorized for — never any other team, even if a tool is called with another team's resource id. A resource id that belongs to a team you can't reach returns exactly the same "not found" as an id that doesn't exist, so the tools never reveal whether something exists elsewhere.

Available tools ​

43 tools. Which ones respond depends on your scopes.

Monitors ​

ToolDescription
list-monitorsList monitors, filterable by type, tag, or search term. Paginated (max 50 per call); the response carries has_more
list-monitor-tags-and-groupsThe tag and group names actually in use — call this before filtering list-monitors by tag
get-monitor-detailsA single monitor with its checks and latest results
get-monitor-uptimeUptime for the last 24h, 7d, and 30d. Says so explicitly when uptime does not apply (e.g. a cron/agent heartbeat monitor) rather than returning bare nulls
get-monitor-reportUptime over an explicit date range: overall percentage, incident count, day-by-day breakdown. Ranges over 90 days are trimmed to the most recent 90
get-monitor-performanceResponse-time percentiles (avg, p50, p95, p99) over 24h, 7d, 30d, and 90d, computed from real results
get-monitor-certificateSSL certificate details and expiry
get-monitor-dns-historyDNS records and recent changes
get-monitor-broken-linksBroken-link scan results
get-check-resultsPaginated result history for one check
get-check-timeseriesResponse-time timeseries for a check over a period — per-bucket avg/min/max (plus p50/p95 and timing phases for short windows)
get-monitor-check-detailLatest result for one check type: lighthouse, geo, web_vitals, security_headers, domain_expiry, robots_txt, sitemap, redirects, mixed_content, dnsbl, ping, tcp, or application_health. Reports check_configured so "no such check" and "no data yet" are distinguishable

Incidents ​

ToolDescription
list-incidentsIncidents, filterable by status, monitor, or archive state
get-incident-detailsA single incident with its full update timeline

Dashboards, logs & other resources ​

ToolDescription
list-cron-monitorsCron heartbeat monitors with status and schedule
list-agent-monitorsServer agent monitors with hostname, OS, and resource status
list-status-pagesStatus pages with their monitors and visibility
list-maintenance-windowsMaintenance windows, filterable by active/upcoming/past
get-dashboard-statsAggregate stats: uptime, response time, monitor counts, total checks. Availability failures are counted as downtime; failing informational checks (e.g. Lighthouse) are listed separately under failing_informational_checks so a slow audit is not mistaken for an outage
get-dashboard-eventsEvent timeline for the last 7 days: incidents created/resolved, maintenance started/ended, SSL-expiry warnings
get-monitor-logsAnalyse a monitor's access logs: overview, timeseries, peak-hours, top, or errors. Requires log shipping. Visitor IP addresses are withheld by default (they are your visitors' personal data) and returned only when include_client_ips is passed

Notifications & escalation ​

ToolDescription
list-notification-channelsConfigured channels (email, Slack, webhook, etc.). Secrets are masked
list-notification-rulesRules mapping events to channels
list-escalation-policiesMulti-step escalation policies and their wait times
list-on-call-schedulesOn-call schedules and their rotations
get-current-on-callWho is on call right now

Team & audit ​

ToolDescription
list-accessible-tenantsThe teams this connection can reach
list-team-membersA team's members and their roles
get-audit-logWho changed what and when — monitors, incidents, status pages, channels, team members, tokens, and more, including actions taken through this MCP server. Needs settings:read. Full change diffs are admin-only

Write actions ​

Each needs the matching :write scope, a plan with full API access, and a team that is not paused. A read-only connection can call none of them.

ToolScopeWhat it does
acknowledge-incidentincidents:writeAcknowledges an open incident and stops escalation so the on-call rotation is no longer paged. Refused if already resolved or already acknowledged
add-incident-updateincidents:writePosts an update to an incident timeline (max 5000 chars, max 200 per incident). Passing resolved closes the incident and sends the all-clear to subscribers
snooze-checkchecks:writeSilences one check for 1–10080 minutes (up to 7 days). The check keeps running; it just stops alerting. End it early with unsnooze-check
unsnooze-checkchecks:writeEnds a check's snooze early. Safe to call on a check that isn't snoozed
trigger-check-runchecks:writeRuns one check now. At most once per 60s per check, 10 runs per minute overall
create-maintenance-windowmaintenance:writeSchedules a maintenance window so planned work raises no incidents. Title, start, end (≤ 30 days apart), and optionally the monitors it covers. Shows on your status pages
post-status-page-updatestatus-pages:writePublishes a status-page update — publicly visible and emailed to every confirmed subscriber. Max 5 per minute, 500 per page. Per-locale translations must be published from the dashboard
set-check-enabledchecks:writeTurns a check on or off. Disabling stops it running (a gap in uptime history) — to keep the data and only silence alerts, use snooze-check
set-incident-stateincidents:writeLifecycle actions: snooze (60/240/480/1440 min), unsnooze, archive (resolved only), or unarchive
update-incidentincidents:writeChanges title, severity, or status without posting to the public timeline. resolved closes it and sends the all-clear, once
create-incidentincidents:writeOpens an incident by hand. This notifies people — the team's incident.created rules fire. Max 100 open per team, 5 per minute
create-monitormonitors:writeCreates a monitor with its template's checks. Counts against the plan's monitor limit; the interval cannot go below the plan minimum; private and internal addresses are refused
update-monitormonitors:writeRenames, retargets, re-intervals, pauses, or resumes a monitor. A monitor's type cannot change after creation
update-maintenance-windowmaintenance:writeReschedules a window, changes its monitors, or lifts it with is_active: false

A write is never applied to more than one team. If your connection can reach several teams, pass tenant_id to the write tool — it refuses rather than guessing. Every write, and every refused attempt, is recorded in the target team's audit log with the tool used and the token behind it.

Example conversations ​

Ask in plain language; the assistant picks the right tools, chains several when needed, and summarizes.

Health & uptime — "Are any of my monitors down right now?" · "What's the average uptime across all my monitors this month?" · "Which monitors had the worst uptime in the last 30 days?"

Performance & trends — "What's the p95 response time for my API monitor?" · "Show the response-time trend for the checkout page over 7 days." · "How are my Core Web Vitals on the homepage?"

Certificates, domains & links — "Which SSL certificates expire in the next 30 days?" · "Have any DNS records changed recently?" · "Are there broken links on my marketing site?"

Incidents — "What incidents were created in the last 7 days?" · "Give me the full timeline for the latest incident on the API monitor."

Cron & agents — "Did any scheduled task miss its last run?" · "How's CPU and memory on my reported servers?"

Alerting & on-call — "Which channels are configured, and are any disabled?" · "Walk me through how an unacknowledged incident escalates." · "Who is on call right now?"

Multiple teams — "Which teams can this connection reach?" · "Compare uptime across all of my teams this month."

A good opener: "Give me a health summary — anything down, any incidents in the last 24 hours, and any certificates expiring soon." The assistant fans out across the relevant tools and returns one readable digest.

Rate limiting ​

The MCP endpoint has its own limits, separate from the REST API:

ScopeLimit
Per token60 requests per minute
Per team200 requests per minute (across all tokens)

Write tools carry a second, tighter per-team throttle on top of this. Exceeding a limit returns 429 Too Many Requests.

Security ​

  • Reads by default, writes only where listed. Every tool outside "Write actions" is read-only, and no tool deletes anything.
  • Least-privilege consent. The OAuth consent screen preselects read-only regardless of what the client asked for; acting access is always a deliberate choice, and it never includes team, billing, or settings changes.
  • Scope-gated. A tool works only if the connection holds the matching scope; a write needs a :write scope.
  • Writes target exactly one team, are audited (success and refusal alike), and are checked against your role in that team — being an admin in one team grants nothing in another.
  • Audience-bound tokens. An OAuth token is bound to the domain it was granted on and is rejected anywhere else, so a grant on a reseller portal cannot be used against app.hoppla.dev, or the reverse.
  • Team isolation. A connection reads only the teams it is authorized for. Another team's resource id returns the same "not found" as a nonexistent one.
  • Credential redaction. Webhook URLs, agent tokens, and channel secrets are never exposed.
  • Revocable. Disconnect an OAuth app from Developers in your dashboard, or delete an API token in Settings → API Tokens — either cuts access immediately.