/ guides / uptime-monitoring-with-ai-agents

Set up uptime monitoring from Claude Code or Codex

Connect Claude Code or Codex to Fettle over MCP, then let the agent create monitors and heartbeats, silence a deploy and triage an outage in the terminal.

Updated

Uptime monitoring from Claude Code or Codex means your coding agent creates and manages the checks itself: you describe what to watch, and it calls a monitoring API through MCP. Fettle is uptime monitoring for developers with a first-class MCP server, so Claude Code, Codex and any other MCP client can set up HTTP, ping, TCP, DNS and SSL checks plus heartbeat and cron monitoring, silence alerts around a deploy, and read incidents back when something breaks. Connect it once and the whole loop happens in the same terminal session as the code:

claude mcp add --transport http fettle https://api.fettle.sh/mcp

This guide is the workflow: what the agent calls, in what order, and where it stops. Installing for other clients, and every tool listed one by one, is on Set up the Fettle MCP server. If uptime monitoring itself is new, start with what uptime monitoring is.

How do you connect Claude Code or Codex to Fettle?

Add the hosted endpoint https://api.fettle.sh/mcp and sign in with OAuth, or pass an API key as a bearer token. Nothing is installed. Clients that cannot speak remote MCP run the fettle-mcp npm package over stdio instead. Both channels expose the same tools, because both read one generated contract.

In Claude Code, run the command above, then type /mcp inside Claude Code and authenticate: the browser opens Fettle's consent screen, where you pick the organization and Read only or Read and write. Codex takes the same URL:

codex mcp add fettle --url https://api.fettle.sh/mcp

Codex opens the same consent screen when it detects OAuth; if the browser does not open, run codex mcp login fettle. If you would rather use an API key, or need the local package, both clients take one command:

claude mcp add fettle --env FETTLE_API_KEY=fettle_your_key_here -- npx -y fettle-mcp
codex mcp add fettle --env FETTLE_API_KEY=fettle_your_key_here -- npx -y fettle-mcp

The local package needs Node.js 20 or newer. Key-based remote setup for both clients, the JSON config for Claude Desktop, Cursor and Windsurf, and the ChatGPT connector are covered step by step in the MCP setup docs.

Should the agent get a read-only or a write key?

Give it the narrowest access the session needs. A read key, or an OAuth connection with Read only, lists monitors, incidents, check results and uptime. Creating, changing, pausing or acknowledging anything needs write scope. So does check_target, which changes nothing but sends a real probe to the target host.

In the dashboard a key's scope is set when you create it: for write access, create a write key rather than widening a read one. A key belongs to one organization, so the agent cannot wander into another team's monitors. A key can also carry an expiry date and an IP allow-list, which suits a key you hand to an agent on a CI box (API keys has the details). Your role still applies on top of the scope: the OAuth consent screen refuses Read and write to someone who is a Viewer in the organization.

A sensible split: a read-only connection for the triage sessions you run every day, and write access for the occasional setup session.

What does a setup session look like?

You describe the services in plain words and the agent turns that into tool calls. It reads your plan limits first, probes each URL once to catch typos, creates the monitors and the heartbeat, then binds alert channels. Fettle's own agent guide, sent to the client when it connects, tells it to follow that order.

A realistic request:

Monitor these three endpoints and the nightly backup:
- https://www.example.com
- https://api.example.com/health (expect 200 and the word "ok")
- https://app.example.com/login
The backup runs at 03:00 every night and takes about 20 minutes.
Alert the on-call Slack channel only. Tag everything env:prod.

What the agent calls, in order:

  1. get_plan_usage returns the plan's limits and current usage: how many monitors and heartbeats you have left, the shortest allowed interval, max_regions per monitor and the allowed_regions codes. Unless you name regions, the agent uses every allowed code up to the per-monitor cap. On Free that means 20 monitors checked every 3 minutes from 1 region, and 3 heartbeats.
  2. check_target probes each URL once from a region Fettle picks, without saving anything. It returns status, status_code, response_time_ms, error and failure_kind. A down result does not block creation, but it is the moment to catch https://api.exmaple.com.
  3. list_tags shows the tags already in use, so the agent reuses env:prod instead of inventing prod.
  4. list_channels returns each channel's id, type, label and whether it is verified and active. The agent picks the Slack channel's id. Leave channel_ids empty and every verified, active channel is alerted. Email is not a channel here: every alert also goes to the account email of whoever created the monitor.
  5. create_monitor, once per endpoint, or bulk_create_monitors for up to 100 in one all-or-nothing call. For the health endpoint the arguments look like this:
{
  "name": "API health",
  "type": "HTTP",
  "target": "https://api.example.com/health",
  "interval_seconds": 300,
  "timeout_seconds": 10,
  "regions": ["eu-central"],
  "config": { "expected_status_codes": [200], "keyword": "ok" },
  "channel_ids": ["<slack channel id from list_channels>"],
  "tags": ["env:prod"]
}
  1. create_heartbeat for the backup. The job runs every 24 hours, so period_seconds is 86400; to be alerted an hour after a missed run, grace_seconds is 3600. The result carries the ping_url, and the agent can add the ping to your crontab itself:
0 3 * * * /opt/backup/run.sh && curl -fsS --retry 3 https://api.fettle.sh/v1/heartbeat/YOUR_TOKEN > /dev/null

When it is done, the agent should tell you the interval and regions it chose and offer to change them with update_monitor. Two things it cannot change later: a monitor's type and target are fixed after creation, so a wrong URL means delete and recreate. A limit you hit comes back as a 403 naming the limit, and the agent is told not to retry it unchanged. Heartbeat sizing in more depth is in the cron job monitoring guide.

How do you silence alerts before a deploy?

Ask the agent for a maintenance window. It calls create_maintenance_window with a start time, a duration in minutes and a scope: one or more monitors, or the whole organization. While the window is in effect checks keep running, but no incident opens and no alert goes out. Maintenance windows start on Pro.

We deploy the API at 22:00 Berlin time tonight, about 30 minutes.
Silence the API health monitor for that, nothing else.

The agent finds the monitor's id with list_monitors, then creates a window with scope set to MONITOR, dtstart in local wall-clock time (for example 2026-11-03T22:00:00) with timezone set to Europe/Berlin, and duration_minutes set to 30. A timestamp with a Z or a UTC offset is refused, because the timezone field already says where the clock is.

For a recurring window, such as every Sunday at 03:00, the agent passes a repeat rule and should call preview_maintenance_window first to show you the next occurrences before saving. list_active_maintenance answers "what is silenced right now". Windows do not cover heartbeats: for a job you know will not run, the agent calls pause_heartbeat. On a plan without maintenance windows the fallback is pause_monitor, which stops checks entirely until resume_monitor. The trade-offs are in the maintenance windows guide.

How does the agent triage an outage?

It walks from the symptom to the cause in four calls. list_monitors filtered to DOWN shows what is broken, list_check_results shows which regions fail and with what status code or error, get_incident gives the structured cause and whether alerts were delivered, and acknowledge_incident stops the repeat alerts while someone works on it.

Something is wrong with the API. What's down, since when, and why?
  1. list_monitors with status set to ["DOWN", "DEGRADED"]. Each row has the monitor's id, name, target, status and last_checked_at. DOWN means every fresh region agreed the check failed for the configured number of rounds; DEGRADED means at least one region keeps returning a non-UP result without all of them agreeing, and it never opens an incident or sends an alert. Multi-region monitoring explains why Fettle waits for agreement.
  2. list_check_results for the monitor, newest first. Each result has region, checked_at, status, status_code, response_time_ms and error_message. This is where "503 from every region" and "timeout from one region only" stop looking alike.
  3. get_incident with the incident id from list_incidents. It returns started_at, the cause (a timeout, a DNS failure, an invalid certificate, an unexpected status code, a missing keyword, a missed heartbeat…), cause_detail with the raw check error, and every alert attempt for the incident with its channel type, SENT or FAILED status and error. "Did the Slack alert actually go out?" is answered here.
  4. acknowledge_incident marks it as being handled. Repeat alerts for open incidents, sent on Plus and up, stop; the recovery alert still goes out when the monitor comes back. The incident closes itself on recovery, not on acknowledgement.

After you ship a fix, check_now re-arms the monitor for the next scheduler tick instead of waiting out its interval, so the agent can confirm recovery in the same session. If your status page needs a note, the agent can draft it with create_status_page_incident, but that can email the page's subscribers, so it is told to confirm the text with you first.

What can't the agent do?

Anything that is configuration rather than monitoring stays in the dashboard. Adding or verifying notification channels, status page settings and layout, inviting members, creating API keys and changing the plan are dashboard-only. The agent can read channels and status pages, bind channels to monitors, and post incidents on a status page.

A few more limits worth knowing before you hand over a session:

  • No bulk delete. bulk_pause_monitors, bulk_resume_monitors and bulk_update_monitors take up to 100 ids, but deletion is one delete_monitor call at a time, on purpose.
  • Config is replaced whole. update_monitor changes only the fields you pass, but a config you pass replaces the stored one entirely, so the agent reads the monitor with get_monitor first and resends every config field it wants to keep.
  • One organization per connection. To work across two organizations, add the server twice under different names, each authorized to its own organization.
  • Shared rate limit. Tool calls come out of the same per-minute budget as your other API keys, and a connection made by signing in shares a cap of half that budget with the same user's other app connections. A Rate limited reply names the wait; the agent waits and retries.

What each plan includes, from monitor counts to the shortest interval, is on pricing. The other guides in this series, including how to monitor an MCP server you run yourself, are collected under guides.

Questions

Can Claude Code or Codex create uptime monitors on their own?
Yes, once Fettle is connected as an MCP server with write access. The agent probes each target with check_target, reads your plan limits with get_plan_usage, then calls create_monitor or create_heartbeat. With a read-only key it can only list and inspect.
Does the Fettle MCP server cost extra or have its own rate limit?
No extra cost and no separate MCP allowance. The MCP server is available on every Fettle plan, including Free, and each tool call is an ordinary API call: it spends one unit of the organization's per-minute request budget, shared with your scripts and other API keys. Apps you connect by signing in also share a cap of half that budget per user.
Can the agent add a Slack channel or edit a status page?
No. Notification channels, status page settings, members, API keys and billing are managed only in the Fettle dashboard. The agent can list channels and bind them to monitors, read status pages, and open or update incidents on them.

Start monitoring in a minute

The free plan checks up to 20 monitors as often as every 3 minutes from 1 region, and emails you when one breaks. See pricing for the paid intervals, or follow the quickstart to do it from the API.