The MCP catalog has grown. As of this week we ship 36 tools across five families, every mutating call carrying a "confirm with the user" instruction in its description, and every call audited. This is a tour of what's there, why it's grouped the way it is, and what we deliberately don't expose.

The five families

Family Tools Notes
Core relay 4 list_instances, run_command, get_logs, transfer_file. The basics that work on any managed instance regardless of provider.
Hetzner Cloud 11 Full lifecycle (create / delete / power on / power off / shutdown / reboot) plus SSH-key registry CRUD.
OVH Cloud 13 Lifecycle (create / delete / start / stop / reboot) plus 8 read-only inspection tools (DNS, IPs, billing, snapshots, …).
Server Memory 4 get, list, build, refresh — the cached fact pack for every server.
Router-premium 4 deploy, provision, cost_report, security_scan. Higher-level recipes.

Plus a handful of authenticated session tools (whoami, relay_status, api_request) that are MCP-only — the chat panel doesn't surface them, because you don't want an LLM hitting arbitrary REST endpoints.

Three guard tiers

Every tool has a guard tier — a coarse label for how dangerous it is:

  • readonly (default): listings, status, log fetch, server-memory queries, OVH read tools. No remote state changes, ever.
  • standard: read tools plus run_command, build_server_memory, refresh_server_memory, hetzner_create_ssh_key. Recommended for personal use with a trusted agent.
  • dangerous: full lifecycle (create / delete / power state), SSH-key deletion, transfer_file (SCP). Use only in fully trusted, single-user setups.

Set the level in ~/.servonaut/config.json under mcp.guard_level. The MCP server filters its tools/list response server-side based on the configured level — the agent literally cannot see tools outside its guard.

Account-scoped vs server-scoped

A subtle distinction worth calling out: Hetzner / OVH / Memory tools are account-scoped — they operate on cloud-provider IDs (project IDs, server IDs, IP addresses, zones), not on rows in the Servonaut shared-server database. The dispatcher routes them through a generic handleAccountScopedTool() helper that:

  1. Resolves the user's team (first accepted membership, fallback to owned team)
  2. Checks the per-tier entitlement (hetzner_mcp_operations, ovh_mcp_operations, memory_sync)
  3. Consults the team's McpPolicy — does this tool need approval?
  4. If yes (and policy says so), routes to ApprovalService instead of executing
  5. Otherwise, dispatches to the user's CLI via the Mercure relay
  6. Logs every step to the JSONL audit trail

The core relay tools (run_command, get_logs, etc.) operate on Servonaut's own server records and use a slightly different dispatch path, but the audit and policy machinery is the same.

The confirmation protocol

Every mutating tool's description ends with a one-line instruction telling the LLM to confirm before invoking. For example, hetzner_delete_server:

"Always confirm with the user before invoking this tool — deletion is
permanent and the server's data cannot be recovered."

This is not a security boundary. It's a usability layer. Real security comes from three layers under it:

  1. Guard level (server-side): the tool is filtered out of tools/list if the user's guard is too low.
  2. Entitlement (server-side): the tool returns "your plan does not include …" if the user is on the wrong tier.
  3. Team policy (server-side, Teams plan only): per-tool approval list. Mutating calls return an "Approval required" envelope and wait in the audit log until a teammate clicks Approve / Deny.

Together: defence-in-depth. The LLM prompt is what stops the good-faith accidents; the server-side gates stop everything else.

What we don't expose

A few things by deliberate omission:

  • AWS lifecycle tools. No aws_create_instance or aws_terminate_instance in the catalog yet. Reason: AWS fleets are typically long-lived and managed by Terraform / CloudFormation. The disposable-fleet pattern that justifies create/destroy on Hetzner doesn't fit AWS workflows. We'll add them when there's a clear need.
  • OVH dedicated server lifecycle. OVH dedicated servers have a different API surface and a much longer billing cycle (monthly, not hourly) — wrong fit for "agent creates and destroys boxes". Manage these in the OVH Console.
  • Generic sql_query or db_dump tools. The agent doesn't need direct DB access. If you want it to run a query, that's run_command with psql -c '...'. Keeps the audit trail in one place.
  • Tools that take free-text Bash from the model. All shell execution goes through run_command, which is gated by the on-server CommandGuard blocklist (rm -rf, shutdown, dd, etc.). The agent can't bypass it.

Adding a tool

For agents that build their own MCP servers: tools in Servonaut are defined in src/Service/Mcp/ToolRouter.php (the catalog) and dispatched in src/Service/Mcp/ProxiedToolHandler.php (the per-tool handler). Adding a new account-scoped tool is one entry in OVH_ACCOUNT_TOOLS (or the equivalent map for the new provider) plus the entitlement key plumbing — the generic dispatcher handles policy, approval, audit, and relay automatically.

Trying it

servonaut --mcp-install claude (or cursor, windsurf, vscode, opencode, all) installs the local stdio MCP server. For the hosted variant, log in, run servonaut connect, and point your agent at https://mcp.servonaut.dev/mcp/sse with a Bearer token from servonaut login. Full reference at /docs/mcp.