Infra is a production‑grade stdio MCP server for AI‑agent operations. It provides a single, deterministic interface to SSH, HTTP, Postgres, git/repo ops, pipelines, runbooks, intents, evidence, audit, and state.
Most MCP tool servers give agents raw shell access and hope for the best. Infra takes the opposite approach: every action goes through a unified interface with built-in audit, evidence, and explicit opt-ins for risky ops.
- One server, full stack — SSH, HTTP, Postgres, git, runbooks, state. No juggling 5 different MCP servers.
- Audit by default — Every call is logged with evidence/artifacts. You can always answer "what did the agent do?"
- Safe-by-default execution — Local exec and secret export are disabled unless you explicitly opt in. Agents can't escape the sandbox by accident.
Core engineering idea: deterministic, auditable infrastructure actions with the minimal surface area an agent actually needs.
Infra is locked down out of the box. Risky capabilities require explicit environment variables:
| Capability | Env var | Default |
|---|---|---|
| Local shell/filesystem access | INFRA_UNSAFE_LOCAL=1 |
disabled |
| Secret export (env vars, tokens) | INFRA_ALLOW_SECRET_EXPORT=1 |
disabled |
Without these flags, agents cannot execute arbitrary local commands or leak secrets — even if they try.
You: "What runbooks do we have for deploys?"
Agent → help { query: "deploy runbook" }
← Found: deploy.k8s, deploy.staging, deploy.rollback ...
You: "Run staging deploy for service 'api'"
Agent → runbook { action: "run", name: "deploy.staging", input: { service: "api" } }
← ✓ Artifacts: artifact://runs/deploy.staging/2026-01-29T10:30:00Z
Evidence: commit abc123 deployed to staging-api-7f8d9, health-check passed.
Every run creates an artifact with full audit trail — what ran, what changed, what the output was.
- Install
- Download a prebuilt binary from GitHub Releases.
- Or build from source:
cargo build --release
# binary: target/release/infra- Configure your MCP client (example shape; adjust for your client)
{
"mcpServers": {
"infra": {
"command": "/path/to/infra",
"args": [],
"env": {
"MCP_PROFILES_DIR": "/path/to/your/project/.infra"
}
}
}
}- Sanity check
{ "tool": "help", "args": { "query": "runbook" } }No external services needed — just run a built-in runbook to see Infra in action:
// 1. List available runbooks
{ "tool": "runbook", "args": { "action": "list", "query": "repo", "limit": 5 } }
// 2. Run repo.snapshot on the current directory (read-only, no side effects)
{ "tool": "runbook", "args": { "action": "run", "name": "repo.snapshot", "input": { "repo_path": "." } } }Output includes: repo root, current branch, recent commits, diffstat — and an artifact:// reference you can browse later.
When downloading from Releases, verify the binary:
# Download binary and checksum
curl -LO https://github.com/AmirTlinov/infra/releases/latest/download/infra-linux-x86_64
curl -LO https://github.com/AmirTlinov/infra/releases/latest/download/infra-linux-x86_64.sha256
# Verify
sha256sum -c infra-linux-x86_64.sha256
chmod +x infra-linux-x86_64
./infra-linux-x86_64Note: Prebuilt binaries are available starting with future releases. For now, build from source with
cargo build --release.
Create a minimal .infra/ directory for your project:
mkdir -p .infra.infra/runbooks.json (minimal):
{
"hello.world": {
"description": "A simple test runbook.",
"tags": ["test"],
"inputs": ["message"],
"steps": [
{
"id": "echo",
"tool": "mcp_state",
"args": { "action": "set", "key": "hello", "value": "{{ input.message }}" }
}
]
}
}.infra/capabilities.json (minimal):
{
"version": 1,
"capabilities": {}
}.infra/targets.json (example SSH target):
{
"prod": {
"host": "prod.example.com",
"port": 22,
"username": "deploy",
"key_file": "~/.ssh/id_ed25519"
}
}Then point Infra to your project:
export MCP_PROFILES_DIR=/path/to/your/project/.infraEvery tool call can produce artifacts. Here's how to browse them:
// List recent artifacts
{ "tool": "mcp_artifacts", "args": { "action": "list", "limit": 10 } }
// Read a specific artifact
{ "tool": "mcp_artifacts", "args": { "action": "get", "uri": "artifact://runs/repo.snapshot/2026-01-29T10:00:00Z", "max_bytes": 4096 } }
// Get just the tail (last N bytes)
{ "tool": "mcp_artifacts", "args": { "action": "tail", "uri": "artifact://...", "max_bytes": 1024 } }Artifacts contain: full command output, timing, exit codes, and any structured data returned by the tool.
Common config locations:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json - Windows:
%APPDATA%\\Claude\\claude_desktop_config.json
{
"mcpServers": {
"infra": {
"command": "/path/to/infra",
"args": [],
"env": {
"MCP_PROFILES_DIR": "/path/to/your/project/.infra"
}
}
}
}Create .vscode/mcp.json in your workspace:
{
"servers": {
"infra": {
"type": "stdio",
"command": "/path/to/infra",
"args": [],
"env": {
"MCP_PROFILES_DIR": "/path/to/your/project/.infra"
}
}
}
}Add to your Zed settings.json:
{
"context_servers": {
"infra": {
"command": "/path/to/infra",
"args": [],
"env": {
"MCP_PROFILES_DIR": "/path/to/your/project/.infra"
}
}
}
}- Deterministic, auditable infrastructure actions (audit + evidence + artifacts).
- Repeatable workflows via runbooks and intents.
- Safe‑by‑default execution with explicit opt‑ins for risky operations.
- Project‑isolated state so agents don't leak configs across repos.
| Category | What you can do | Example |
|---|---|---|
| SSH | Execute commands, health checks, system info | ssh { action: "exec", target: "prod", command: "uptime" } |
| Postgres | Query, export tables to CSV | psql { action: "query", sql: "SELECT now()" } |
| HTTP | API requests, health checks | http { action: "request", url: "https://api/health" } |
| K8s | Render, diff, apply, rollout inspect | runbook { name: "k8s.diff", input: { overlay: "./dev" } } |
| GitOps | Full release cycle (ArgoCD/Flux) | See GitOps Autopilot below |
| Runbooks | Composable multi-step workflows | Chain SSH → DB → HTTP in one call |
| Artifacts | Store and retrieve run outputs | artifact://runs/deploy/2026-01-29T10:30:00Z |
| Jobs | Async execution, status, logs, cancel | Long-running tasks don't block |
| Context | Auto-detect repo type, k8s, flux/argocd | Agent knows what tools apply |
| Preflight | Self-diagnostics before running | "Can I connect to this cluster?" |
┌─────────┐ stdio/JSON-RPC ┌──────────────────────────────────────┐
│ Agent │ ◀──────────────────────▶ │ Infra │
└─────────┘ │ │
│ ┌──────┐ ┌────────┐ ┌──────┐ │
│ │ SSH │ │Postgres│ │ HTTP │ ... │
│ └──┬───┘ └───┬────┘ └──┬───┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Audit · Evidence · Artifacts │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────┘
Full release cycle in one runbook — no manual steps:
plan → propose (branch + PR) → wait for CI → merge → sync → verify health → auto-rollback on failure
Built-in capabilities: gitops.plan, gitops.propose, gitops.sync, gitops.verify, gitops.rollback, gitops.release.
Set a per‑repo profiles directory:
MCP_PROFILES_DIR=/path/to/your/project/.infra
Optional explicit paths:
MCP_RUNBOOKS_PATH=/path/to/your/project/.infra/runbooks.jsonMCP_CAPABILITIES_PATH=/path/to/your/project/.infra/capabilities.jsonMCP_CONTEXT_REPO_ROOT=/path/to/your/project/.infra/artifacts
Infra exposes a rich tool catalog. Use these to discover exact schemas and actions:
{ "tool": "help", "args": { "query": "ssh exec" } }Machine‑readable catalog:
tool_catalog.json
Stdin options (for ssh, env, repo, mcp_local):
stdin: plain textstdin_base64: binary inputstdin_file: stream from local filestdin_ref: stream from artifact (artifact://...)stdin_eof: control EOF behavior (default: true)
List runbooks:
{ "tool": "runbook", "args": { "action": "list", "query": "k8s", "limit": 20 } }Run a runbook:
{ "tool": "runbook", "args": { "action": "run", "name": "k8s.diff", "input": { "overlay": "./overlays/dev" } } }Run a remote command:
{ "tool": "ssh", "args": { "action": "exec", "target": "prod", "command": "uptime" } }Make an HTTP request:
{ "tool": "http", "args": { "action": "request", "method": "GET", "url": "https://example.com/health" } }Query Postgres:
{ "tool": "psql", "args": { "action": "query", "sql": "select now()" } }Note: For exact tool names and schemas, use help or tool_catalog.json.
Define the runbook:
{
"tool": "runbook",
"args": {
"action": "upsert",
"name": "gitops.k8s.diff",
"runbook": {
"description": "Render kustomize overlay and diff against the cluster.",
"tags": ["gitops", "k8s", "read"],
"inputs": ["overlay", "kubeconfig"],
"steps": [
{
"id": "render",
"tool": "mcp_local",
"args": {
"action": "exec",
"command": "kubectl",
"args": ["kustomize", "{{ input.overlay }}"],
"env": { "KUBECONFIG": "{{ input.kubeconfig }}" },
"inline": true
}
},
{
"id": "diff",
"tool": "mcp_local",
"args": {
"action": "exec",
"command": "kubectl",
"args": ["diff", "-f", "-"],
"stdin": "{{ steps.render.stdout }}",
"env": { "KUBECONFIG": "{{ input.kubeconfig }}" },
"inline": true
}
}
]
}
}
}Run it:
{ "tool": "runbook", "args": { "action": "run", "name": "gitops.k8s.diff", "input": { "overlay": "./overlays/dev", "kubeconfig": "~/.kube/config" } } }Define the runbook:
{
"tool": "runbook",
"args": {
"action": "upsert",
"name": "vps.service.restart",
"runbook": {
"description": "Restart a systemd service and check status.",
"tags": ["vps", "ssh", "write"],
"inputs": ["target", "service"],
"steps": [
{
"id": "restart",
"tool": "ssh",
"args": {
"action": "exec",
"target": "{{ input.target }}",
"command": "sudo systemctl restart {{ input.service }}"
}
},
{
"id": "status",
"tool": "ssh",
"args": {
"action": "exec",
"target": "{{ input.target }}",
"command": "systemctl status {{ input.service }} --no-pager"
}
}
]
}
}
}Run it:
{ "tool": "runbook", "args": { "action": "run", "name": "vps.service.restart", "input": { "target": "prod", "service": "nginx" } } }Define the runbook:
{
"tool": "runbook",
"args": {
"action": "upsert",
"name": "db.export.table",
"runbook": {
"description": "Export a table to CSV on the Infra host.",
"tags": ["db", "backup", "read"],
"inputs": ["profile_name", "table", "file_path"],
"steps": [
{
"id": "export",
"tool": "psql",
"args": {
"action": "export",
"profile_name": "{{ input.profile_name }}",
"table": "{{ input.table }}",
"file_path": "{{ input.file_path }}",
"format": "csv",
"csv_header": true
}
}
]
}
}
}Run it:
{ "tool": "runbook", "args": { "action": "run", "name": "db.export.table", "input": { "profile_name": "prod-db", "table": "events", "file_path": "/var/backups/events.csv" } } }- If a tool call times out, increase your client timeout or reduce batch size.
- Use audit/evidence tools to inspect what happened.
- Run
./tools/doctorfor diagnostics when building from source.
mcp_config.md— MCP client configurationdocs/RUNBOOK.md— runbooksdocs/INTEGRATION.md— integration checksSECURITY.md— security policy
Can the agent delete my files or run arbitrary shell commands?
No — unless you explicitly set INFRA_UNSAFE_LOCAL=1. By default, local exec and filesystem access are disabled.
Does Infra phone home or send telemetry?
No. Infra is fully local, stdio-only. No network calls except the ones you configure (SSH, HTTP, Postgres targets).
What if a command hangs or takes too long?
Use timeout_ms on any tool call. For long-running tasks, use the Jobs API — async execution with status, logs, and cancel.
How do I know what the agent actually did?
Every action creates an artifact with full audit trail. Use mcp_artifacts { action: "list" } to browse, or check the artifacts directory.
Does it work with Claude Desktop / VS Code / Zed?
Yes — any MCP-compatible client. See Client configs for examples.
./tools/doctor— diagnostics./tools/gate— fmt + clippy + tests