Owner decision 2026-10-09 ("Do it"): rather than only softening the site
claim "manage your ENTIRE self-hosted infrastructure", EXPAND the MCP tool
set to match what the product actually manages. 17 tools -> 28, each a thin
handler over an EXISTING, verified route (every path/method/body checked
against the route source before wiring; no new route logic):
calendar: dashcaddy_calendar_events (days horizon -> ISO start/end
window per routes/calendar.js contract, clamped 1..60; default
14), dashcaddy_calendar_add_source (caldav/ics; user/pass only
sent when provided)
security: dashcaddy_security_events (limit/source_type/severity/since
passthrough — only provided filters reach the query string),
dashcaddy_security_summary (stats + perimeter fan-out; opt-out
via withPerimeter:false)
meta: dashcaddy_license_status, dashcaddy_capabilities (the DC-165
ground-truth manifest — agents can now self-describe the build)
dns writes: dashcaddy_dns_add_record (POST /dns/record body {domain,ip,
ttl?}), dashcaddy_dns_remove_record (DELETE with encoded query,
type default 'A')
orchestrate: dashcaddy_deploy_recipe ({recipeId, overrides->config}),
dashcaddy_run_workflow (encodeURIComponent'd id + /run),
dashcaddy_tailscale_status
Security posture UNCHANGED and preserved by tests: DC-162's machine-
credential gate still guards tools/call over HTTP (session-cookie callers
cannot execute tools), and the caller's credential TYPE is forwarded
downstream (apikey -> x-api-key header) — asserted for the new WRITE tools
by the credential-passthrough test. Premium-gated endpoints (recipes,
workflows) answer their own 403 envelope through the existing apiCall
error shape; nothing bypasses entitlements.
Tests: NEW __tests__/mcp/mcp-core-dc166.test.js — 15 tests (catalog
integrity: 28 unique names + required-field declarations on every write
tool; per-handler captured-fetchImpl assertions on method/URL/body/query
incl. calendar window math, security fan-out order, id encoding; unknown-
tool rejection; x-api-key passthrough). Existing MCP suites unbroken:
88 total (73 prior + 15 new); eslint 0 errors on touched files.