MCP SERVER · AGENT-FIRST · FREE FOR INDIVIDUALS

The monitor your agents set up for themselves.

LastPing's MCP server lets an AI agent create its own dead-man's-switch monitor in a single conversation — calling create_monitor and get_ping_instructions to wire in the check-in pings on the spot. Nothing to install. Hosted at mcp.lastping.dev (Streamable HTTP). Works with Claude, Cursor, and Windsurf.

Connect your client — copy and paste

The server speaks Model Context Protocol over Streamable HTTP. Add a URL and a Bearer token — nothing else to install. Get an API key at app.lastping.dev → Settings → API Keys.

Claude Desktop

Add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/):

{ "mcpServers": { "lastping": { "url": "https://mcp.lastping.dev", "headers": { "Authorization": "Bearer lp_your_key" } } } }
Claude Code CLI

One command — adds LastPing to your user-scope MCP config:

claude mcp add \ --transport http \ --scope user \ lastping \ https://mcp.lastping.dev \ --header "Authorization: Bearer lp_…"
Cursor

Add to ~/.cursor/mcp.json (user-scope) or .cursor/mcp.json (project-scope):

{ "mcpServers": { "lastping": { "url": "https://mcp.lastping.dev", "headers": { "Authorization": "Bearer lp_your_key" } } } }
Windsurf

Add to ~/.codeium/windsurf/mcp_config.json (note: Windsurf uses serverUrl):

{ "mcpServers": { "lastping": { "serverUrl": "https://mcp.lastping.dev", "headers": { "Authorization": "Bearer lp_your_key" } } } }

One conversation. The agent instruments itself.

The MCP server closes the loop: the agent doesn't just read monitoring data, it creates the monitor and wires in the pings. Three tool calls. No dashboard. No human in the loop.

Create the monitor

Call create_monitor with a name, a stable slug (makes re-runs idempotent — upsert, not duplicate), and a schedule. Heartbeat monitors expect a ping every N seconds or on a cron; CI monitors track pipeline runs; HTTP monitors probe a URL.

create_monitor({ "name": "nightly-summary-agent", "slug": "nightly-summary-agent", "schedule_kind": "cron", "cron_expr": "0 2 * * *", "grace_s": 1800 }) → created · ping_url: https://ping.lastping.dev/<id>

Get ping snippets

Call get_ping_instructions with the monitor's UUID. The tool returns the ping URL plus ready-to-run curl_success, curl_start, curl_fail and curl_step commands — no URL construction, no format guessing. This is the tool that makes one-conversation self-instrumentation possible.

get_ping_instructions({ "id": "<monitor-uuid>" }) → { "curl_success": "curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<id>", "curl_start": "curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<id>/start", "curl_fail": "curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<id>/fail", "curl_step": "curl -fsS -m 10 --retry 3 -o /dev/null \"https://ping.lastping.dev/<id>/step?rid=$RID&step=db+migrate\"", "step_timeout_s": null, "how_to_steps": "... Stall detection is OFF on this monitor ..." }

Wire pings into the work

The agent adds the success ping to the end of its workflow, the fail ping on any error path, and the start ping at launch to arm overrun detection. From that point on — crash, hang, stall, or a scheduled run that silently stops firing — LastPing opens an incident and alerts the operator. No human check-in required.

# In the agent's wrapper script or tool call: RID=$(uuidgen) curl -fsS ".../<id>/start?rid=$RID" # arms overrun + never-finished detection # ... do a stage of the work ... curl -fsS ".../<id>/step?rid=$RID&step=plan" # still moving — resets the stall clock # ... do the rest ... curl -fsS ".../<id>?rid=$RID" # success — closes any open incident # on error path: curl -fsS ".../<id>/fail?rid=$RID" # opens incident immediately with failure detail

Step pings are optional and opt-in: they only produce an alert if the monitor sets step_timeout_s, which get_ping_instructions reports back so the agent knows whether anything is watching. A step never extends the run budget — an agent that reports progress forever still overruns.


The MCP tool surface

Every tool is implemented in github.com/tp322d/lastping-app and ships in both the hosted server and the self-host stdio binary.

  • Monitors create_monitor — create or upsert a monitor by slug (heartbeat · ci · http); upsert-by-slug makes it idempotent and safe for agents to retry list_monitors — list all monitors in the project with id, name, slug, status, and ping_url get_monitor — get a single monitor's full config by UUID update_monitor — update an existing monitor's schedule and config by UUID, including step_timeout_s to arm or disarm stall detection delete_monitor — permanently delete a monitor (cannot be undone) pause_monitor — pause alerting; the monitor still receives pings but does not open incidents resume_monitor — resume a paused monitor; alerting resumes on the next missed ping snooze_monitor — set or clear a maintenance window (by duration e.g. "1h", RFC 3339 timestamp, or clear=true)
  • Incidents list_incidents — list recent incidents for a monitor, newest first; an open incident has closed_at=null; includes the failure detail captured by the CI/CD integration or a /fail ping get_run_history — recent runs of a monitor, each with its run id (rid) and the progress steps reported under it, in the order they happened. This is what turns a stalled incident into an answer: the last step on the timeline is the one the run wedged in.
  • The failure loop list_open_incidents — the agent's failure inbox: everything currently broken on the monitors one agent owns, read at the start of its next run. No webhook, no chat integration, no mailbox to wire up. What the entry carries is what the agent could not work out from its own run: failure_signature.occurrences — first time or fortieth repeat, which is the fact that decides retry versus escalate — plus the step it died on, the exit code it reported, and how long the run took compared with its own normal (8.2x the typical run, not 41 minutes). Every enrichment degrades to absent rather than guessing, and absent means no evidence: a missing duration_vs_normal never means "normal", and a missing exit_code never means "exited cleanly". add_incident_note — the write-back, and the half a human actually reads. Instead of "check failed at 03:04", the person who gets paged reads "failed because the upstream API returned 503; same failure as the last three nights; I retried twice and stopped". The instruction is to write back whether or not the agent could fix it — an agent that reports only its successes leaves a record worse than none, because every unexplained incident then reads as one nobody has looked at. Notes are append-only: a correction is a new note, never an edit, because a diagnosis whose history a reader cannot trust is not evidence.
  • Destinations list_destinations — list all notification destinations in the project (email, webhook, Slack, Discord, Telegram, ntfy, Pushover, Teams, Google Chat) create_destination — create a notification destination; non-email kinds are ready immediately; email sends a confirmation link before it can be routed update_destination — update a destination's name and/or config in place; only the fields you pass are changed; the kind cannot be changed — delete and recreate instead test_destination — deliver a synthetic test alert through a destination to verify credentials before routing delete_destination — permanently delete a destination; any routes pointing at it go with it
  • Status pages list_status_pages — list the project's public status pages with their slugs and which monitors each one shows create_status_page — create a public status page from a set of monitors, served on its own slug update_status_page — change a status page's title, description or the monitors it lists delete_status_page — permanently delete a status page; the monitors it listed are unaffected
  • Routing set_route — route a monitor's down / recovery / fail / every-run / success / started / blocked / note alerts to a set of destinations; replaces the full set for that event type; empty list clears routing
  • Alert templates get_alert_templates — get a monitor's custom alert message templates by event type (or event-type/cause); an empty result means all alerts use the built-in defaults set_alert_template — set or clear a single template on a monitor (read-modify-write; all other templates are preserved); an empty string resets that entry to the built-in default
  • API keys create_api_key — create a new API key; the plaintext key is returned once and cannot be retrieved again list_api_keys — list all API keys in the project; never returns plaintext values, only the prefix revoke_api_key — permanently revoke an API key; it stops authenticating immediately and this cannot be undone
  • Agent registry register_agent — register a new autonomous agent, returning its id, slug and wire-up instructions in one call; call once per worker, not once per monitor list_agents — list every registered agent with its status rolled up live from the monitors it owns: down, blocked, late, running, up, pending or idle get_agent — get a single agent by UUID, including its live status rollup update_agent — update an agent's name/description by UUID (merge-patch: only fields you pass are changed); slug is immutable delete_agent — permanently delete an agent from the registry; its monitors are NOT deleted, they survive unowned
  • Self-instrumentation get_ping_instructions — the flagship tool: returns the monitor's ping URL plus ready-to-run curl_success, curl_start, curl_fail and curl_step snippets, a run_example showing the whole run under one run id, and whether stall detection is armed on this monitor. Call this right after create_monitor. The agent creates a monitor and immediately receives the check-in code to embed in its own workflow — one conversation, zero dashboards. declare_run_expectations — commit, at the start of a run, to the criteria that run will be judged by, before the outcome is knowable. A success ping whose body does not meet them is recorded as a failed run whatever the exit code claims, and the incident names the criterion that was not met. The declaration is immutable — a second attempt for the same run is refused — because an agent that could revise its criteria after seeing the outcome would just be grading itself again. Declaring nothing is allowed and leaves the monitor's own assertions in force.
  • Discovery discover_monitors_reconcile — the tool that removes the form. The agent scans the repository or the host itself (LastPing never reads either) for the four things that schedule work — crontab lines, github-actions on.schedule.cron entries, k8s-cronjob manifests and systemd-timer units — and sends the list. Back comes a three-way diff: created, existing and orphaned. Existing monitors are returned completely unmodified, so an expect_every_s somebody tuned by hand survives every scan; orphaned monitors — ones whose source the scan did not find — are reported and left running, because this call has no delete path at all. That is what makes it safe to run nightly, and a scan you can run nightly is drift detection rather than a setup wizard: "you added a scheduled workflow last week and nothing is watching it." The agent is expected to propose what it found and get agreement before it calls, and to read the host's real timezone (timedatectl show -p Timezone --value) for crontab and systemd sources, which fire in local time — a guessed UTC there arms the deadline about twenty hours early, every day.
  • Monitoring as code export_terraform — renders what exists as Terraform HCL, with an import block per resource. The MCP-to-HCL flow ↓

Ping API (plain HTTP, no SDK needed): GET /<id> (success) · /<id>/start (arms overrun detection) · /<id>/fail (POST error body, up to 64 KB, stored on the incident) · /<id>/<exit-code> (0 = success, non-zero = fail) · /<id>/step?rid=<run-id>&step=<name> (progress inside a started run; arms stall detection) · ?rid=<run-id> (pair start with its later success/fail, record duration). All pings hit https://ping.lastping.dev/.


export_terraform — from a conversation to a pull request

Monitors an agent creates over MCP are real, but they are invisible to the repo. export_terraform closes that loop: it renders what exists as Terraform HCL, pairs every resource with an import block, and hands it back as text the agent can commit.

export_terraform({ "tag": "agent:claude" }) # Optional arguments: # tag — only monitors carrying this exact tag # monitor_slug — a single monitor by slug # include — monitors,destinations,routes,templates,status_pages

What comes back is ready to commit. The import block is the important part — the first terraform plan adopts the monitor that already exists rather than proposing to recreate it:

# Generated by LastPing. # Secrets are not exported — the API never returns them. # Import blocks adopt your existing resources instead of recreating them. import { to = lastping_monitor.nightly_backup id = "nightly-backup" } resource "lastping_monitor" "nightly_backup" { name = "Nightly backup" slug = "nightly-backup" schedule_kind = "cron" cron_expr = "0 3 * * *" tz = "UTC" grace_s = 1800 tags = ["env:prod", "team:platform"] }
  • Secrets are never in the output The API does not return destination credentials, so each one is emitted as a var. reference with a matching sensitive = true variable block and a loud TODO. An empty string would silently ship a destination that delivers nothing, so the export refuses to guess.
  • The same export from the API or the dashboard GET /api/v1/export/terraform with the same query parameters, or Export as Terraform in the app. Same generator, same output.
  • Then it is ordinary Terraform The official provider is lastping-dev/lastping on the public Terraform Registry. See the Terraform provider guide, the agent-readable terraform.md, or why monitoring as code matters more with agents.

Prompt cookbook — ask your agent

These prompts work out of the box once LastPing MCP is connected. Paste as-is or adapt for your stack.

"Monitor my nightly Postgres backup and alert me on Telegram if it doesn't check in by 3am."

uses: create_monitor · create_destination · test_destination · set_route · get_ping_instructions

"Add a LastPing dead-man's-switch to the deploy pipeline you just wrote — daily at midnight, 30-minute grace."

uses: create_monitor · get_ping_instructions

"Create a monitor for this nightly summary agent — runs at 2am UTC, alert me on Slack if it goes silent or fails."

uses: create_monitor · create_destination · test_destination · set_route · get_ping_instructions

"Check all my monitors. Which ones have had incidents in the past week?"

uses: list_monitors · list_incidents

"Snooze the nightly-backup monitor for 4 hours while I run a maintenance window."

uses: list_monitors · snooze_monitor

"Set up a LastPing HTTP uptime monitor for api.example.com, probing every 60 seconds."

uses: create_monitor

"Create a webhook destination for my on-call endpoint and route the production-deploy monitor's down and fail events to it."

uses: list_monitors · create_destination · test_destination · set_route

"Instrument yourself: register a heartbeat for this agent at '0 6 * * *' (6am daily, 45-minute grace), get the ping snippets, and add them to your run loop."

uses: create_monitor · get_ping_instructions


Prefer to self-host? Use the stdio binary.

The same tools are available as a single Go binary — no npm, no runtime, no Docker required. MIT-licensed and open source at github.com/tp322d/lastping-app.

Install

# requires Go 1.22+ go install github.com/tp322d/lastping-app/cmd/lastping-mcp@latest

Add to your client config (stdio)

Replace the url + headers block with command + env in your claude_desktop_config.json or .mcp.json:

{ "mcpServers": { "lastping": { "command": "lastping-mcp", "env": { "LASTPING_API_KEY": "lp_your_key_here" } } } }

Optional env vars: LASTPING_BASE_URL (default: https://app.lastping.dev) and LASTPING_PING_HOST (default: https://ping.lastping.dev) — useful when pointing the binary at a different LastPing environment, such as staging.


Questions

Front-loaded answers — the most important fact first.

  • What is the LastPing MCP server?

    A hosted Model Context Protocol endpoint at https://mcp.lastping.dev (Streamable HTTP). Point your AI client at it with a Bearer API key and the agent gains tools for creating monitors, querying incidents, managing alert destinations, configuring routing, and — the flagship — instrumenting its own dead-man's-switch check-in loop. Nothing to install; get a key at app.lastping.dev.

  • How is this different from other monitoring MCP servers?

    Competitors (Hyperping, Checkly, Sentry, Cronitor) ship MCP servers for reading and triaging existing monitors created by humans. LastPing is designed for agent-created monitoring: the agent calls create_monitor to register its own heartbeat, then get_ping_instructions to receive ready-to-run curl_success / curl_start / curl_fail / curl_step snippets — and wires them into its own workflow. The agent owns the monitor it set up. No dashboard visit required.

  • Which AI clients are supported?

    Any client supporting Streamable HTTP MCP: Claude Desktop, Claude Code (claude mcp add --transport http …), Cursor, and Windsurf. For stdio (local process), any client supporting stdio-based MCP — configure with command + env instead of url + headers using the go install binary described in the self-host section above.

  • Does the agent need an SDK or library to send pings?

    No. The MCP server is for creating and managing monitors. Once a monitor exists, pinging it is a plain HTTP GET to https://ping.lastping.dev/<uuid>. The get_ping_instructions tool returns ready-to-run curl commands the agent can embed in any shell script, tool call, or workflow step. No SDK, no import, no language dependency — one HTTP request is all that is needed.

  • Is the LastPing MCP server free?

    Yes. LastPing is free for individuals — no monitor cap, no feature gate. The hosted MCP server at mcp.lastping.dev is included. The open-source stdio binary is MIT-licensed. Get an API key at app.lastping.dev → Settings → API Keys.

MCP SERVER · AGENT-FIRST · FREE FOR INDIVIDUALS

Let your agent set up its own monitor.

Get a free API key, paste one config block, and your agent gains the tools for creating and managing dead-man's-switch monitors — no dashboard, no human in the loop.