heartbeat-monitor

Dead-man's-switch for cron jobs & AI agents. Import a crontab to arm one silent-miss alert per job.

Should I use this

Quality & Safety

A
Description quality
100%
Schema completeness
99%
Naming quality
97%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~1,915Tokens (tool definitions)
~1.6 KBTypical response size
Moderate attention impact (1.50% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "heartbeat-monitor": {
      "url": "https://cronping.cronping-oren.workers.dev/mcp"
    }
  }
}

Remote endpoints

https://cronping.cronping-oren.workers.dev/mcpstreamable-http

What it can do

Tool inventory

Tools (7)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟡create_heartbeat(name, period_seconds, grace_seconds, email, webhook_url, ...)

Create a Cronping heartbeat monitor (dead-man's-switch). Returns a ping_url to call on each successful run of your agent loop, worker, or cron job, plus a claim_token to manage it. If pings stop arriving within period+grace, Cronping raises an alert. No account required. After creating, send one verification ping (call ping_heartbeat with the returned id) to confirm setup — the check flips from 'new' to UP so you know it's wired correctly. Alternatively, pass pull_url to make a PULL check: Cronping fetches that URL on schedule and alerts if it fails — for targets that can't call a ping URL (a health endpoint, status page, or API).

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Label for what is monitored, e.g. \"nightly-backup\" or \"research-agent-loop\"."
    },
    "period_seconds": {
      "type": "number",
      "description": "How often you expect a ping, in seconds (min 60). Default 86400 (daily)."
    },
    "grace_seconds": {
      "type": "number",
      "description": "Extra slack before marking DOWN, in seconds. Default 3600."
    },
    "email": {
      "type": "string",
      "description": "Email address for DOWN and recovery alerts. STRONGLY RECOMMENDED — without an email or webhook_url, Cronping tracks status but cannot notify anyone when the job stops, which defeats the purpose. Use your operator's email."
    },
    "webhook_url": {
      "type": "string",
      "description": "https webhook (Slack/Discord/generic) for DOWN and recovery alerts. Set this OR email so someone is actually notified when the monitored job goes silent."
    },
    "stuck_after": {
      "type": "number",
      "description": "Optional. Flip to STUCK if the progress_token passed to ping_heartbeat stays identical for this many consecutive runs (default 3, 0 disables). Catches zombie runs that keep pinging but make no progress."
    },
    "pull_url": {
      "type": "string",
      "description": "Optional. If set, creates a PULL check instead: Cronping itself fetches this URL every period_seconds and alerts if it fails — use for a target that can't call a ping URL (a public health endpoint, status page, or API). No ping needed."
    },
    "pull_contains": {
      "type": "string",
      "description": "Optional (pull checks only). The fetched response body must contain this text to count as UP; otherwise Cronping alerts."
    }
  },
  "required": [
    "name"
  ]
}
🟡ping_heartbeat(id, signal, progress_token)

Send a heartbeat signal to a Cronping check. signal="success" (default) marks it UP and resets the timer; "start" records that a run began (for duration); "fail" marks it DOWN immediately and alerts. Optionally pass progress_token (a digest of your run's actual output) on success pings: if the same token repeats for several consecutive runs, the check flips to STUCK — catching a "zombie" job that keeps pinging on schedule while its real work has stalled.

Input Schema

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The check id returned by create_heartbeat."
    },
    "signal": {
      "type": "string",
      "enum": [
        "success",
        "start",
        "fail"
      ],
      "description": "success | start | fail. Default success."
    },
    "progress_token": {
      "type": "string",
      "description": "Optional. A short digest/hash of this run's output (e.g. last-processed id, row count, content hash). If it stays identical across stuck_after consecutive runs, the check flips to STUCK and alerts."
    }
  },
  "required": [
    "id"
  ]
}
🟢get_heartbeat_status(id, claim_token)

Get the live status of a Cronping check (up/down/new, last ping time, ping count, and whether an alert channel is set).

Input Schema

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "claim_token": {
      "type": "string",
      "description": "The claim_token returned by create_heartbeat."
    }
  },
  "required": [
    "id",
    "claim_token"
  ]
}
🟡set_heartbeat_alert(id, claim_token, email, webhook_url)

Add or change the alert channel on an EXISTING Cronping check (use this instead of creating a duplicate). Sets the email and/or webhook (Slack/Discord/generic https) that Cronping notifies when the monitor goes silent or recovers. Without an alert channel a check tracks status but can't warn you — call this once per check to make the dead-man's-switch actually protect you.

Input Schema

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The check id returned by create_heartbeat."
    },
    "claim_token": {
      "type": "string",
      "description": "The claim_token returned by create_heartbeat."
    },
    "email": {
      "type": "string",
      "description": "Email address to notify (e.g. the operator/owner). Pass empty string to clear."
    },
    "webhook_url": {
      "type": "string",
      "description": "Optional https webhook (Slack/Discord/generic) to notify. Pass empty string to clear."
    }
  },
  "required": [
    "id",
    "claim_token"
  ]
}
🔴import_crontab(crontab, email)

Arm a dead-man's-switch for EVERY line of a crontab in one call. Paste raw crontab text; Cronping parses each schedule, derives the expected interval from the cron expression itself (using the longest gap between runs so weekend/twice-daily schedules don't false-alarm), and creates one heartbeat monitor per job. Returns, for each line, a ping_url plus the same command with `&& curl -fsS <ping_url>` already appended so you can drop it straight back into the crontab. Also anchors each new check's first deadline to the schedule's real next run — so a fresh switch neither pages at t=0 nor sleeps a full period. No account required. Ideal when an agent or operator wants to instrument a whole box's scheduled jobs at once. Up to 20 lines per call. Lines with no fixed interval (e.g. @reboot) are skipped.

Input Schema

{
  "type": "object",
  "properties": {
    "crontab": {
      "type": "string",
      "description": "Raw crontab text, one job per line (comments and FOO=bar env lines are ignored). Standard 5-field expressions plus @daily/@hourly/@weekly/@monthly/@yearly macros and named days/months are supported."
    },
    "email": {
      "type": "string",
      "description": "Optional. Email address for DOWN and recovery alerts, applied to every check created. STRONGLY RECOMMENDED — without it the checks track status but cannot notify anyone."
    }
  },
  "required": [
    "crontab"
  ]
}
🔴delete_heartbeat(id, claim_token)

Permanently delete a Cronping heartbeat monitor and all its events. Use this to tear down an ephemeral check your agent created (e.g. at shutdown, or after a one-off job) so it stops being monitored and can never raise a stale DOWN alert. Requires the claim_token returned by create_heartbeat. This is irreversible — the id and ping_url stop working immediately. To silence a check temporarily instead of deleting it, use pause_heartbeat.

Input Schema

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The check id returned by create_heartbeat."
    },
    "claim_token": {
      "type": "string",
      "description": "The claim_token returned by create_heartbeat."
    }
  },
  "required": [
    "id",
    "claim_token"
  ]
}
🟡pause_heartbeat(id, claim_token, paused)

Pause or resume monitoring on an existing Cronping check without deleting it. Pause during planned maintenance or a known downtime window so a silent job does not raise a false DOWN alert; resume to re-arm the dead-man's-switch. While paused, missed pings are ignored and no alerts fire. Requires the claim_token returned by create_heartbeat.

Input Schema

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The check id returned by create_heartbeat."
    },
    "claim_token": {
      "type": "string",
      "description": "The claim_token returned by create_heartbeat."
    },
    "paused": {
      "type": "boolean",
      "description": "true to pause monitoring, false to resume it. Defaults to true."
    }
  },
  "required": [
    "id",
    "claim_token"
  ]
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded7 tools
verifiedversion not recorded7 tools