protogrid

Search / net.hookpulse/hookpulse

hookpulse

R0· no sign-in

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

v1.0.1 · active · repository · website · descriptor JSON · versions

An agent can connect right now, no human step.Remote endpoint, no authentication, reachable on the last probe.
Quality69needs work
Trust95of 100
Uptime, 30 days96%
Latency p50480 ms

Connect

8 clients · secrets stay placeholders
{
  "mcpServers": {
    "hookpulse": {
      "type": "http",
      "url": "https://hookpulse.net/mcp"
    }
  }
}
claude mcp add --transport http hookpulse https://hookpulse.net/mcp
[mcp_servers.hookpulse]
url = "https://hookpulse.net/mcp"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "hookpulse": {
      "type": "remote",
      "url": "https://hookpulse.net/mcp",
      "enabled": true
    }
  }
}
{
  "mcpServers": {
    "hookpulse": {
      "type": "http",
      "url": "https://hookpulse.net/mcp"
    }
  },
  "deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=hookpulse&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vaG9va3B1bHNlLm5ldC9tY3AifQ%3D%3D"
}
{
  "servers": {
    "hookpulse": {
      "type": "http",
      "url": "https://hookpulse.net/mcp"
    }
  }
}
{
  "mcpServers": {
    "hookpulse": {
      "httpUrl": "https://hookpulse.net/mcp"
    }
  }
}
extensions:
  "hookpulse":
    enabled: true
    name: "hookpulse"
    type: streamable_http
    uri: "https://hookpulse.net/mcp"
    timeout: 300

Quality 69 / 100needs work

protocol75 · weight 25
  • warn
    protocol.modernnewest supported version is 2025-06-18; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
  • n/a
    protocol.statelessonly applies to 2026-07-28 servers
  • pass
    protocol.transportstreamable HTTP
  • n/a
    protocol.list_ttlonly applies to 2026-07-28 servers
authorizationn/a · weight 15
  • n/a
    auth.prm, auth.as_metadata, auth.cimdno remote uses OAuth
  • n/a
    auth.secret_in_urlno templated URL
tool hygiene86 · weight 30
  • warn
    tools.descriptions1 of 24 tools have a description under 20 characters
  • warn
    tools.description_length1 tools have descriptions over 1,024 characters, which crowds the context
  • pass
    tools.schemasevery tool has an object input schema
  • pass
    tools.annotations24 of 24 tools declare readOnlyHint or destructiveHint
  • pass
    tools.directory_hintsevery tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint
  • pass
    tools.token_costabout 4,619 tokens to load every tool
  • pass
    tools.api_dumptools are not a one-to-one API dump
stability25 · weight 15
  • warn
    stability.changes146 tool changes in 30 days
  • fail
    stability.rug_pull1 tools kept their name but changed most of their description in 30 days; review before trusting them
dependenciesn/a · weight 15
  • n/a
    deps.known_vulns, deps.mcp_sdk_version, deps.resolvableno npm or PyPI package

24 tools, about 4,619 tokens to load them all · tool set 0acad41b76d3 · tools last changed 2026-10-16 · checked 2026-10-19 16:53 UTC

Tool changes

  • delete_environmentremoved

    Removes a device and every measurement on it, in one call. One call, not one per measurement — the same reason `GET /api/coletas/serie` exists. What goes away is the ownership: your list, the authority to read those series, and the slots those measurements held, so the device can be registered again. Readings already stored at the ingest origin stay there until their own retention, and the machine keeps sending: the symbols are signed and stand on their own there. That is why the answer carries `remover`, one command per measurement that had a cron line. The device's collector channels are revoked first; if the input central cannot confirm that, nothing is deleted (503) and the call can be repeated, so no channel is left receiving data without a device.

  • update_environmentremoved

    Renames a device, and its measurements along with it. One machine has one name. The measurements carry a copy of it, so renaming here renames them too — leaving the old name on them would show the same machine twice in a list that groups by device. Its collector channels take the new name and group too in `GET /api/coletas` (`inputs[]`), and the group decides which dashboard tab the device is under. Send only what changes; what you omit stays. The detected environment is never rewritten: it is evidence of what that machine reported.

  • delete_collectionremoved

    Removes one measurement and frees that slot on the device. What disappears is the OWNERSHIP: your list, the authority to read that series, and the unique slot that measurement holds on that environment — so you can add it again later. Readings already stored at the ingest origin stay there until their own retention. The machine keeps sending: the symbol is signed and stands on its own there, which is why the answer carries `remover`, the command that takes the line out of the crontab. Use `ativa:false` instead when you only want to stop looking.

  • update_collectionremoved

    Renames one measurement, or stops and resumes reading it. The id never changes: it is the write symbol already sitting in a crontab, and renaming on a screen must not send anyone back to the machine to edit a line. Send only what you are changing; anything omitted stays as it is. `ativa:false` takes the measurement out of the fleet read — it keeps its history and its commands, stops costing a query, and comes back with `ativa:true`. It does NOT silence the machine: the symbol is signed and stands on its own at the ingest origin, so a device keeps sending until you remove its cron line. The answer is the collection as it now stands — draw the screen from it, not from a local copy.

  • get_collection_seriesremoved

    The latest readings of one device, for the screen that draws it. Authorised by YOUR session, never by the symbol in the crontab. A device that is not yours answers 404 exactly like one that does not exist — telling the two apart would confirm to a stranger that the id exists — 401 is only for sending no credential at all, which tells the caller what they already know. When the ingest origin cannot be read the answer is 503, not an empty series: a screen must say "I could not read now", never let you believe your machine stopped. Readings are reused for up to 60 seconds. Poll no faster than once per minute in steady use; `poll_after_sec` is the minimum wait for this response. During the first minute after registration an empty series may be checked every 5 seconds. Do not overlap requests. On 429 or 503, respect `Retry-After` and `retry_after_sec`, increase the delay after repeated failures, and keep the last successful reading. Changing n does not bypass reuse or capacity limits.

  • create_collectionremoved

    Adds compatible measurements to a previously detected device. First create /api/ambientes and submit its environment report. Reference that ambiente_id here; its saved name and group are authoritative. Same device+measurement returns the existing stream instead of duplicating it. A profile adds only compatible measurements. Up to 200 collections per owner. The signed collection id writes only its own measurement stream.

  • list_collectionsremoved

    Lists your measurements with commands adapted to each saved device environment. Two views of the same thing: `coletas` is one entry per measurement, `equipamentos` is one per machine with a SINGLE command that does all of its measurements and a SINGLE cron line. Use the device one unless you really want a single measurement on its own. Commands are generated only from a detected environment. Legacy collections without one keep their readings, but comandos.agora/agenda are null until a compatible environment is provided. Curl, wget and Python 3 follow the detected capabilities; Windows disk uses PowerShell. comandos.agora is a readable multiline block; run the whole block together. A separate cron line is offered only when crontab exists. Unsupported formats are never guessed.

  • report_environmentremoved

    Preview or save the allowlisted discovery report for one device. Send terminal and saidas (step id to pasted output), initially with conferir:true. Preview returns normalized dados, additional passos and pronto without writing. Omit conferir to save when complete. Only allowlisted facts are saved, never raw commands. First report wins within one hour; identical retries do not rewrite. The discovery never creates a legacy measurement, sends a reading, installs software or creates a schedule. With Accept: text/plain the receipt is only `ok`.

  • list_input_fleetremoved

    Every collector channel of the caller, with state and live numbers, in one response. One call for the whole fleet — one query to the time-series store for all channels, never one per device. It is the same function the dashboard subscribes to over the socket (`/api/inputs/serie`), where the input central then pushes `inputs.updated` and `inputs.removed` events; integrators get the same data here without the socket. A failed input-central request or an invalid fleet response returns 503 inputs_unavailable, never a successful empty fleet. Fleet reads give the input-central exchange, including its response body, a 750 ms deadline. The optional time-series query has a 400 ms deadline; when it is unavailable or too slow, channels are preserved with stats null. An authenticated owner with no channels still gets an empty list.

  • set_device_input_activeremoved

    Pauses or resumes one collector channel. Pausing keeps the channel, its credential and its configuration: batches the collector sends while paused are accepted and discarded, so nothing is stored or measured and the collector does not retry in a loop. Resuming stores the next batch again. The input central changes only a channel of the same owner, including one whose device was already deleted.

Showing the latest 10. Full history: list_changes · trend: quality JSON.

Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.

Trust 95 / 100

provenance85
liveness99
freshness100
hygiene100

+repository +dns-namespace +website +reachable +uptime-96% +updated-5d-ago

Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.

Endpoints

remoteauthreachableuptime 30dp50protocollast ok
https://hookpulse.net/mcp streamable-httpnoneyes96%480 ms2025-06-182026-10-19

Tools (24)

api_indexread-onlyFull index of the HookPulse API.
check_siteCheck 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.
contactWrite 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.
create_endpointCreate 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.
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.
create_siteMonitor 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.
delete_endpointdestructiveRemoves the owner's endpoint.
get_endpointread-onlyStatus 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.
healthread-onlyLiveness.
import_crontabReads 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.
ingest_keyread-onlyReturns (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.
ingest_key_rotatedestructiveRotates 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.
list_endpointsread-onlyLists the guest's/session's endpoints.
list_eventsread-onlyLatest ingest pings.
list_sitesread-onlyThe state of every site you monitor (up, down, waiting, paused), with the last check.
list_templatesread-onlyIngest 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.
ping_ingestread-onlySimulates the cron: GET on /in/:id. No credential on purpose — the caller is a cron, and the ID is already the secret.
ping_slugread-onlyCreate 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.
signal_exit_coderead-onlyThe 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.
signal_failread-onlyRecord 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.
signal_slugread-onlySend 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.
signal_startread-onlySays 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.
status_feed_rotatedestructiveRotates the status feed token; the previous URL stops working.
status_feed_urlread-onlyPublic 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.

Schemas: list_tools.

Similar MCP servers

Official server.json
{
  "name": "net.hookpulse/hookpulse",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
  "remotes": [
    {
      "url": "https://hookpulse.net/mcp",
      "type": "streamable-http"
    }
  ],
  "version": "1.0.1",
  "repository": {
    "url": "https://github.com/wrpbr/hookpulse",
    "source": "github"
  },
  "websiteUrl": "https://hookpulse.net",
  "description": "Dead-man switch for cron and webhooks: ingest URL, miss detection, alerts and a status feed."
}