Connect an AI assistant with the MCP server
HostTracker runs a hosted Model Context Protocol (MCP) server. Connect it to an AI assistant and the assistant can operate your account from a conversation: run a live check, list what is down, pause a monitor, schedule maintenance, publish a status page incident or wire up a webhook. Every tool is a thin wrapper over the REST API v2, so it can do exactly what your credential allows and nothing more.
| Endpoint | https://mcp.host-tracker.com/mcp |
| Transport | Streamable HTTP. Nothing to install or run locally. |
| Sign-in | OAuth 2.1 (sign in and approve, recommended) or an Authorization: Bearer <token> header with an API token |
| Plan | Your plan must include API access - see Rate limits and quotas |
| Request limit | 60 requests per minute per client IP address on the MCP endpoint, plus your plan’s API quota |
| Paging | List tools take limit (1-50, default 20) and cursor |
| Time | Every timestamp in and out is Unix seconds |
Connect with OAuth (recommended)
Section titled “Connect with OAuth (recommended)”With OAuth there is no token to copy. The client opens HostTracker’s sign-in page, then a consent card that lists exactly what the assistant will be allowed to do. You press Approve and the client handles the rest: access tokens are short-lived (about an hour) and refreshed silently.
- If the client does not ask for specific scopes, the connection gets
check+monitor:read(run instant checks, read monitors, uptime and incidents). - The
accountscope family is never offered to connected apps. - To widen an OAuth connection later, remove and re-add the connector and approve the wider set - scopes on an existing connection cannot be widened silently.
- To cut a connection off, open Integrations -> API -> Connected apps and click Revoke. Its refresh chain dies immediately; the last access token expires within the hour.
Claude.ai and Claude Desktop: Settings -> Connectors -> Add custom connector -> paste
https://mcp.host-tracker.com/mcp -> Connect. Sign in if asked, press Approve on the consent card, and the
connector shows as connected.
Claude Code:
claude mcp add --transport http hosttracker https://mcp.host-tracker.com/mcpThen run /mcp, pick hosttracker and choose Authenticate. The browser opens the sign-in and consent page;
Claude Code listens on a localhost port for the redirect, which is normal.
ChatGPT: in developer mode, open connectors and add https://mcp.host-tracker.com/mcp. ChatGPT shows its “link
account” step after the first call, which opens the same sign-in and consent page.
Any other client with an OAuth-capable connector dialog needs only the URL.
Connect with an API token
Section titled “Connect with an API token”Use a token for clients that only send static headers, for CI, or when you want a hand-picked scope set and expiration.
- Open Integrations -> API in the app (
/integrations/api) and create a token. - Tick only the scopes the assistant needs (table below). Scope leaves do not imply each other:
monitor:writedoes not grantmonitor:read. A bare family name (monitor) covers every leaf in it. - Set a short expiration and, if the client runs from a fixed address, an IP allow-list. A token cannot be revoked before it expires.
- Copy the token - it is shown once.
| You want the assistant to… | Scopes |
|---|---|
| Run instant checks | check |
| See monitors, uptime, results and incidents | monitor:read |
| Create, edit, pause or delete monitors and maintenance windows; comment incidents | monitor:write |
| See who is notified about what | contact:read, subs:read |
| Manage contacts and contact groups | contact:write (plus contact:read to list them) |
| Subscribe or unsubscribe contacts to monitors | monitor:write |
| Manage webhooks | webhook:read, webhook:write |
| Manage status pages and publish incidents on them | statuspage:read, statuspage:write |
| Read account usage, limits and quota | account:read (API tokens only - OAuth connections never get it) |
There is no reason to grant account:write: the MCP server refuses every write under /account whatever the token
allows.
Claude Code
Section titled “Claude Code”Project-scoped, in .mcp.json at the repository root:
{ "mcpServers": { "hosttracker": { "type": "http", "url": "https://mcp.host-tracker.com/mcp", "headers": { "Authorization": "Bearer YOUR_HOSTTRACKER_API_TOKEN" } } }}Or from the command line, which writes the same entry:
claude mcp add --transport http hosttracker https://mcp.host-tracker.com/mcp \ --header "Authorization: Bearer YOUR_HOSTTRACKER_API_TOKEN"Check it with claude mcp list. Inside a session the tools appear prefixed, for example
hosttracker_run_instant_check.
Claude Desktop with a token
Section titled “Claude Desktop with a token”The Desktop connector dialog is OAuth-only, so a token goes through the mcp-remote bridge. Settings -> Developer
-> Edit config opens claude_desktop_config.json:
{ "mcpServers": { "hosttracker": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.host-tracker.com/mcp", "--header", "Authorization:${HT_AUTH}"], "env": { "HT_AUTH": "Bearer YOUR_HOSTTRACKER_API_TOKEN" } } }}Quit and restart Desktop completely. Node.js 18 or newer must be on the PATH the desktop app sees.
Cursor
Section titled “Cursor”~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):
{ "mcpServers": { "hosttracker": { "url": "https://mcp.host-tracker.com/mcp", "headers": { "Authorization": "Bearer YOUR_HOSTTRACKER_API_TOKEN" } } }}VS Code (GitHub Copilot agent mode)
Section titled “VS Code (GitHub Copilot agent mode)”.vscode/mcp.json in the workspace. The inputs block keeps the token out of the file - VS Code prompts for it once
and stores it in its secret storage:
{ "inputs": [ { "type": "promptString", "id": "ht-token", "description": "HostTracker API token", "password": true } ], "servers": { "hosttracker": { "type": "http", "url": "https://mcp.host-tracker.com/mcp", "headers": { "Authorization": "Bearer ${input:ht-token}" } } }}Windsurf
Section titled “Windsurf”~/.codeium/windsurf/mcp_config.json:
{ "mcpServers": { "hosttracker": { "serverUrl": "https://mcp.host-tracker.com/mcp", "headers": { "Authorization": "Bearer YOUR_HOSTTRACKER_API_TOKEN" } } }}Some Windsurf versions use url instead of serverUrl; if the entry is ignored, try the other key.
Any other client
Section titled “Any other client”Any client that can dial a streamable-HTTP MCP endpoint and send a static header works:
URL https://mcp.host-tracker.com/mcpHeader Authorization: Bearer YOUR_HOSTTRACKER_API_TOKENA client that can launch a command but not send headers can use the bridge:
npx -y mcp-remote https://mcp.host-tracker.com/mcp --header "Authorization:${HT_AUTH}"with HT_AUTH set to Bearer YOUR_HOSTTRACKER_API_TOKEN in the environment.
Verify the connection
Section titled “Verify the connection”This handshake needs no token and proves the endpoint is reachable from your machine:
curl -sS https://mcp.host-tracker.com/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize", "params":{"protocolVersion":"2025-06-18","capabilities":{}, "clientInfo":{"name":"curl","version":"1"}}}'The reply is a text/event-stream frame whose data line carries serverInfo. Then ask the assistant: “use
hosttracker to run an http check on example.com”.
The tools
Section titled “The tools”65 tools: 63 curated ones (one API call each, small argument sets) plus a guarded generic door for everything else. The scope is what your token or OAuth connection needs.
How arguments are passed
Section titled “How arguments are passed”The tools take flat, simple arguments. Three shapes matter, and getting them wrong is the most common reason a call fails:
- Lists are comma-separated strings, not JSON arrays.
tags="prod,eu",monitorIds="ID1,ID2",alertTypes="down,up",events="monitor.down,monitor.up",componentIds="C1,C2". Passing["a","b"]to one of these is refused by the client or the server before anything runs. - Arguments whose name ends in
Jsontake a JSON document as a string.settingsJson="{\"keywords\":\"Checkout\"}",itemsJson="[{\"contact\":\"ID\",\"events\":[\"down\"]}]". Inside that string the members are exactly the REST API’s members. - Timestamps are Unix seconds (integers) and intervals are seconds.
A tool has only the arguments listed below. No tool takes an items or a scope argument, and none takes a raw
JSON array or object: where the REST body has one, the tool either takes a ...Json string or builds it for you
from comma-separated arguments (create_webhook builds scope from tags or monitorIds). Anything a tool does
not expose is reachable through api_request.
List tools take limit 1-50 (default 20; out-of-range values are clamped, not refused) and cursor from the
previous answer. Keep calling with the cursor until the answer has no continuation line.
Instant checks
Section titled “Instant checks”| Tool | What it does | Scope |
|---|---|---|
run_instant_check |
Runs a one-off check from HostTracker’s locations, polls up to about 30 s and returns per-location results plus the public result-page URL. A check still running comes back partial with the dbId and id to poll. |
check |
get_check_result |
Fetches the current results of an instant check. | check |
list_check_types |
Lists the instant-check types and the device profiles a page-load (waterfall) check can emulate. |
none |
run_instant_check
| Argument | Type | Required | Meaning |
|---|---|---|---|
url |
string | yes | The site or host, e.g. example.com or https://example.com. |
type |
string | no (default http) |
A type token from list_check_types: http, ping, port, trace, dns, dnsbl, whois, webRisk, crawl, waterfall (pageSpeed is accepted as an alias). |
pools |
string, comma-separated | no (default everywhere) | Pool ids to run from, e.g. westeurope,northamerica. An unknown id is refused with the valid ones. (The tool’s own example says europe; there is no europe pool - see Location pool ids.) |
device |
string | no | Device-emulation profile for a waterfall check, from list_check_types. |
strictTls |
boolean | no (default false) |
http only: fail the check on an untrusted, incomplete, mismatched or self-signed certificate. |
get_check_result
| Argument | Type | Required | Meaning |
|---|---|---|---|
dbId |
integer | yes | The dbId run_instant_check returned. |
id |
string (GUID) | yes | The check id run_instant_check returned. |
list_check_types takes no arguments.
Monitors
Section titled “Monitors”| Tool | What it does | Scope |
|---|---|---|
list_monitors |
Lists monitors; filters combine with AND. | monitor:read |
get_monitor |
Reads one monitor with its full configuration. | monitor:read |
create_monitor |
Creates one monitor (POST /monitor). Adds no subscriptions: attach contacts afterwards with subscribe_contact. |
monitor:write |
update_monitor |
Changes only the arguments you pass (PATCH /monitor/{id}). |
monitor:write |
delete_monitor |
Deletes one monitor and its subscriptions. Preview first, then confirmed=true. |
monitor:write |
pause_monitor |
Stops checking and alerting until resumed (sets enabled: false). |
monitor:write |
resume_monitor |
Resumes a paused monitor (sets enabled: true). |
monitor:write |
copy_monitor |
Copies a monitor to one or more new addresses. Many addresses answer with a job id. | monitor:write |
bulk_create_monitors |
Validates a batch; with submit=true creates it as an asynchronous job. |
monitor:write |
bulk_update_monitors |
Applies one patch to every monitor a filter selects; validates unless submit=true. |
monitor:write |
bulk_delete_monitors |
Deletes every monitor a filter selects; validates unless confirmed=true and expectedCount are both sent. |
monitor:write |
list_monitor_types |
Lists every monitor type with its label, minimum interval and whether your plan can create it. | none (a token adds your limits) |
list_monitors
| Argument | Type | Required | Meaning |
|---|---|---|---|
q |
string | no | Free-text search over name and url. |
state |
string, comma-separated | no | up, down, paused, maintenance. |
type |
string, comma-separated | no | Monitor type tokens, e.g. http,ping. |
tag |
string, comma-separated | no | Tags; a monitor matches when it carries any of them. |
id |
string, comma-separated | no | Monitor ids. |
sort |
string | no | name, state, type, interval, lastChange, url, tags or created; add :desc or :asc, e.g. lastChange:desc. |
limit, cursor |
integer, string | no | Paging (1-50, default 20). |
get_monitor
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The monitor id. |
expand |
string, comma-separated | no (default settings,uptime) |
Extra blocks: settings, uptime, lastResult, lastIncident, subscription, maintenance, attached, spans. |
from, to |
integer (Unix seconds) | no | Window for uptime and spans. |
create_monitor
| Argument | Type | Required | Meaning |
|---|---|---|---|
type |
string | yes | Monitor type token: http, api, ping, port, cntCheck, waterfall, tran, sslExp, domainExp, dnsbl, webRisk, database, snmp, counter (list_monitor_types is the live list). |
url |
string | for most types | The address to monitor. A Counter monitor may carry settings.probeUrl instead. |
name |
string | no (default: the url) | Display name. |
interval |
integer, seconds | no (default: the account’s default cadence) | Check interval. Must be one of the account’s allowed intervals and not below the type’s floor. |
tags |
string, comma-separated | no | Tags for the new monitor. |
pools |
string, comma-separated | yes for HTTP, API, ping, port, content check, page speed and transaction | Location pool ids, e.g. westeurope,easteurope,northamerica, or allworld for everywhere. Unlike the app, the API applies no account default. Refused for types that run on HostTracker’s own network (SSL expiry, domain expiry, DNSBL, Web Risk, database, SNMP, counter). |
enabled |
boolean | no (default true) |
false creates it paused. |
settingsJson |
string, JSON object | per type | Type-specific settings with their v2 names, e.g. {"keywords":"Checkout","keywordMode":"PresentAny"}. Fields per type: Monitor fields by type. |
dryRun |
boolean | no | true validates and previews, creating nothing. |
update_monitor
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The monitor id. |
name, url |
string | no | New name or address. |
interval |
integer, seconds | no | New interval. |
tags |
string, comma-separated | no | Replaces the whole tag set. Do not combine with addTags/removeTags. |
addTags |
string, comma-separated | no | Tags to add, keeping the others. |
removeTags |
string, comma-separated | no | Tags to remove, keeping the others. |
pools |
string, comma-separated | no | Replaces the location pools. |
settingsJson |
string, JSON object | no | Settings to change; members you leave out keep their stored values. |
The type cannot be changed, and enabled is changed with pause_monitor / resume_monitor.
delete_monitor, pause_monitor, resume_monitor
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The monitor id. |
confirmed |
boolean | delete_monitor only (default false) |
Without it the tool only shows the monitor it would delete. |
copy_monitor
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The monitor to copy from. |
urls |
string, comma-separated | yes | The new addresses, one copy each. |
includeAlerts |
boolean | no (default true) |
Copy the alert subscriptions. |
includeReports |
boolean | no (default true) |
Copy the report subscriptions. |
includeMaintenance |
boolean | no (default true) |
Copy the maintenance-window coverage. |
name |
string | no (default: the address) | Name for the copies. |
bulk_create_monitors
| Argument | Type | Required | Meaning |
|---|---|---|---|
itemsJson |
string, JSON array | yes | Monitor definitions, each shaped like a POST /monitor body: [{"type":"http","url":"a.com","locations":{"pools":["allworld"]}}]. |
defaultsJson |
string, JSON object | no | Members applied to every item, e.g. {"interval":300,"tags":["prod"]}. |
submit |
boolean | no (default false) |
false returns the validation report only; true creates the batch as a job. |
idempotencyKey |
string | no (generated) | Reuse it on a retry so the batch is not created twice. |
bulk_update_monitors
| Argument | Type | Required | Meaning |
|---|---|---|---|
filterJson |
string, JSON object | yes | The selection: any of monitorIds, tags, types, states, enabled, q, e.g. {"tags":["prod"]}. |
patchJson |
string, JSON object | one of patchJson / operation |
The change applied to each selected monitor, e.g. {"interval":300} or {"addTags":["eu"]}. |
operation |
string | one of patchJson / operation |
resetStats clears the statistics instead of patching. |
submit |
boolean | no (default false) |
false returns the count and a sample only; true applies it as a job. |
idempotencyKey |
string | no (generated) | Reuse it on a retry. |
bulk_delete_monitors
| Argument | Type | Required | Meaning |
|---|---|---|---|
filterJson |
string, JSON object | yes | The selection, as for bulk_update_monitors. |
expectedCount |
integer | to delete | The matched count the validation step reported. |
confirmed |
boolean | to delete (default false) |
Needed together with expectedCount. Without both, the tool only validates. |
idempotencyKey |
string | no (generated) | Reuse it on a retry. |
list_monitor_types takes no arguments.
Results and incidents
Section titled “Results and incidents”| Tool | What it does | Scope |
|---|---|---|
get_uptime_summary |
Uptime, SLA and response-time figures over a window (GET /monitor/result/summary). |
monitor:read |
list_monitor_results |
One monitor’s raw check results, newest first. | monitor:read |
list_incidents |
Down-episodes across the account or chosen monitors, newest first. | monitor:read |
get_incident |
One incident with the transitions that opened and closed it. | monitor:read |
comment_incident |
Sets a note on an incident; it replaces any previous one. | monitor:write |
get_uptime_summary
| Argument | Type | Required | Meaning |
|---|---|---|---|
monitor |
string, comma-separated | yes | Monitor ids, up to 500. For a whole-account figure pass monitor="" together with groupBy="account". |
from, to |
integer (Unix seconds) | no (default: the last 30 days) | The window. |
bucket |
string | no (default none) |
none (one row per monitor), hour, day, week or month. |
groupBy |
string | no (default monitor) |
monitor or account (one row for the whole selection; window up to 30 days). |
sla |
number | no | A target percentage, e.g. 99.9; adds slaMet and errorBudgetSecRemaining. |
metrics |
string, comma-separated | no | responseTime, dns, connect, tls, ttfb, transfer. |
limit, cursor |
integer, string | no | Paging. |
This tool has no expand and no sort argument. Rows come back ordered by monitor id, not by uptime - sort them
yourself (see Sort a summary). For
incident counts per row, call the API through api_request with expand=incidentCounts.
list_monitor_results
| Argument | Type | Required | Meaning |
|---|---|---|---|
monitorId |
string | yes | The monitor id. |
from, to |
integer (Unix seconds) | no | The window (at most 30 days). |
state |
string, comma-separated | no | up, down. |
location |
string, comma-separated | no | Location (agent) ids from list_locations(agents=true). The tool text says names; the API takes ids. |
expand |
string, comma-separated | no | metrics, recheck. |
limit, cursor |
integer, string | no | Paging. |
list_incidents
| Argument | Type | Required | Meaning |
|---|---|---|---|
monitor |
string, comma-separated | no (default: the whole account) | Monitor ids. |
state |
string, comma-separated | no | open, resolved. |
severity |
string, comma-separated | no | minor, major, critical. |
from, to |
integer (Unix seconds) | no | Incidents that overlap this window (not clipped to it). |
limit, cursor |
integer, string | no | Paging. |
get_incident: id (string, required - the incident id), expand (string, comma-separated, optional:
monitor, recheck).
comment_incident: id (string, required), comment (string, required - replaces any previous comment).
Maintenance windows
Section titled “Maintenance windows”| Tool | What it does | Scope |
|---|---|---|
list_maintenance |
Lists windows. | monitor:read |
create_maintenance |
Schedules a window over an explicit list of monitors (POST /maintenance). |
monitor:write |
update_maintenance |
Changes only what you pass. | monitor:write |
delete_maintenance |
Cancels a window. Cancelling an active window makes its monitors alert again at once. | monitor:write |
list_maintenance
| Argument | Type | Required | Meaning |
|---|---|---|---|
state |
string, comma-separated | no | scheduled, active, finished. |
monitor |
string, comma-separated | no | Monitor ids. |
from, to |
integer (Unix seconds) | no | The window. |
limit, cursor |
integer, string | no | Paging. |
create_maintenance
| Argument | Type | Required | Meaning |
|---|---|---|---|
name |
string | yes | Window name. |
from |
integer (Unix seconds) | yes | Start instant. |
monitorIds |
string, comma-separated | yes | The monitors it covers - a fixed list; there is no tag selector. |
durationSec |
integer | one of durationSec / to |
Length in seconds. |
to |
integer (Unix seconds) | one of durationSec / to |
End instant. Sending both is refused. |
timezone |
string | no (default UTC) |
IANA zone, e.g. Europe/Berlin; matters for weekly windows. |
suppressAlerts |
boolean | no | Suppress alerts. See the note below. |
suppressStats |
boolean | no | Exclude the window from uptime statistics. |
weekDays |
string, comma-separated | no | Makes it a weekly window, e.g. Saturday,Sunday. |
When you send neither suppressAlerts nor suppressStats, the window suppresses alerts only. When you send
either one, the other counts as false - so for “silence alerts and exclude from statistics” send both
suppressAlerts=true and suppressStats=true. Sending both as false is refused.
update_maintenance
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The window id. |
name, timezone |
string | no | New name or zone. |
from, to |
integer (Unix seconds) | no | New start or end. |
durationSec |
integer | no | New length. |
monitorIds |
string, comma-separated | no | Replaces the coverage. |
enabled |
boolean | no | Switch the window off or on without deleting it. |
This tool cannot change the suppression flags, the weekly days or showOnStatusPage; use api_request with
PATCH /maintenance/{id} for those.
delete_maintenance: id (string, required), confirmed (boolean, default false - without it the tool only
shows the window).
Contacts and contact groups
Section titled “Contacts and contact groups”| Tool | What it does | Scope |
|---|---|---|
list_contacts |
Lists contacts. An unconfirmed contact receives nothing until confirmed. | contact:read |
get_contact |
Reads one contact. | contact:read |
create_contact |
Meant to create an email, sms, voiceCall or webPush contact - see the caution below. |
contact:write |
update_contact |
Partially updates a contact. Changing the address re-triggers confirmation. | contact:write |
delete_contact |
Deletes a contact and every subscription it had. Preview first, then confirmed=true. |
contact:write |
send_contact_confirmation |
Sends (or resends) the confirmation code. The code is never returned to the assistant - ask the person for it. | contact:write |
confirm_contact |
Confirms a contact with the code it received. | contact:write |
test_contact |
Sends a real test alert to a confirmed contact and reports how delivery ended. SMS and voice may cost balance. | contact:write |
list_contact_groups |
Lists contact groups. | contact:read |
create_contact_group |
Creates a named set of contacts, each with the events it should receive. | contact:write |
update_contact_group |
Renames a group and/or replaces its membership. | contact:write |
delete_contact_group |
Deletes a group; the contacts themselves stay. | contact:write |
list_contacts
| Argument | Type | Required | Meaning |
|---|---|---|---|
q |
string | no | Free-text search over name and address. |
type |
string, comma-separated | no | Contact types, e.g. email,sms. |
confirmed |
boolean | no | true only confirmed, false only unconfirmed. |
id |
string, comma-separated | no | Contact ids. |
limit, cursor |
integer, string | no | Paging. |
get_contact: id (string, required), expand (string, comma-separated, optional: subscription,
template, group).
create_contact
| Argument | Type | Required | Meaning |
|---|---|---|---|
type |
string | yes | email, sms, voiceCall or webPush. |
address |
string | yes | An email address, or a phone number in international format. |
name |
string | no | Display name. |
language |
string | no | Message language code, e.g. en. |
alertDelay |
integer, minutes | no | Delay before an alert is sent to this contact (one of the published delay steps). |
update_contact
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The contact id. |
name, address, language |
string | no | New values. A new address must be confirmed again. |
alertDelay |
integer, minutes | no | New alert delay. |
groupedAlerts |
boolean | no | Group several alerts into one message. |
delete_contact: id (string, required), confirmed (boolean, default false).
send_contact_confirmation: id (string, required).
confirm_contact: id (string, required), code (string, required - the 5-digit code the person received).
test_contact: id (string, required), alertType (string, optional: up, down or repeatedlyDown).
list_contact_groups: limit, cursor.
create_contact_group
| Argument | Type | Required | Meaning |
|---|---|---|---|
name |
string | yes | Group name. |
itemsJson |
string, JSON array | yes | The members: [{"contact":"CONTACT_ID","events":["down","up"]}]. Events: up, down, repeatedlyDown, daily, weekly, monthly, quarterly, yearly. |
Example: create_contact_group(name="On-call", itemsJson="[{\"contact\":\"ID1\",\"events\":[\"down\",\"up\"]},{\"contact\":\"ID2\",\"events\":[\"down\",\"up\"]}]").
A group does not subscribe anyone by itself - see Contact groups.
update_contact_group: id (string, required), name (string, optional), itemsJson (string, JSON array,
optional - replaces the whole membership). delete_contact_group: id (string, required), confirmed
(boolean, default false).
Subscriptions
Section titled “Subscriptions”| Tool | What it does | Scope |
|---|---|---|
list_subscriptions |
Who is notified about what. | subs:read |
subscribe_contact |
Subscribes one contact to one monitor (PUT /monitor/{id}/alert/{contactId} and/or .../report/{contactId}). |
monitor:write |
unsubscribe_contact |
Removes one contact’s subscription to one monitor. | monitor:write |
list_subscriptions
| Argument | Type | Required | Meaning |
|---|---|---|---|
kind |
string | no (default alert) |
alert or report. |
monitorId, contactId |
string, comma-separated | no | Filter by monitor ids and/or contact ids. |
monitorQuery, contactQuery |
string | no | Free-text search over monitors or contacts. |
limit, cursor |
integer, string | no | Paging. |
subscribe_contact
| Argument | Type | Required | Meaning |
|---|---|---|---|
monitorId |
string | yes | The monitor id. |
contactId |
string | yes | The contact id. |
alertTypes |
string, comma-separated | one of alertTypes / frequencies |
up, down, repeatedlyDown. Replaces this pair’s alert set. |
frequencies |
string, comma-separated | one of alertTypes / frequencies |
daily, weekly, monthly, quarterly, yearly (email contacts). Replaces this pair’s report set. |
unsubscribe_contact: monitorId, contactId (strings, required), kind (string, optional: alert,
report or both, default both).
For many monitors x contacts at once there is no curated tool: use api_request with POST /alert/bulk or
POST /report/bulk (both need confirmed=true, see The confirmation rule),
or repeat subscribe_contact per pair.
Webhooks
Section titled “Webhooks”| Tool | What it does | Scope |
|---|---|---|
list_webhooks |
Lists webhooks with their enabled state and recent failure count. | webhook:read |
create_webhook |
Registers an https webhook for chosen events. The signing secret is returned once. | webhook:write |
update_webhook |
Changes url, events, monitor scope, name or enabled state. Re-enabling clears the failure counter. | webhook:write |
delete_webhook |
Unregisters a webhook; pending deliveries are dropped. Preview first, then confirmed=true. |
webhook:write |
test_webhook |
Sends a synthetic delivery and reports the endpoint’s answer. | webhook:write |
list_webhook_deliveries |
Recent deliveries of one webhook with outcome and attempts. | webhook:read |
redeliver_webhook |
Resends a recorded delivery with the same delivery id. | webhook:write |
create_webhook
| Argument | Type | Required | Meaning |
|---|---|---|---|
url |
string | yes | The public https endpoint. |
events |
string, comma-separated | yes | Event names, e.g. monitor.down,monitor.up. The list is in Webhook events. |
name |
string | no | Display name. |
monitorIds |
string, comma-separated | no | Deliver only for these monitors. |
tags |
string, comma-separated | no | Deliver only for monitors carrying these tags. |
Send at most one of monitorIds and tags; with neither, the webhook covers the whole account. Sending both is
refused by the API (a scope names exactly one form). There is no scope argument - the tool builds the REST
scope object from these two. Example: create_webhook(url="https://hooks.example.com/ht", events="monitor.down,monitor.up", tags="prod", name="Prod down/up").
update_webhook
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The webhook id. |
url, name |
string | no | New endpoint or name. |
events |
string, comma-separated | no | Replaces the event set. |
enabled |
boolean | no | Enable or disable deliveries. |
monitorIds |
string, comma-separated | no | Replaces the scope with these monitors. To scope by tags or back to the whole account, use api_request with PATCH /webhook/{id} and a scope object. |
delete_webhook: id, confirmed (default false). test_webhook: id, eventName (optional, e.g.
monitor.down). redeliver_webhook: id, deliveryId (the d_... id from list_webhook_deliveries).
list_webhooks: limit, cursor.
list_webhook_deliveries
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The webhook id. |
outcome |
string, comma-separated | no | pending, delivered, failed, dropped. |
eventName |
string, comma-separated | no | Event names. |
from, to |
integer (Unix seconds) | no | The window. |
limit, cursor |
integer, string | no | Paging. |
Status pages
Section titled “Status pages”| Tool | What it does | Scope |
|---|---|---|
list_status_pages |
Lists your status pages. | statuspage:read |
get_status_page |
Reads one page with its settings and components. | statuspage:read |
create_status_page |
Creates a page. It is public at its slug immediately. | statuspage:write |
update_status_page |
Changes the title and/or settings. | statuspage:write |
delete_status_page |
Deletes a page with its components, incidents and subscribers. Preview first, then confirmed=true. |
statuspage:write |
create_status_page_incident |
Publishes an incident or a scheduled maintenance on a page and notifies its subscribers. | statuspage:write |
add_status_page_incident_update |
Appends an update to an incident’s timeline and moves its state. Notifies subscribers. | statuspage:write |
create_status_page
| Argument | Type | Required | Meaning |
|---|---|---|---|
slug |
string | yes | The page’s permanent address; must be unique. |
title |
string | yes | Title shown to visitors. |
componentsJson |
string, JSON array | no | [{"monitorId":"ID","name":"API","group":"Core"}]. |
settingsJson |
string, JSON object | no | Page settings with their v2 names, e.g. {"slaTarget":99.9,"showGroups":true,"features":["barCharts","uptimePercent"]} - see Create a status page. |
update_status_page
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The page id. |
title |
string | no | New title. |
settingsJson |
string, JSON object | no | Settings to change. They are merged field by field: members you leave out keep their values, and only features replaces its whole set. (The tool’s own text says it replaces the settings object; it does not.) |
Components are replaced with api_request and PUT /statuspage/{id}/component.
create_status_page_incident
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The status page id. |
title |
string | yes | Headline. |
message |
string | yes | The first timeline message. |
state |
string | no (default investigating) |
investigating, identified, monitoring or resolved. |
kind |
string | no (default incident) |
incident or maintenance. |
impact |
string | no | minor or major. |
componentIds |
string, comma-separated | no | Component ids from get_status_page - "C1,C2", not a JSON array. |
scheduledStart, scheduledEnd |
integer (Unix seconds) | for kind="maintenance" |
The planned window. |
idempotencyKey |
string | no (generated) | Reuse it on a retry so the post is not published twice. |
add_status_page_incident_update
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | The status page id. |
incidentId |
string | yes | The incident id. |
message |
string | yes | The update text. |
state |
string | yes | investigating, identified, monitoring or resolved. |
idempotencyKey |
string | no (generated) | Reuse it on a retry. |
get_status_page: id. delete_status_page: id, confirmed (default false).
list_status_pages: limit, cursor.
Reports, jobs, account and locations
Section titled “Reports, jobs, account and locations”| Tool | What it does | Scope |
|---|---|---|
generate_report |
Requests an uptime report over monitors and a time range; answers with a job id. | monitor:write (the tool’s text says monitor:read; the API requires write) |
list_report_types |
Lists report types, formats, sections and schedules. | none |
get_job |
One asynchronous job: state, progress and per-item results. | the scope of the job’s operation |
wait_for_job |
Polls a job for up to about 30 s; call again if it is still running. | the scope of the job’s operation |
cancel_job |
Cancels a queued or running job. Finished items are not rolled back. | the scope of the job’s operation |
resume_job |
Continues a job whose state is interrupted. |
the scope of the job’s operation |
get_account |
Identity, package, usage, limits and status flags. Read-only. | account:read (a token; OAuth connections never get it) |
get_account_quota |
API quota headroom and the scopes the current token carries - the first call to make after a 403. | account:read |
get_account_usage |
How many monitors, contacts, reports and maintenance windows the account uses out of its plan. | account:read |
list_locations |
Location pools (and with agents=true, individual locations). |
none |
generate_report
| Argument | Type | Required | Meaning |
|---|---|---|---|
monitorIds |
string, comma-separated | yes | Up to 500 monitors. |
from, to |
integer (Unix seconds) | no (default: the last 30 days) | The range. |
format |
string | no (default pdf) |
pdf, csv, xml or html. |
sections |
string, comma-separated | no (default stats) |
state, stats, outages, incidents, log. |
timezone |
string | no | IANA zone the report is rendered in. |
language |
string | no | Report language code, e.g. en. |
idempotencyKey |
string | no (generated) | Reuse it on a retry. |
get_job: id (string, required), limit (1-50, default 20 per-item results), cursor.
wait_for_job, cancel_job, resume_job: id (string, required).
list_report_types, get_account, get_account_quota and get_account_usage take no arguments.
list_locations
| Argument | Type | Required | Meaning |
|---|---|---|---|
agents |
boolean | no (default false) |
true lists individual locations instead of pools. |
country |
string, comma-separated | no | ISO country codes (with agents=true). |
pool |
string, comma-separated | no | Pool ids (with agents=true). |
limit, cursor |
integer, string | no (default 50) | Paging. |
Location pool ids
Section titled “Location pool ids”pools arguments take pool ids from list_locations (REST GET /agent/pool). The ones most requests need:
| Pool id | Where |
|---|---|
allworld |
Every location |
westeurope |
Western Europe |
easteurope |
Eastern Europe |
northamerica |
North America |
southamerica |
South America |
asia |
Asia |
australia |
Australia |
africa |
Africa |
There is no single europe pool: for “Europe” send westeurope,easteurope. The app’s default for a new monitor,
when the account has no defaults of its own, is westeurope,easteurope,northamerica. The pool list is data, not a
fixed enum - an account may also see private pools of its own - so confirm an id with list_locations when in
doubt; an unknown id is refused with 422 unknown_pool and the list of valid ones. A selection with too few
locations answers 422 insufficient_agents. See Monitoring locations.
Anything else
Section titled “Anything else”| Tool | What it does | Scope |
|---|---|---|
describe_api |
Searches the real v2 operations (paths, parameters, body members) so a call can be built from the contract. | none |
api_request |
Calls any v2 operation no curated tool covers. The method and path must match a real operation. | the operation’s own scope |
describe_api: search (string, optional - a path or operation-id fragment such as /alert, statuspage,
createWebhook; omit it to list every path).
api_request
| Argument | Type | Required | Meaning |
|---|---|---|---|
method |
string | yes | GET, POST, PATCH, PUT or DELETE. |
path |
string | yes | The v2 path with ids filled in, e.g. /monitor/ID/incident. No host, no version prefix. |
query |
string | no | A query string (limit=10&state=down) or a flat JSON object of parameters. |
bodyJson |
string, JSON | no | The request body, for POST/PATCH/PUT. |
idempotencyKey |
string | no | Sent as the Idempotency-Key header. Not generated for you - pass one wherever the operation requires it (below). |
confirmed |
boolean | no (default false) |
Must be true for the calls the confirmation rule covers. |
The api_request confirmation rule
Section titled “The api_request confirmation rule”api_request refuses a call before sending anything unless confirmed=true when:
- the method is
DELETE(any path), or - the method is
POST,PATCHorPUTand the path contains/bulkand does not end in/validate.
No v2 path ends in /validate - the dry runs are spelled ...-validate - so today the second rule covers every
bulk door and its dry run:
Needs confirmed=true through api_request |
What it is |
|---|---|
POST /alert/bulk, POST /report/bulk |
Many alert or report subscriptions in one transaction (answers directly, no job, no dry run) |
POST /monitor/bulk, POST /monitor/bulk-update, POST /monitor/bulk-delete |
Bulk monitor jobs |
POST /contact/bulk, POST /contact/bulk-delete |
Bulk contact jobs |
POST /monitor/bulk-validate, /monitor/bulk-update-validate, /monitor/bulk-delete-validate, /contact/bulk-validate, /contact/bulk-delete-validate |
The read-only dry runs (they change nothing, but the rule still asks for confirmed=true) |
every DELETE |
Deletes, unsubscribes, cancelling a maintenance window |
A ?dryRun=true in query does not exempt a call - only the method and path are checked. Every other call
(GET, and writes such as POST /contact, PUT /monitor/{id}/alert/{contactId}, PATCH /statuspage/{id}) runs
without confirmed. The refusal says the call was not executed; show the user what it will do, then repeat it with
confirmed=true. For monitor bulk work prefer the curated bulk_*_monitors tools: they run the dry run for you
without any confirmation flag.
Operations that need idempotencyKey through api_request (the API answers 400 idempotency_key_required
otherwise): POST /monitor/bulk, /monitor/bulk-update, /monitor/bulk-delete, /contact/bulk,
/contact/bulk-delete, POST /monitor/report, POST /monitor/{id}/reset-stats,
POST /statuspage/{id}/incident, POST /statuspage/{id}/incident/{incidentId}/timeline, POST /contact for an
email, sms or voiceCall contact, and POST /monitor when the body carries inline contacts. Sending a key on
any other write is harmless.
Writes under /account are always refused, whatever the token allows.
How the tools behave
Section titled “How the tools behave”- Deletes preview first. Every single-resource delete tool deletes nothing on its first call - it returns the
live resource so the assistant can confirm with you. Only a repeat call with
confirmed=truedeletes, and the API then returns a receipt of what was removed.api_requestdoes not preview: withoutconfirmed=trueit refuses aDELETEor bulk call outright and sends nothing. - Bulk writes validate first. The bulk tools return the validation report; the write needs
submit=true, and a bulk delete also needsconfirmed=trueplus the validatedexpectedCount. If the selection changed in between, the API refuses with409 selection_mismatchand deletes nothing. - Async work returns a job. Bulk operations, multi-address copies and report generation answer with a job id;
poll it with
wait_for_job. - Publishing is real. Status page incidents and updates go to the public page and to its subscribers at once. Contact tests and confirmations send real messages.
- Errors come back as tool results. A missing scope, a quota, a validation refusal or a blacklisted URL
returns an actionable message naming the problem code.
Retry-Afteris passed through as a value; the server never retries or waits on its own. - Untrusted content is fenced. Text a monitored target or a third-party endpoint controls (check errors, webhook response excerpts) is wrapped and length-capped so it cannot pass instructions to the assistant.
What the server never does
Section titled “What the server never does”These refusals are built into the server and apply whatever your token allows:
- Any write under
/account(profile, email, country, default pools). Account reads stay open. - Payments, packages and plan changes, passwords, sign-in and account recovery - none of these are on the API.
- Minting or revoking API tokens. A token cannot mint another token.
Troubleshooting
Section titled “Troubleshooting”- Every call is refused for permissions. The refusal names the required and granted scopes. On OAuth, remove and
re-add the connector and approve the wider set. On a token, run
get_account_quotato see its scopes, then mint a new token - scopes cannot be added to an existing one. - The client connects but lists no tools. The client probably dropped the
Authorizationheader; test the same token withcurland atools/listcall. - The consent page says the app is not registered. The client’s registration expired (registrations with no approved connection are cleaned up after about 30 days). Remove and re-add the connector.
- Rate-limit or quota messages. The endpoint limits requests per client IP, and your plan’s API quota applies to the token. The message says which one bound and, when known, when it resets.
mcp-remotestarts and exits. Usually Node.js older than 18, a header argument split on its space (pass it asAuthorization:${HT_AUTH}with the value in the environment), or a stale session under~/.mcp-auth, which you can delete.- A corporate proxy breaks the stream. Streamable HTTP holds a long-lived response; allow
mcp.host-tracker.comthrough without buffering. - A token leaked. Tokens cannot be revoked before they expire. Remove it from every client, mint a replacement with a short expiration, and contact [email protected] (never include the token itself).

