fettle-mcp 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/contracts/mcp_tools.json +14 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -229,19 +229,21 @@ humans and for clients that do not surface server instructions.
|
|
|
229
229
|
Fettle is an uptime monitoring service. The tools see only the API key's organization: monitors, heartbeats, maintenance windows, incidents, status page incidents, tags, channels (read), regions. Channels, status pages, members, API keys and billing are managed only in the dashboard (https://dashboard.fettle.sh). Read a tool's description (arguments, limits, errors) before its first call.
|
|
230
230
|
|
|
231
231
|
FINDING THINGS
|
|
232
|
-
- list_monitors
|
|
232
|
+
- list_monitors: one short row per monitor, to find ids. Filters are JSON arrays. Broken now: status ["DOWN", "DEGRADED"]. Certificates expiring first: type ["SSL"], sort "ssl_expiry".
|
|
233
233
|
- tag filters lists; tag_match "all" (default) needs every tag, "any" one of them.
|
|
234
|
-
-
|
|
234
|
+
- Pages: page from 1, size 1..100 (default 25).
|
|
235
235
|
|
|
236
236
|
PLAN LIMITS
|
|
237
237
|
Call get_plan_usage before creating anything: limits (null means none) and usage. A broken limit or an unknown region is a 403 naming it: change the request or tell the user; never retry it unchanged.
|
|
238
238
|
|
|
239
239
|
CREATING MONITORS
|
|
240
|
-
- check_target probes a target once before create_monitor.
|
|
240
|
+
- check_target probes a target once before create_monitor.
|
|
241
|
+
- regions: unless the user names some, use every limits.allowed_regions code, up to max_regions; SSL, DNS and port-list TCP take one.
|
|
242
|
+
- After create, tell the user the interval and regions chosen; offer to change the interval (update_monitor).
|
|
241
243
|
- bulk_create_monitors creates up to 100, all or nothing.
|
|
242
244
|
- type and target never change after create.
|
|
243
|
-
- channel_ids: ids from list_channels. Empty or omitted on create alerts every verified, active channel. Email is not a channel: every alert also
|
|
244
|
-
- update tools change only the fields you pass
|
|
245
|
+
- channel_ids: ids from list_channels. Empty or omitted on create alerts every verified, active channel. Email is not a channel: every alert also emails the creator of the monitor or heartbeat.
|
|
246
|
+
- update tools change only the fields you pass; omit one to keep it, never send null. A monitor's config is replaced whole: resend every config field to keep.
|
|
245
247
|
- Exposed ports on a server: follow get_exposed_ports_preset.
|
|
246
248
|
|
|
247
249
|
MANY MONITORS AT ONCE
|
|
@@ -265,7 +267,7 @@ ERRORS (start of a failed call's text)
|
|
|
265
267
|
- "Invalid argument(s)": names each failing field. "Invalid request:": the rule broken. Fix, retry.
|
|
266
268
|
- "Forbidden:": a plan limit, an unknown region, or the key's user lacks the permission; the reason says which.
|
|
267
269
|
- "Not found:": no such id in this organization.
|
|
268
|
-
- "Rate limited": wait the seconds given, then retry. All API
|
|
270
|
+
- "Rate limited": wait the seconds given, then retry. All API keys share the organization's per-minute budget.
|
|
269
271
|
- "Tool '<name>' failed: the API returned 5xx": server fault, retry once later.
|
|
270
272
|
- "Tool '<name>' does not accept argument(s)": drop the ones named.
|
|
271
273
|
- "Request failed with status N": read the reason, do not retry unchanged.
|
package/contracts/mcp_tools.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"instructions": "Fettle is an uptime monitoring service. The tools see only the API key's organization: monitors, heartbeats, maintenance windows, incidents, status page incidents, tags, channels (read), regions. Channels, status pages, members, API keys and billing are managed only in the dashboard (https://dashboard.fettle.sh). Read a tool's description (arguments, limits, errors) before its first call.\n\nFINDING THINGS\n- list_monitors
|
|
3
|
+
"instructions": "Fettle is an uptime monitoring service. The tools see only the API key's organization: monitors, heartbeats, maintenance windows, incidents, status page incidents, tags, channels (read), regions. Channels, status pages, members, API keys and billing are managed only in the dashboard (https://dashboard.fettle.sh). Read a tool's description (arguments, limits, errors) before its first call.\n\nFINDING THINGS\n- list_monitors: one short row per monitor, to find ids. Filters are JSON arrays. Broken now: status [\"DOWN\", \"DEGRADED\"]. Certificates expiring first: type [\"SSL\"], sort \"ssl_expiry\".\n- tag filters lists; tag_match \"all\" (default) needs every tag, \"any\" one of them.\n- Pages: page from 1, size 1..100 (default 25).\n\nPLAN LIMITS\nCall get_plan_usage before creating anything: limits (null means none) and usage. A broken limit or an unknown region is a 403 naming it: change the request or tell the user; never retry it unchanged.\n\nCREATING MONITORS\n- check_target probes a target once before create_monitor.\n- regions: unless the user names some, use every limits.allowed_regions code, up to max_regions; SSL, DNS and port-list TCP take one.\n- After create, tell the user the interval and regions chosen; offer to change the interval (update_monitor).\n- bulk_create_monitors creates up to 100, all or nothing.\n- type and target never change after create.\n- channel_ids: ids from list_channels. Empty or omitted on create alerts every verified, active channel. Email is not a channel: every alert also emails the creator of the monitor or heartbeat.\n- update tools change only the fields you pass; omit one to keep it, never send null. A monitor's config is replaced whole: resend every config field to keep.\n- Exposed ports on a server: follow get_exposed_ports_preset.\n\nMANY MONITORS AT ONCE\nFind ids with list_monitors, then bulk_pause_monitors, bulk_resume_monitors or bulk_update_monitors (interval, timeout, regions, channels, threshold, cooldown) for up to 100 ids, all or nothing. bulk_update_monitor_tags adds or removes tags on up to 300. There is no bulk delete.\n\nTAGS\nCall list_tags first and reuse names. Tags are flat labels such as env:prod, trimmed, lowercased and deduplicated; at most 10 per item. rename_tag and delete_tag act on every monitor and heartbeat.\n\nHEARTBEATS\nA job calls ping_url when it succeeds. Job every N seconds, alert after T seconds of silence: period_seconds = N, grace_seconds = T - N. Never late before its first success ping. ping_url + \"/start\" restarts the clock, ping_url + \"/fail\" marks it DOWN at once.\n\nMAINTENANCE\nBefore a deploy or reboot, create_maintenance_window (scope ORG or MONITOR) instead of pausing monitors: checks keep running, but no incident opens and no alert goes out. Not for heartbeats. preview_maintenance_window shows a schedule's next occurrences; list_active_maintenance shows what is silenced now.\n\nOUTAGES\nlist_monitors status [\"DOWN\"] -> list_check_results (status code, error, region per check) -> get_incident. acknowledge_incident stops repeat alerts; the recovery alert still goes out. create_status_page_incident and post_status_page_update can email the page's subscribers: confirm the text with the user first.\n\nERRORS (start of a failed call's text)\n- \"Authentication failed\": the key is missing, revoked or expired, the address is not allowed, or its creator lost access. Do not retry; tell the user.\n- \"This tool requires/needs an API key with write scope\": the key is read-only; tell the user.\n- \"Invalid argument(s)\": names each failing field. \"Invalid request:\": the rule broken. Fix, retry.\n- \"Forbidden:\": a plan limit, an unknown region, or the key's user lacks the permission; the reason says which.\n- \"Not found:\": no such id in this organization.\n- \"Rate limited\": wait the seconds given, then retry. All API keys share the organization's per-minute budget.\n- \"Tool '<name>' failed: the API returned 5xx\": server fault, retry once later.\n- \"Tool '<name>' does not accept argument(s)\": drop the ones named.\n- \"Request failed with status N\": read the reason, do not retry unchanged.\n",
|
|
4
4
|
"tools": [
|
|
5
5
|
{
|
|
6
6
|
"name": "list_monitors",
|
|
@@ -436,7 +436,7 @@
|
|
|
436
436
|
{
|
|
437
437
|
"name": "create_monitor",
|
|
438
438
|
"title": "Create a monitor",
|
|
439
|
-
"description": "Create one monitor that checks a URL, host or port on a schedule from one or more regions, and return it in the get_monitor shape. Use check_target first to catch a typo or an unreachable host; use bulk_create_monitors for several monitors, and create_heartbeat for a job that should report in rather than be probed. Requires a key with the write scope. Plan limits apply (monitor count, minimum interval, monitors faster than 60 seconds, regions per monitor): breaking one is a 403 naming it, so call get_plan_usage first. A paused monitor still counts toward them. An invalid argument is a 422 naming it. Example: {\"name\": \"API\", \"type\": \"HTTP\", \"target\": \"https://api.example.com/health\", \"interval_seconds\":
|
|
439
|
+
"description": "Create one monitor that checks a URL, host or port on a schedule from one or more regions, and return it in the get_monitor shape. Use check_target first to catch a typo or an unreachable host; use bulk_create_monitors for several monitors, and create_heartbeat for a job that should report in rather than be probed. Requires a key with the write scope. Plan limits apply (monitor count, minimum interval, monitors faster than 60 seconds, regions per monitor): breaking one is a 403 naming it, so call get_plan_usage first. A paused monitor still counts toward them. An invalid argument is a 422 naming it. The example shows the shape for a plan with one region per monitor; take interval_seconds and regions from the user and get_plan_usage, not from it. Example: {\"name\": \"API\", \"type\": \"HTTP\", \"target\": \"https://api.example.com/health\", \"interval_seconds\": 600, \"timeout_seconds\": 10, \"regions\": [\"us-east\"], \"config\": {\"expected_status_codes\": [200]}, \"tags\": [\"env:prod\"]}",
|
|
440
440
|
"scope": "write",
|
|
441
441
|
"input_schema": {
|
|
442
442
|
"type": "object",
|
|
@@ -468,7 +468,7 @@
|
|
|
468
468
|
"maximum": 86400,
|
|
469
469
|
"minimum": 30,
|
|
470
470
|
"type": "integer",
|
|
471
|
-
"description": "Seconds between checks, 30 to 86400. The plan sets a minimum (limits.min_interval_seconds) and caps how many monitors may check more often than every 60 seconds (max_fast_monitors); breaking either is a 403 naming the limit."
|
|
471
|
+
"description": "Seconds between checks, 30 to 86400. The plan sets a minimum (limits.min_interval_seconds) and caps how many monitors may check more often than every 60 seconds (max_fast_monitors); breaking either is a 403 naming the limit. Tell the user the interval you chose."
|
|
472
472
|
},
|
|
473
473
|
"timeout_seconds": {
|
|
474
474
|
"maximum": 120,
|
|
@@ -482,7 +482,7 @@
|
|
|
482
482
|
},
|
|
483
483
|
"minItems": 1,
|
|
484
484
|
"type": "array",
|
|
485
|
-
"description": "One or more distinct region codes
|
|
485
|
+
"description": "One or more distinct region codes: the plan's choices are limits.allowed_regions in get_plan_usage. An unknown code, or more regions than max_regions, is a 403. SSL, DNS and TCP monitors with a ports list take exactly one region (422 otherwise). Unless the user names regions, pass every code in limits.allowed_regions, up to the plan's max_regions."
|
|
486
486
|
},
|
|
487
487
|
"config": {
|
|
488
488
|
"additionalProperties": true,
|
|
@@ -493,7 +493,7 @@
|
|
|
493
493
|
"maximum": 10,
|
|
494
494
|
"minimum": 1,
|
|
495
495
|
"type": "integer",
|
|
496
|
-
"description": "How many checks in a row must fail in every region before the monitor goes DOWN and an incident opens, 1 to 10;
|
|
496
|
+
"description": "How many checks in a row must fail in every region before the monitor goes DOWN and an incident opens, 1 to 10; 2 when not set on create."
|
|
497
497
|
},
|
|
498
498
|
"notification_cooldown_seconds": {
|
|
499
499
|
"maximum": 86400,
|
|
@@ -764,13 +764,13 @@
|
|
|
764
764
|
{
|
|
765
765
|
"name": "bulk_create_monitors",
|
|
766
766
|
"title": "Create several monitors",
|
|
767
|
-
"description": "Create 1 to 100 monitors in one call, all or nothing; for a single monitor use create_monitor. Requires a key with the write scope. An invalid item, or a batch that would exceed the plan, rejects the whole call and creates nothing: call get_plan_usage first to check the batch fits. Errors name the failing item. A field that fails validation is named by its path, such as monitors.3.target (index 3 is the fourth item; all such errors are reported at once). Any other item error keeps the status create_monitor would give (403 when its interval or regions break the plan or name an unknown region, 404 for an unknown channel id, 422 for its config or its type's region rules) and its reason starts with monitors[3] (\"<item name>\"): — only the first such item is reported. Read the index only from that leading monitors[N] (the pattern ^monitors\\[(\\d+)\\] after any lead-in such as \"Forbidden: \" or \"Invalid request: \"), never from the name, which may itself contain quotes or brackets. A plan-limit 403 without that prefix is about the batch as a whole: together the items would exceed the plan's monitor count or its quota of monitors below 60 seconds. Fix the item or shrink the batch and send the whole call again. Returns monitors: one list_monitors row per created monitor, in request order. Example: {\"monitors\": [{\"name\": \"db.example.com exposed ports\", \"type\": \"TCP\", \"target\": \"db.example.com\", \"interval_seconds\": 3600, \"timeout_seconds\": 10, \"regions\": [\"eu-central\"], \"config\": {\"ports\": [5432, 6379, 27017], \"expected_state\": \"closed\"}}]}",
|
|
767
|
+
"description": "Create 1 to 100 monitors in one call, all or nothing; for a single monitor use create_monitor. Requires a key with the write scope. An invalid item, or a batch that would exceed the plan, rejects the whole call and creates nothing: call get_plan_usage first to check the batch fits. Errors name the failing item. A field that fails validation is named by its path, such as monitors.3.target (index 3 is the fourth item; all such errors are reported at once). Any other item error keeps the status create_monitor would give (403 when its interval or regions break the plan or name an unknown region, 404 for an unknown channel id, 422 for its config or its type's region rules) and its reason starts with monitors[3] (\"<item name>\"): — only the first such item is reported. Read the index only from that leading monitors[N] (the pattern ^monitors\\[(\\d+)\\] after any lead-in such as \"Forbidden: \" or \"Invalid request: \"), never from the name, which may itself contain quotes or brackets. A plan-limit 403 without that prefix is about the batch as a whole: together the items would exceed the plan's monitor count or its quota of monitors below 60 seconds. Fix the item or shrink the batch and send the whole call again. Returns monitors: one list_monitors row per created monitor, in request order. The example is a port-list TCP monitor, which takes exactly one region and an interval of at least 300 seconds. Example: {\"monitors\": [{\"name\": \"db.example.com exposed ports\", \"type\": \"TCP\", \"target\": \"db.example.com\", \"interval_seconds\": 3600, \"timeout_seconds\": 10, \"regions\": [\"eu-central\"], \"config\": {\"ports\": [5432, 6379, 27017], \"expected_state\": \"closed\"}}]}",
|
|
768
768
|
"scope": "write",
|
|
769
769
|
"input_schema": {
|
|
770
770
|
"type": "object",
|
|
771
771
|
"properties": {
|
|
772
772
|
"monitors": {
|
|
773
|
-
"description": "1 to 100 monitors, each taking the same fields and rules as create_monitor's arguments. Items with is_active false are created paused and still count toward the plan.",
|
|
773
|
+
"description": "1 to 100 monitors, each taking the same fields and rules as create_monitor's arguments. Items with is_active false are created paused and still count toward the plan. Unless the user names regions, give each item every code in limits.allowed_regions, up to the plan's max_regions; tell the user the intervals you chose.",
|
|
774
774
|
"items": {
|
|
775
775
|
"additionalProperties": false,
|
|
776
776
|
"properties": {
|
|
@@ -1434,7 +1434,7 @@
|
|
|
1434
1434
|
},
|
|
1435
1435
|
"minItems": 1,
|
|
1436
1436
|
"type": "array",
|
|
1437
|
-
"description": "One or more distinct region codes
|
|
1437
|
+
"description": "One or more distinct region codes: the plan's choices are limits.allowed_regions in get_plan_usage. An unknown code, or more regions than max_regions, is a 403. SSL, DNS and TCP monitors with a ports list take exactly one region (422 otherwise)."
|
|
1438
1438
|
},
|
|
1439
1439
|
"config": {
|
|
1440
1440
|
"additionalProperties": true,
|
|
@@ -1445,7 +1445,7 @@
|
|
|
1445
1445
|
"maximum": 10,
|
|
1446
1446
|
"minimum": 1,
|
|
1447
1447
|
"type": "integer",
|
|
1448
|
-
"description": "How many checks in a row must fail in every region before the monitor goes DOWN and an incident opens, 1 to 10;
|
|
1448
|
+
"description": "How many checks in a row must fail in every region before the monitor goes DOWN and an incident opens, 1 to 10; 2 when not set on create."
|
|
1449
1449
|
},
|
|
1450
1450
|
"notification_cooldown_seconds": {
|
|
1451
1451
|
"maximum": 86400,
|
|
@@ -5652,7 +5652,7 @@
|
|
|
5652
5652
|
{
|
|
5653
5653
|
"name": "get_uptime_daily",
|
|
5654
5654
|
"title": "Get a monitor's daily uptime",
|
|
5655
|
-
"description": "Report one monitor's uptime for each UTC day, oldest first and ending today, to find the day an outage or degradation began. Each day has date, uptime_percentage, downtime_seconds, observed_seconds, total_checks, up_checks, down_checks, degraded_checks and maintenance_checks. uptime_percentage is the share of the day's observed time outside confirmed outages (an outage counts from the first failing probe to the first probe that is not DOWN; a failure only one region saw does not count; maintenance counts as up; hours with no checks are left out); a day with no checks and no outage has a null uptime_percentage, not 100. The check counts are informational: a failed check outside a confirmed outage does not lower uptime_percentage. For 24h, 7d and 30d totals use get_uptime_summary. Returns monitor_id and days.",
|
|
5655
|
+
"description": "Report one monitor's uptime for each UTC day, oldest first and ending today, to find the day an outage or degradation began. Each day has date, uptime_percentage, downtime_seconds, observed_seconds, degraded_seconds, total_checks, up_checks, down_checks, degraded_checks and maintenance_checks. degraded_seconds is the day's time in confirmed DEGRADED status (an ongoing degradation counts up to now; 0 for days before this monitor's status history began, when the status ledger shipped); it does not lower uptime_percentage. A day with degraded_seconds above 0 and no confirmed outage is a degraded (yellow) day in the dashboard; degraded_checks alone does not make one. uptime_percentage is the share of the day's observed time outside confirmed outages (an outage counts from the first failing probe to the first probe that is not DOWN; a failure only one region saw does not count; maintenance counts as up; hours with no checks are left out); a day with no checks and no outage has a null uptime_percentage, not 100. The check counts are informational: a failed check outside a confirmed outage does not lower uptime_percentage. For 24h, 7d and 30d totals use get_uptime_summary. Returns monitor_id and days.",
|
|
5656
5656
|
"scope": "read",
|
|
5657
5657
|
"input_schema": {
|
|
5658
5658
|
"type": "object",
|
|
@@ -5736,6 +5736,10 @@
|
|
|
5736
5736
|
"observed_seconds": {
|
|
5737
5737
|
"description": "Seconds of the day the monitor was observed; uptime is measured over this time. Never less than downtime_seconds; 0 means no data.",
|
|
5738
5738
|
"type": "integer"
|
|
5739
|
+
},
|
|
5740
|
+
"degraded_seconds": {
|
|
5741
|
+
"description": "Seconds of this UTC day the monitor spent in confirmed DEGRADED status (from the monitor's status history; an ongoing degradation counts up to now). Maintenance is not subtracted. Zero for days before this monitor's status history began (when the status ledger shipped).",
|
|
5742
|
+
"type": "integer"
|
|
5739
5743
|
}
|
|
5740
5744
|
},
|
|
5741
5745
|
"required": [
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fettle-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"mcpName": "sh.fettle/mcp",
|
|
5
|
-
"description": "Fettle uptime monitoring (https://fettle.sh) for any MCP client — manage monitors, incidents, heartbeats, maintenance windows and status
|
|
5
|
+
"description": "Fettle uptime monitoring (https://fettle.sh) for any MCP client — manage monitors, incidents, heartbeats, maintenance windows and status page incidents from Claude, Cursor or Codex.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
8
8
|
"mcp-server",
|