Skip to main content
Glama

Create a heartbeat monitor

create_heartbeat

Create a heartbeat that alerts when a scheduled job stops reporting. Jobs call the returned ping_url on success, /start when starting, or /fail to mark down.

Instructions

Create a heartbeat: Fettle alerts when a scheduled job stops calling its ping_url. Use it for cron jobs, backups and workers that should report in; to probe a URL, host or port from outside use create_monitor. The job calls ping_url (GET or POST) on success, ping_url + "/start" when it begins (restarts the clock) and ping_url + "/fail" to go DOWN at once. It is never late before its first success ping (a /fail call still marks it DOWN); after that an alert fires period_seconds + grace_seconds after the last ping. Requires a key with the write scope. The plan caps how many heartbeats exist (403 past it; see get_plan_usage). An invalid argument is a 422 naming it. Returns the heartbeat, with ping_url. Example: {"name": "nightly backup", "period_seconds": 86400, "grace_seconds": 3600}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name, 1 to 255 characters.
tagsNoFlat labels for grouping and filtering, for example env:prod or service:api, at most 10. Each tag is trimmed, lowercased and deduplicated on write, at most 50 characters of a-z, 0-9 and : _ . / -, starting with a letter or digit. Reuse names from list_tags rather than inventing near-duplicates.
channel_idsNoNotification channel uuids from list_channels. Omit it or pass [] to alert every verified, active channel of the organization. An id that is not an active channel of this organization is a 404.
grace_secondsYesExtra seconds of silence tolerated after the period before the heartbeat is reported late, 0 to 2592000; it may exceed the period.
period_secondsYesHow often the job runs, 60 to 2592000 seconds. To ping every N seconds and be alerted after T seconds of silence, set period_seconds = N and grace_seconds = T - N (T at least N).
notification_cooldown_secondsNo60 to 86400 seconds; 1800 when not set on create. Only holds back a duplicate first alert for the same incident within that window. Repeat reminders while an incident stays open and unacknowledged follow the plan's renotify_interval_seconds and renotify_max_count (get_plan_usage; 0 means no reminders) instead, and the recovery alert is never held back.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYes
nameYes
tagsNo
stateYesKnown values: PENDING, UP, DOWN, PAUSED.
ping_urlYes
is_activeYes
created_atYes
overdue_atYes
updated_atYes
channel_idsNo
last_ping_atYes
grace_secondsYes
last_start_atYes
period_secondsYes
last_success_atYes
last_duration_msYes
notification_cooldown_secondsYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv0.6.1
    • addedInput schema / properties / channel_ids / description
      Added value: +"Notification channel uuids from list_channels. Omit it or pass [] to alert every verified, active channel of the organization. An id that is not an active channel of this organization is a 404."
    • addedInput schema / properties / grace_seconds / description
      Added value: +"Extra seconds of silence tolerated after the period before the heartbeat is reported late, 0 to 2592000; it may exceed the period."
    • addedInput schema / properties / name / description
      Added value: +"Display name, 1 to 255 characters."
    • addedInput schema / properties / notification_cooldown_seconds / description
      Added value: +"60 to 86400 seconds; 1800 when not set on create. Only holds back a duplicate first alert for the same incident within that window. Repeat reminders while an incident stays open and unacknowledged follow the plan's renotify_interval_seconds and renotify_max_count (get_plan_usage; 0 means no reminders) instead, and the recovery alert is never held back."
    • addedInput schema / properties / period_seconds / description
      Added value: +"How often the job runs, 60 to 2592000 seconds. To ping every N seconds and be alerted after T seconds of silence, set period_seconds = N and grace_seconds = T - N (T at least N)."
    • addedInput schema / properties / tags / description
      Added value: +"Flat labels for grouping and filtering, for example env:prod or service:api, at most 10. Each tag is trimmed, lowercased and deduplicated on write, at most 50 characters of a-z, 0-9 and : _ . / -, starting with a letter or digit. Reuse names from list_tags rather than inventing near-duplicates."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "properties": {
      +    "channel_ids": {
      +      "items": {
      +        "format": "uuid",
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "created_at": {
      +      "type": "string"
      +    },
      +    "grace_seconds": {
      +      "type": "integer"
      +    },
      +    "id": {
      +      "format": "uuid",
      +      "type": "string"
      +    },
      +    "is_active": {
      +      "type": "boolean"
      +    },
      +    "last_duration_ms": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "last_ping_at": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "last_start_at": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "last_success_at": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "name": {
      +      "type": "string"
      +    },
      +    "notification_cooldown_seconds": {
      +      "type": "integer"
      +    },
      +    "overdue_at": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "period_seconds": {
      +      "type": "integer"
      +    },
      +    "ping_url": {
      +      "type": "string"
      +    },
      +    "state": {
      +      "description": "Known values: PENDING, UP, DOWN, PAUSED.",
      +      "type": "string"
      +    },
      +    "tags": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "updated_at": {
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "id",
      +    "name",
      +    "state",
      +    "period_seconds",
      +    "grace_seconds",
      +    "ping_url",
      +    "last_ping_at",
      +    "last_success_at",
      +    "last_start_at",
      +    "last_duration_ms",
      +    "overdue_at",
      +    "notification_cooldown_seconds",
      +    "is_active",
      +    "created_at",
      +    "updated_at"
      +  ],
      +  "type": "object"
      +}
  2. First observedv0.5.4

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare the mutation safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false). The description adds substantial behavior: the ping_url contract (/start restarts the clock, /fail goes DOWN immediately), the never-late-before-first-ping rule, the period_seconds + grace_seconds alert timing, the write-scope requirement, the plan cap returning 403, and invalid args returning 422. This is exactly the context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single dense paragraph, but it is front-loaded with the purpose and then the ping_url contract, error behavior, and example in a logical order. Every sentence carries distinct information, though the run-on density slightly taxes readability compared to a cleaner separation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter mutation tool with an output schema, the description covers the gaps an agent actually needs: purpose, alternative tool, ping contract, auth scope, plan limits, and error codes. Return values are summarized ('returns the heartbeat, with ping_url') without redundantly re-specifying the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds value on top: a worked example tying name/period_seconds/grace_seconds together and the timing rule (alert fires period_seconds + grace_seconds after the last ping), which explains how the two numeric params interact. It does not add detail for tags, channel_ids, or notification_cooldown_seconds beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Create) and resource (a heartbeat), then immediately defines what a heartbeat is: 'Fettle alerts when a scheduled job stops calling its ping_url.' It explicitly distinguishes itself from the sibling create_monitor ('to probe a URL, host or port from outside use create_monitor'), so an agent can route correctly without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use cases (cron jobs, backups, workers that report in) and an explicit alternative with its condition (use create_monitor to probe a URL/host/port from outside). It also routes to get_plan_usage for quota and names the write scope requirement. Nothing about selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.