Scope-bounded
A tool can’t exceed the key’s scopes — an out-of-scope
call fails with a 403. Hand an agent a read-only key and it physically
cannot purge a cache or switch a PHP version, let alone anything worse.
The official Model Context Protocol server puts the
managed.dev API in front of an AI agent as a set
of typed tools. It ships inside the mf CLI as mf mcp — a stdio
JSON-RPC 2.0 server (protocol version 2025-06-18) built on the
Go SDK, so it inherits the same
scopes and jobs — an agent
gets exactly the surface your key grants it and nothing more.
Install the CLI and provide a key (see the
mf guide for mf login --mint down-scoping):
go install terriblegit.com/terrible/mf/cmd/mf@latestRegister the server with your agent. For Claude Code:
claude mcp add forge -- mf mcpTo give the agent its own key rather than your stored one, pass it through
the environment: claude mcp add forge --env FORGE_TOKEN=mfk_live_… -- mf mcp.
List the tool set any time (no token needed):
mf mcp --toolsThe design choices that make the API pleasant for humans are the same ones that make it safe for agents — this isn’t a separate “AI mode” bolted on:
Scope-bounded
A tool can’t exceed the key’s scopes — an out-of-scope
call fails with a 403. Hand an agent a read-only key and it physically
cannot purge a cache or switch a PHP version, let alone anything worse.
Idempotent
Job-returning write tools attach an
Idempotency-Key, so an agent that retries
(they do) replays the original job instead of running the action twice.
Job-returning
Mutations return a job the agent can resolve
with wait_job for a real outcome, instead of a fire-and-forget call it
can’t verify.
Typed failures
Tool errors are structured JSON — type, code, message, status,
param, request_id, retry_after_s — and an action a runtime can’t
perform fails with capability.unsupported, so the agent adapts instead
of guessing. (Full capability discovery
is available via mf capabilities and GET /v1/sites/{id}/capabilities.)
Every tool also carries the standard MCP behavior annotations
(readOnlyHint, destructiveHint: false, idempotentHint, openWorldHint),
so a client can apply its own guardrails without parsing descriptions.
The server exposes 36 tools in three tiers, so you can reason about what an agent can actually do:
*:read scopes:
whoami, list_sites, get_site, get_site_health, get_site_insights,
list_insights_pages, get_site_logs, list_environments,
get_environment, list_deployments, list_builds,
get_vulnerabilities, get_malware_overview, get_security_summary,
get_backups_status, get_team_insights, list_teams, get_rate_limits,
list_jobs, get_job, wait_job, list_events,
list_webhook_endpoints, get_webhook_endpoint,
list_webhook_deliveries, list_snapshots, list_audit.create_webhook_endpoint, roll_webhook_secret,
delete_webhook_endpoint, replay_webhook_delivery,
dismiss_malware_detection.Idempotency-Key and
returns a job: trigger_malware_scan,
purge_cache, create_backup, switch_site_php.The policy line is deliberate: the server never exposes credentials, magic
links, SSH keys, API-key management, raw exec, or destructive deletes and
restores — those stay behind the CLI and API, gated by
isolated scopes, for a human to invoke. An agent whose
key lacks a scope gets a 403; the tools inherit the key, they don’t extend it.
A remediation agent that “checks a site’s health, investigates, acts, and verifies” maps cleanly onto the tool tiers:
Read health. Call get_site_health and get_site_logs to find the
problem — say, elevated errors and a malware flag in the summary.
Investigate. Call get_malware_overview and get_vulnerabilities to
see what’s known — detections, and whether an installed plugin matches a
published CVE.
Act, idempotently. Call trigger_malware_scan. The tool returns a
job; the agent resolves it with wait_job. A
retry replays the same job rather than scanning twice.
Verify. Call get_malware_overview again and confirm the state. If a
fix involved a cache (purge_cache) or a PHP switch (switch_site_php),
check get_site_insights for the after-picture — and every step it took is
in the audit log under the key’s identity.
This is the whole point of the design: bounded scopes, idempotent writes, and job-backed verification turn an agent from a liability into a careful operator — with a hard floor under it, because the genuinely dangerous surface was never exposed as a tool at all.