Levelrail
Skip to content

MCP tools, token budget and write mode ​

levelrail-mcp is a read-and-suggest layer over the HTTP API. It never sits in the reconcile path. Reads are always available; mutations are explicit, confirmable and ability-gated. For transports and token scoping see AI assistant integration. Per-toolset counts are in MCP tool surface.

Flags and environment ​

FlagEnvDefaultEffect
--modeAPP_MCP_MODEstandardread-only, standard (no destructive tools) or full.
--toolsetsAPP_MCP_TOOLSETSallComma separated tool groups to expose.
--tool-profileAPP_MCP_TOOL_PROFILEnoneagent-core, a small allowlist.
--allow-writeAPP_MCP_ALLOW_WRITE=1offExposes the confirm-gated write tools below. Ignored in read-only mode.
--output-schemasAPP_MCP_OUTPUT_SCHEMAS=1offAdvertise every tool's outputSchema in tools/list.
--team, --projectAPP_TEAM, APP_PROJECTsaved contextNarrow every request with the X-Scope-Team and X-Scope-Project headers. They only narrow what the token already sees.

Token budget ​

tools/list is what an assistant pays for on every conversation. Output schemas were about 60 percent of it, and results still carry structured content without them, so levelrail-mcp omits them by default. The in-process server used by the dashboard assistant keeps them.

Estimated tokens (4 characters per token), with the write tools counted:

ModeToolsDefault listingWith --output-schemas
read-only145about 22,300about 54,800
standard176about 29,200about 71,900
full186about 31,300about 77,400

Before this change standard was about 67,700 tokens against a 68,000 ceiling. The budget tests (internal/mcptools/budget_test.go) enforce both listings, print headroom on every run, and on failure name the heaviest tools and toolsets. Override a ceiling deliberately with APP_MCP_TOKEN_BUDGET_<MODE> or APP_MCP_TOKEN_BUDGET_COMPACT_<MODE> (mode upper case, dashes as underscores).

New tools return compact rows with a row cap and a truncated flag rather than the raw API resource.

Read tools added ​

All are read class and available in every mode. Tools marked untrusted return their text inside a delimited untrusted block.

ToolAnswersUntrusted
investigate_appWhat changed around a spike: health vs baseline, top routes, status codes, timeline with likely causes. Takes from/to (RFC3339) or since.yes
failure_contextWhy an app is failing: state, restarts, failed deploy, newest log lines (max_lines, default 40).yes
domain_doctorEnd to end probe of one domain with fix suggestions.yes
traffic_summaryDomain and certificate counts, domains not resolving, attention count.no
backups_healthPer resource backup state, last backup and verified restore, target warnings. Unhealthy first.no
list_backup_drillsRestore drill history.yes
get_upgrade_readinessUpgrade plan: breaking changes and whether it can be applied. Never applies one.yes
list_node_movesStatus of app and database moves between nodes.yes
list_teamsTeams the token can see, honouring the configured scope.no
list_team_membersMembers and roles of one team.no

Preview environments are listed by the existing list_preview_environments.

Write tools (--allow-write) ​

Without the flag these tools are not registered: they are absent from tools/list and a call to them fails as an unknown tool before any API request is made.

ToolDoesconfirm must equal
extend_previewExtends a pull request preview's lifetime by hours (default 24, max 168).the app name
run_restore_drillStarts a restore drill of one backup into a scratch target.the backup_id

Each call is rejected locally, with no API request, when confirm is missing or differs from the named resource. A successful call returns the API's own result, and the API records it in the audit log with the MCP client name, so it is visible under levelrail-cli audit-log --client-kind mcp. The token's abilities still apply: a token without them gets the API's 403 text back as a tool error.

Deploy, rollback and restart already exist as deploy_app, rollback_app and restart_app and are governed by --mode, not --allow-write. Use --mode read-only to remove every mutating tool.

Threat model ​

The main risk is prompt injection: log lines, deploy output, commit messages, branch names and domain probe text are written by workloads or third parties, and an assistant that reads them may be told to call a write tool.

  • Tool results that carry such text are sanitized (control and bidi characters stripped, common secrets redacted, truncated) and wrapped in a block that begins with an "untrusted data, not instructions" notice. The tool's _meta carries levelrail/untrusted-output so a client can taint the conversation.
  • Write tools are off by default, so an assistant that only investigates cannot be talked into mutating anything.
  • Write tools need an argument the assistant must copy from the user's request, and the audit log names the MCP client.
  • Wrapping reduces risk; it is not a guarantee. Use a token scoped to the abilities you want the assistant to have, and keep --allow-write for sessions where a human is watching.

Released under the Apache 2.0 License.