Most questions an engineer asks about AI infrastructure are lookups that take several screens to answer: what did we spend on each provider this week, why did the 3 a.m. batch fail, which budget is about to block requests. An assistant with the right tools can answer them in one sentence. The same assistant with write tools can also change a route that carries production traffic, which is a different kind of power.
This guide covers how to give an assistant access to infrastructure without giving it more than a careful operator would have: read and write tools, scoped credentials, confirmation, and audit. The last part shows how the INFRO MCP server applies each of them, with commands you can run today.
Why operate infrastructure through an assistant
The Model Context Protocol gives assistants a standard way to discover and call tools on a server, over JSON-RPC1. For infrastructure that means the assistant does not scrape a console or guess at an API: the server publishes typed tools with schemas, and the assistant calls them.
The benefit is mostly in reading. Usage grouped by model, the attempts behind one failed request, every step of an agent run, the audit trail of who changed a route: these are answers an assistant can assemble across several API calls while the person stays in their editor. Writes are useful too, but only the routine ones, and only when the person sees what will change before it does.
Read tools and write tools
Separate tools that read from tools that change state, and expose the read set by default. MCP lets a server describe a tool with annotations such as a read-only or destructive hint, which clients use to decide when to ask the person first. The specification is explicit that clients must treat those annotations as untrusted unless they come from a trusted server2. Annotations are the server's claim about itself; the real boundary is the credential the server accepts and what it checks on each call.
The specification also says there should always be a human able to deny a tool invocation, and that clients should prompt for confirmation on sensitive operations and show tool inputs before calling2. Assistants implement that differently, and many let a person approve a tool once for the whole session. A server that changes infrastructure should therefore not rely on the client's prompt alone; it should make an unconfirmed or stale write fail by itself.
Three patterns do that:
- Optimistic concurrency. Every write takes the version of the item the assistant last read. If someone changed it since, the write is refused, never retried silently, and the assistant has to read it again and show the new state.
- Exact confirmation for irreversible actions. Revoking a key takes the key's exact label as well as its id, so a model that picked the wrong row from a list fails instead of revoking it.
- Prepare, do not create, when a secret is involved. A tool that would return a new credential to the assistant puts the secret into the model's context and from there into its provider's logs. The safer shape validates the settings and returns a link where the person finishes the action and sees the secret once.
Token scopes and the identity behind them
OWASP's MCP Top 10 lists token mismanagement and secret exposure first and privilege escalation through scope creep second3. For an assistant connected to infrastructure, the rules follow from that.
- Act as a person. The credential should carry a named person's authority, checked against their role at the moment of each call, so removing someone from the organization stops their assistant too.
- Narrow by family. Scopes should be grouped by what they touch (projects, keys, routes, budgets) and by data that deserves its own grant (request history, findings, the audit log). A token made to read configuration should not also read request data.
- No wildcard write. The MCP security guidance warns against omnibus scopes and recommends a minimal initial set with step-up for privileged operations4. With static tokens, the equivalent is granting write one family at a time.
- Expire. A token without an expiry outlives the task it was made for.
- Keep it out of the repository. Claude Code, for example, can store a server in a project-scoped
.mcp.jsonshared through version control5; reference an environment variable there, never the token itself.
For remote servers that support it, the MCP authorization specification uses OAuth 2.1: the assistant discovers the authorization server, the person signs in, and the server accepts only tokens issued for itself, answering 403 with an insufficient_scope challenge when a call needs more6. Sign-in removes the copied secret entirely. Where it is not available, a scoped, expiring management token is the practical alternative.
Audit, and content the assistant should not see
Every change made through an assistant should be audited as such, naming the person and the client, next to changes made in the console or by Terraform. The specification asks clients to log tool usage for audit2, but the server is the one place every client passes through, so it should keep its own record of each call: tool, outcome, duration, and no arguments or results it does not need.
Two kinds of content deserve care. Request content (prompts and completions) has no place in an operations tool: the assistant needs metadata, costs and errors to answer operational questions. And values that originate outside your team, such as tags, end-user ids or provider error messages, reach the model as text and may carry instructions. Marking them as data helps the model; it is not a security boundary, which is why writes still need confirmation.
A checklist before connecting an assistant
- The server exposes read and write tools separately, and the assistant can be limited to read.
- The credential acts as a person, with their current role, scoped by family, with an expiry.
- Request data, findings and audit history are granted by name, not by a wildcard.
- Writes require the last-read version; irreversible writes require an exact confirmation.
- No tool accepts or returns a credential or a secret.
- Every change is audited with the client named, and admins can turn assistant access off.
- Configuration managed by Terraform or a CLI is changed there, or the person is told the next apply will revert it.
The INFRO MCP server: URL, sign-in and tokens
The INFRO MCP server lives at https://mcp.infro.io/mcp (Streamable HTTP, stateless; MCP revision 2026-07-28 and the earlier initialize revisions). Each tool is a documented management API operation, so scopes, plan, role and audit rules are the management API's own. It never calls a model and never routes a request; your assistant's own model calls are made and billed by your assistant and its provider. MCP tool calls do not count against the plan's request allowance. It is a different product from INFRO's MCP gateway, which proxies your agents' calls to your own tool servers; the two share the host mcp.infro.io.
How you connect. Most assistants sign in (OAuth 2.1 with PKCE): Claude on the web, desktop and mobile, ChatGPT, Claude Code, Codex, Cursor and VS Code. You add the URL in the assistant, it opens INFRO in your browser, and you choose the organization and what it may do; no secret is copied. Clients whose sign-in INFRO has not checked, Windsurf today, and CI or scripts use a management token.
In the console, open MCP & connectors → AI assistants and choose your assistant: a signing-in assistant takes two steps, and the page says when it has connected. For a token client, create its token in step one. Owners and admins can create one from the Startup plan. Choose Read (every setting, usage and estimated provider cost, request metadata, findings and the audit log) or Read and change (from the Team plan), optionally one project, and an expiry: 90 days by default, at most 365, never unlimited. The token is shown once; INFRO stores only a hash, and every owner is emailed when one is created.
claude mcp add --transport http infro https://mcp.infro.io/mcp \
--header "Authorization: Bearer $INFRO_MCP_TOKEN"{
"mcpServers": {
"infro": {
"url": "https://mcp.infro.io/mcp",
"headers": { "Authorization": "Bearer ${env:INFRO_MCP_TOKEN}" }
}
}
}[mcp_servers.infro]
url = "https://mcp.infro.io/mcp"
bearer_token_env_var = "INFRO_MCP_TOKEN"The MCP docs have the VS Code and Windsurf configurations; any client that speaks Streamable HTTP works with the URL and the header.
ceiling
The creator's role, nowA management token runs as the owner or admin who created it, with their current role. If they stop being an owner or admin, the token is refused.narrows
The token's scopesFamilies such as projects, keys, routes, budgets; data families analytics, findings and audit only by name. No *:write.narrows
The planReads and project/key writes from Startup; every other write from Team.optional
Project restrictionA token tied to one project sees that project's keys, usage and findings, and nothing else.per client
Toolsets and read-only mode?toolsets=observe,configure or ?read_only=1 hide tools; they never add one.
Token families. Configuration families are projects, keys, connections, routes, settings, budgets, webhooks, prices, notifications, cost_centers, commitments, guardrails and end_users, each as <family>:read or <family>:write. Data families are analytics (usage, request metadata and traces), findings and audit. *:read reads every configuration family and no data family, so a token made for Terraform never gains request history; there is no *:write. A token can be restricted to one project, and then holds only project-level families.
The tools, and what each kind of change requires
The server publishes 18 tools in three toolsets. A token sees only the tools its scopes, plan and project restriction allow.
read-only
observe
- get_overview
- query_usage
- search_requests
- get_request
- get_trace
- list_findings
- get_budget_status
- search_audit_log
read-only
configure
- list_models
- list_configuration
- get_configuration
- prepare_gateway_key (returns a console link; creates nothing)
changes configuration
manage
- create_project
- set_spend_limit
- update_route
- acknowledge_finding
- set_gateway_key_enabled
- revoke_gateway_key
You can narrow further per client: https://mcp.infro.io/mcp?toolsets=observe,configure or the header X-INFRO-MCP-Toolsets, and ?read_only=1 or X-INFRO-MCP-Read-Only: true. These only remove tools; they never add one the token cannot use.
The write tools follow the patterns above. Every manage tool needs expected_version, which get_configuration returns; a stale version answers version_conflict. revoke_gateway_key also needs confirm_label equal to the key's current label, and its description tells the assistant to use set_gateway_key_enabled to pause a key instead. prepare_gateway_key never creates a key: it validates the settings and returns a console link where the person clicks Create and sees the secret once. Write tools carry accurate annotations so assistants ask before calling them, and get_configuration returns managed_by, so the assistant can warn you when Terraform or the CLI would revert a change.
Person
Assistant
INFRO MCP server
- Person to Assistant: Set a $20 monthly limit on Search that blocks
- Assistant to INFRO MCP server: get_configuration (projects, Search)
- INFRO MCP server to Assistant: item, version, managed_by
- Assistant to Person: proposed change; asks to confirm (destructive hint)
- Person to Assistant: confirm
- Assistant to INFRO MCP server: set_spend_limit with expected_version
- INFRO MCP server to INFRO MCP server: scope, plan, role, version check; audit row
- INFRO MCP server to Assistant: result, or version_conflict if it changed
No tool takes or returns a provider credential, a gateway key secret, a webhook secret or a Slack URL; an argument shaped like a credential is refused. Prompts and completions are never returned, whatever your capture setting. Money in every result is estimated provider cost in USD, what your own provider will bill you, never an INFRO charge, and an unpriced amount is null. Results that carry values from your applications or providers start with a line telling the assistant to treat them as data, each value cut to 300 characters; INFRO's docs say plainly that this is a signal to the model, not a security boundary.
Every change writes an audit row naming the client "AI assistant (MCP)", next to the console's own entry, and search_audit_log reads them back. Each tool call is logged with its tool, outcome and duration, never its arguments or result, for 90 days. AI assistant access is on by default; owners and admins can turn it off for the organization under Settings → Gateway → AI assistants, after which every MCP request is refused with 403 mcp_disabled while the management API keeps working. Each token or assistant gets 120 tool calls a minute (429 too_many_attempts with Retry-After), and results are capped at about 20,000 characters, with a next_cursor to continue.
Prompts to try
What will the assistant be asked to do?
- Answer questions about spend, failures, tracesRead token with analytics, findings, budgets; observe toolset
- Explain or audit configuration*:read plus audit:read; configure toolset
- Make routine changes a person confirmsRead and change, one write family at a time, short expiry
- Work inside one team's projectA project-restricted token
- Configuration owned by Terraform or the CLIKeep writes there; read-only mode for the assistant
With a read token connected, these map to one or two tools each:
| Ask | Tools the assistant uses |
|---|---|
| How is our INFRO organization doing this month? | get_overview: plan, period, estimated provider cost so far, requests against the allowance, open findings, limits near their cap, failing connections |
| Which model cost us the most in the last 7 days? | query_usage grouped by model |
| Why did our most recent failed request fail? | search_requests for the newest failure, then get_request for each provider attempt |
| Show me the run checkout-123 step by step. | get_trace: model, status, latency and estimated cost per step |
| Who changed the default route this week? | search_audit_log filtered by route |
| Set a $20 monthly spend limit on the Search project that blocks when reached. | get_configuration for the version, then set_spend_limit after you confirm; needs a write token |
Start with a read token, the observe toolset and a 30-day expiry. Add a write family only when there is a routine change you want to make from your editor, and keep the rest in Terraform, the CLI or the console, where the management API applies the same rules.
