Skip to content

net.hookpulse/hookpulse

by hookpulse.net · remote · no sign-in to list tools · v1.0.1 · published by net.hookpulse

Dead-man switch for cron and webhooks: ingest URL, miss detection, alerts and a status feed.

Deletes · 3Final · 1Changes · 12

24 tools: 3 can delete or cancel things, 1 do something that can't be undone, 12 change things and 8 only read.

Scanned Oct 21, 2026

6 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http hookpulse https://hookpulse.net/mcp

Findings

Matches of fixed checks, with the text they matched.

4 warn2 info
  • The server marks "signal_start" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

    Matched text

    annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "signal_start" says "start": a word for a change.

    What this check looks for
  • The server marks "ping_slug" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

    Matched text

    annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "ping_slug" says "ping": a word for reading.

    What this check looks for
  • The server marks "signal_slug" read-only (readOnlyHint: true), and its own name, description or input give the class "irreversible".

    Matched text

    annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The description's first verb is "send": a word for sending, and what is sent cannot be taken back.

    What this check looks for
  • The server marks "status_feed_rotate" destructive (destructiveHint: true), and its name says "status", a word for reading.

    Matched text

    annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}; The name "status_feed_rotate" says "status": a word for reading.

    What this check looks for
  • The description mentions "credential".

    Matched text

    description: "...hboard without handing over the owner's credential. With a schedule it is here that `next_..."

    What this check looks for
  • The description mentions "credential".

    Matched text

    description: "Simulates the cron: GET on /in/:id. No credential on purpose — the caller is a cron, and..."

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

24 tools

Deletes or cancels 3Claude Code: deny
  • delete_endpointRemoves the owner's endpoint.No findings

    Why it is in this group

    • The name "delete_endpoint" says "delete": a word for removing or ending something.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Removes the owner's endpoint.

    Annotations the server declares

    • title: Delete endpoint
    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: false
  • ingest_key_rotateRotates the ingest key; the previous one stops creating monitors.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Rotates the ingest key; the previous one stops creating monitors. Existing ones keep working. Monitors already created keep working — rotating only revokes the power to create new ones.

    Annotations the server declares

    • title: Ingest key rotate
    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: false
  • status_feed_rotateRotates the status feed token; the previous URL stops working.1 finding

    Why it is in this group

    • The name "status_feed_rotate" says "status": a word for reading.
    • The server marks it destructive (destructiveHint: true).

    Findings

    • Warn

      The server marks "status_feed_rotate" destructive (destructiveHint: true), and its name says "status", a word for reading.

      Matched text

      annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false}; The name "status_feed_rotate" says "status": a word for reading.

      What this check looks for
    Description, as the server wrote it
    Rotates the status feed token; the previous URL stops working.

    Annotations the server declares

    • title: Status feed rotate
    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: false
Can't be undone 1Claude Code: ask
  • signal_slugSend start, fail or an exit code by name, with the ingest key; the first signal of a new name creates its monitor.1 finding

    Why it is in this group

    • The description's first verb is "send": a word for sending, and what is sent cannot be taken back.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "signal_slug" read-only (readOnlyHint: true), and its own name, description or input give the class "irreversible".

      Matched text

      annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The description's first verb is "send": a word for sending, and what is sent cannot be taken back.

      What this check looks for
    Description, as the server wrote it
    Send start, fail or an exit code by name, with the ingest key; the first signal of a new name creates its monitor. The same signals as `/in/:id/start`, `/in/:id/fail` and `/in/:id/:exit_code`, for a fleet that only knows the ingest key: the job sends its name, not the monitor id. The first signal of a new name creates the monitor, with the same rules and the same `cron`, `tz` and `grace_sec` as the plain ping by name.

    Annotations the server declares

    • title: Signal slug
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
Changes things 12Claude Code: ask
  • api_indexFull index of the HookPulse API.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    Full index of the HookPulse API.

    Annotations the server declares

    • title: API index
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • check_siteCheck a site monitor now.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Check a site monitor now. One call every 10 seconds per destination host. One call every 10 seconds per destination host, for everyone: the button cannot hammer a site. The first state of a new site comes from here, without an alert — you are looking at it. After that, the state and the alerts come from the check that runs every minute.

    Annotations the server declares

    • title: Check site
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • contactWrite to the people behind the product: a question, or a sponsorship/partnership/advertising proposal.No findings

    Why it is in this group

    • The description's first verb is "write": a word for a change.
    Description, as the server wrote it
    Write to the people behind the product: a question, or a sponsorship/partnership/advertising proposal. One route for a question and for a sponsorship, partnership or ad proposal (`tipo`, with the placements of `GET /api/partners`). One message every 10 seconds per network: one that arrives sooner waits its turn and then goes out — no error. The message reaches the team by e-mail, with `email` as the reply address. For voice, send multipart/form-data: `dados` is this JSON (up to 32 KiB), and `audio` is one WebM, Ogg or M4A audio file (up to 2 MB). Audio can replace message. The browser records up to two minutes. Audio is attached to the owner's e-mail.

    Annotations the server declares

    • title: Contact
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • create_endpointCreate a monitor for a routine.No findings

    Why it is in this group

    • The name "create_endpoint" says "create": a word for a change.
    Description, as the server wrote it
    Create a monitor for a routine. Use cron, tz and grace_sec for a schedule, or interval_sec for a fixed check-in interval. Set max_duration_sec to detect an open run that exceeds its time limit. With `check` the monitor is a site: HookPulse calls `check.url` every `interval_sec` (default 300) and alerts when it goes down — two failed checks in a row, one minute apart, from a server whose own connection is proven — and when it answers again. `{"check":{"url":"https://example.com/"}}` is enough; the name defaults to the host. A site has no `cron`, no `max_duration_sec` and no ingest URL. This response is the only one that shows the monitor's `token` and the `templates` — keep them. A miss alerts at most once per 24h — or per `alert_repeat_sec`, or per interval, whichever is longer. Send `cron`+`tz`+`grace_sec` instead of `interval_sec` for a real schedule: a 03:00 backup is late at 03:01:30, not 24 hours later. `max_duration_sec` catches the other failure: a run that starts and hangs, which plain silence detection only notices at the next scheduled time.

    Annotations the server declares

    • title: Create endpoint
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • create_guestCreates a guest token hp_… Keep the token: without it there is no way back to the monitors, unless you have already tied them to an e-mail.No findings

    Why it is in this group

    • The name "create_guest" says "create": a word for a change.
    Description, as the server wrote it
    Creates a guest token hp_… Keep the token: without it there is no way back to the monitors, unless you have already tied them to an e-mail.

    Annotations the server declares

    • title: Create guest
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • create_siteMonitor a website: HookPulse calls check.url every interval_sec (default 300) and alerts when it goes down and when it is back.No findings

    Why it is in this group

    • The name "create_site" says "create": a word for a change.
    Description, as the server wrote it
    Monitor a website: HookPulse calls check.url every interval_sec (default 300) and alerts when it goes down and when it is back. With `check` the monitor is a site: HookPulse calls `check.url` every `interval_sec` (default 300) and alerts when it goes down — two failed checks in a row, one minute apart, from a server whose own connection is proven — and when it answers again. `{"check":{"url":"https://example.com/"}}` is enough; the name defaults to the host. A site has no `cron`, no `max_duration_sec` and no ingest URL. This response is the only one that shows the monitor's `token` and the `templates` — keep them. A miss alerts at most once per 24h — or per `alert_repeat_sec`, or per interval, whichever is longer. Send `cron`+`tz`+`grace_sec` instead of `interval_sec` for a real schedule: a 03:00 backup is late at 03:01:30, not 24 hours later. `max_duration_sec` catches the other failure: a run that starts and hangs, which plain silence detection only notices at the next scheduled time.

    Annotations the server declares

    • title: Create site
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
  • healthLiveness.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    Liveness.

    Annotations the server declares

    • title: Health
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • import_crontabReads a crontab and proposes one monitor per scheduled line.No findings

    Why it is in this group

    • The name "import_crontab" says "import": a word for a change.
    Description, as the server wrote it
    Reads a crontab and proposes one monitor per scheduled line. Without apply=1 nothing is written; the proposal says what was ignored and why. Passwords in the command are redacted. The body is the crontab itself, as `text/plain`. Without `?apply=1` **nothing is written**: you get the proposal — what would become a monitor, what was ignored and why, and what still fits in the free tier. With `apply=1` it is all or nothing, under the same rules as `POST /api/endpoints`. Comments, variables and `@reboot` are ignored (there is no way to know when to expect a reboot); `@daily` and friends become the equivalent expression. The command becomes the monitor name, with passwords and tokens redacted first — the name travels in the alert e-mail, in the public dashboard and in the badge.

    Annotations the server declares

    • title: Import crontab
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • ping_slugCreate a monitor on its first check-in.1 finding

    Why it is in this group

    • The name "ping_slug" says "ping": a word for reading.
    • The description's first verb is "create": a word for a change.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "ping_slug" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

      Matched text

      annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "ping_slug" says "ping": a word for reading.

      What this check looks for
    Description, as the server wrote it
    Create a monitor on its first check-in. The same slug uses the same monitor. A rejected creation writes no monitor or event. The slug becomes the monitor name and its identity: the same slug always means the same monitor, so a retry never creates a second one. Normalised to lowercase, `[a-z0-9-]`, 40 chars. Works by GET or POST.

    Annotations the server declares

    • title: Ping slug
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • signal_exit_codeThe shell exit status: 0 behaves like a ping, 1-255 record the code as a failure.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    The shell exit status: 0 behaves like a ping, 1-255 record the code as a failure. `curl -fsS $ORIGIN/in/ID/$?` at the end of a script is the whole integration. `0` behaves exactly like a plain ping; 1 to 255 record the code and leave the failure for the cron.

    Annotations the server declares

    • title: Signal exit code
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • signal_failRecord a failed run.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    Record a failed run. The next five-minute check sends the alert with reason fail. The monitor's alert_repeat_sec controls repeated alerts; the default is 24 hours. Failing is not proof of life either: the clock keeps running. The ingest never sends e-mail and never calls out — it records `alert_pending` and the cron turns it into an alert with `reason: "fail"` within 5 minutes, under the same one-per-24h cap. Works by GET or POST.

    Annotations the server declares

    • title: Signal fail
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • signal_startSays the run STARTED.1 finding

    Why it is in this group

    • The name "signal_start" says "start": a word for a change.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "signal_start" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

      Matched text

      annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The name "signal_start" says "start": a word for a change.

      What this check looks for
    Description, as the server wrote it
    Says the run STARTED. Does not clear the dead-man clock: a routine that starts and hangs still becomes a miss. The next success records the duration. `start` is not proof of life: it does not move `last_event_at` and does not clear the miss counter, so a routine that starts and hangs still becomes a miss at the right time. The next success closes the run and records `last_duration_ms` — pass `?rid=` on both ends when runs can overlap, or the duration is measured against the wrong start. With `max_duration_sec` set on the monitor, a run left open past that ceiling alerts with `reason: "too_long"` on the next 5-minute check. Works by GET or POST.

    Annotations the server declares

    • title: Signal start
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
Only reads 8Claude Code: allow
  • get_endpointStatus of one endpoint (use the endpoint token if you have it).1 finding

    Why it is in this group

    • The name "get_endpoint" says "get": a word for reading.

    Findings

    • Info

      The description mentions "credential".

      Matched text

      description: "...hboard without handing over the owner's credential. With a schedule it is here that `next_..."

      What this check looks for
    Description, as the server wrote it
    Status of one endpoint (use the endpoint token if you have it). The monitor token only reads: it lets you put the state on a third-party dashboard without handing over the owner's credential. With a schedule it is here that `next_expected_at` says when the next run is due.

    Annotations the server declares

    • title: Get endpoint
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • ingest_keyReturns (minting the first time) the key for /in/<key>/<slug>, where a ping creates its own monitor inside the free tier.No findings

    Why it is in this group

    • The description's first verb is "return": a word for reading.
    Description, as the server wrote it
    Returns (minting the first time) the key for /in/<key>/<slug>, where a ping creates its own monitor inside the free tier. Instruments a whole fleet with no setup call per job. One key per owner. The key survives signing in: the crontab you deployed keeps working.

    Annotations the server declares

    • title: Ingest key
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_endpointsLists the guest's/session's endpoints.No findings

    Why it is in this group

    • The name "list_endpoints" says "list": a word for reading.
    Description, as the server wrote it
    Lists the guest's/session's endpoints.

    Annotations the server declares

    • title: List endpoints
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_eventsLatest ingest pings.No findings

    Why it is in this group

    • The name "list_events" says "list": a word for reading.
    Description, as the server wrote it
    Latest ingest pings.

    Annotations the server declares

    • title: List events
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_sitesThe state of every site you monitor (up, down, waiting, paused), with the last check.No findings

    Why it is in this group

    • The name "list_sites" says "list": a word for reading.
    Description, as the server wrote it
    The state of every site you monitor (up, down, waiting, paused), with the last check.

    Annotations the server declares

    • title: List sites
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_templatesIngest snippets and the JSON HookPulse POSTs on a miss.No findings

    Why it is in this group

    • The name "list_templates" says "list": a word for reading.
    Description, as the server wrote it
    Ingest snippets and the JSON HookPulse POSTs on a miss. It exists so nobody guesses the alert format: `miss_json` and `recovery_json` here are the same bodies that arrive at your `alert_url`. Slack and Discord receive only the field they read.

    Annotations the server declares

    • title: List templates
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • ping_ingestSimulates the cron: GET on /in/:id.1 finding

    Why it is in this group

    • The name "ping_ingest" says "ping": a word for reading.

    Findings

    • Info

      The description mentions "credential".

      Matched text

      description: "Simulates the cron: GET on /in/:id. No credential on purpose — the caller is a cron, and..."

      What this check looks for
    Description, as the server wrote it
    Simulates the cron: GET on /in/:id. No credential on purpose — the caller is a cron, and the ID is already the secret.

    Annotations the server declares

    • title: Ping ingest
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • status_feed_urlPublic URL (JSON and RSS) with the status of all the owner's endpoints.No findings

    Why it is in this group

    • The name "status_feed_url" says "status": a word for reading.
    Description, as the server wrote it
    Public URL (JSON and RSS) with the status of all the owner's endpoints. The feed token only reads status: it does not create, change or delete. Whoever has the link sees the dashboard — treat it as a secret.

    Annotations the server declares

    • title: Status feed URL
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Install

Pinned to version 1.0.1. Values in angle brackets are yours to fill in.

claude mcp add --transport http hookpulse https://hookpulse.net/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__hookpulse__list_endpoints",
      "mcp__hookpulse__list_sites",
      "mcp__hookpulse__get_endpoint",
      "mcp__hookpulse__list_events",
      "mcp__hookpulse__ping_ingest",
      "mcp__hookpulse__ingest_key",
      "mcp__hookpulse__status_feed_url",
      "mcp__hookpulse__list_templates"
    ],
    "ask": [
      "mcp__hookpulse__api_index",
      "mcp__hookpulse__health",
      "mcp__hookpulse__create_guest",
      "mcp__hookpulse__create_endpoint",
      "mcp__hookpulse__create_site",
      "mcp__hookpulse__check_site",
      "mcp__hookpulse__import_crontab",
      "mcp__hookpulse__signal_start",
      "mcp__hookpulse__signal_fail",
      "mcp__hookpulse__signal_exit_code",
      "mcp__hookpulse__ping_slug",
      "mcp__hookpulse__signal_slug",
      "mcp__hookpulse__contact"
    ],
    "deny": [
      "mcp__hookpulse__delete_endpoint",
      "mcp__hookpulse__ingest_key_rotate",
      "mcp__hookpulse__status_feed_rotate"
    ]
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as hookpulse. Review it before you use it.