{
  "markdown": "<!-- mcp-name: io.github.AIops-tools/proxy-aiops -->\n\n# Proxy AIops\n\nGoverned, audited AI-ops for **Traefik**, **Caddy** and **HAProxy** reverse proxies / load balancers — for AI agents (via MCP) and humans (via CLI).\n\n> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Traefik Labs, the Caddy project, HAProxy Technologies, or the HAProxy project.** Traefik, Caddy and HAProxy are trademarks of their respective owners. MIT licensed.\n\nproxy-aiops speaks to three proxy platforms behind one MCP server — **Traefik**\n(its API under `/api/...`, metrics-text counters via `/metrics`), **Caddy** (the\nadmin API, default `localhost:2019`) and **HAProxy** (the Data Plane API v2 under\n`/v2/...`, HTTP Basic auth) — with the **same tools working on all three**. Each\ntarget in the config names its own `platform`; a name-keyed platform registry\nselects the API shape (auth + resource paths), and an explicit **support matrix**\nraises teaching errors for ops a platform genuinely cannot do — e.g. Traefik\nwrites point you at its providers (file, container labels, orchestrator CRDs), never\na silent no-op.\n\nEvery tool runs through a **built-in governance harness** (vendored, zero external\ndependency): audit log, token/call budget with runaway circuit-breaker,\ndescriptive risk-tier labelling, undo-token recording, and output sanitisation.\n\n## Why this exists\n\n- **One server, three proxies** — Traefik, Caddy and HAProxy in a mixed edge,\n  spoken to through identical tool names. Adding another proxy later is a new\n  platform descriptor, not a rewrite.\n- **Read the whole edge** — version, entrypoints/listeners, routes (routers /\n  caddy routes / frontends) with parsed hosts+paths, services and server-level\n  upstream health, middlewares, TLS domain inventory, traffic/error counters,\n  and the live config tree (snapshot + search).\n- **Flagship RCA analyses** — transparent heuristics that show their numbers,\n  never a black-box verdict: `backend_health_rca` (down upstreams → cause class\n  L4/L6/L7/DNS/maint + action), `cert_expiry_sweep` (days-to-expiry buckets +\n  per-platform renewal hints), `error_rate_rca` (5xx share vs the fleet\n  baseline, dominant code → 502/503/504/500 cause), and\n  `route_conflict_analysis` (shadowed routes, dead routes, redirect loops).\n- **Governed writes** — caddy config `set` / `delete` / full `load` (the prior\n  subtree/config is fetched first, so the recorded undo replays a real restore)\n  and haproxy runtime server `state` (ready/drain/maint) and `weight` (undo\n  restores the prior value) — all with `dry_run` previews; delete/load are\n  **risk=high** with double confirmation at the CLI.\n\n## What this tool does, and does not, decide\n\nIt delivers proxy operations — reads and writes — accurately and efficiently,\nand records every one of them. It does **not** decide whether a write is allowed\nto happen. That is the agent's judgement, or the permission of the account you\nconnect it with: give the HAProxy Data Plane API a read-only role, or scope down\nthe Traefik/Caddy admin API you point it at, and the writes fail at the server —\nthe place that actually owns the permission.\n\nSo there is no read-only switch, no policy file, no approval gate to configure.\nThe one thing the tool guarantees is that nothing is silent: **every call, over\nMCP and over the CLI alike, lands an audit row** in `~/.proxy-aiops/audit.db`,\nand reversible writes still capture their before-state and record an inverse.\n\n> Each tool declares a `risk_level`, kept in agreement with its `[READ]`/`[WRITE]`\n> documentation tag by a test, and carried into the audit row as a descriptive\n> tier — so a reviewer can see at a glance that a row was a high-risk delete. It\n> is a label, not a gate.\n\nRunning a smaller / local model? See\n[agent-guardrails.md](skills/proxy-aiops/references/agent-guardrails.md) — it lists\nthe guardrails this tool now enforces for you (so you don't spend prompt budget\nrestating them) and gives a ready-made system prompt for what's left.\n\n## Tool inventory (28 tools)\n\n| Domain | Tools | # | Kind |\n|--------|-------|:-:|------|\n| **Status** | `proxy_overview`, `version_info`, `list_entrypoints` | 3 | read |\n| **Routes** | `list_routes`, `route_detail`, `find_route` | 3 | read |\n| **Services** | `list_services`, `service_detail`, `list_upstreams`, `upstream_detail`, `list_middlewares` | 5 | read |\n| **Certificates** | `list_certificates` | 1 | read |\n| **Traffic** | `traffic_stats`, `error_counters` | 2 | read |\n| **Config** | `config_snapshot`, `search_config`, `get_config_value` | 3 | read |\n| **Flagship analyses** | `backend_health_rca`, `cert_expiry_sweep`, `error_rate_rca`, `route_conflict_analysis` | 4 | read |\n| **Writes (caddy)** | `set_config_value` | 1 | write (**med**) |\n| **Writes (caddy)** | `delete_config_path`, `load_config` | 2 | write (**high**) |\n| **Writes (haproxy)** | `set_server_state`, `set_server_weight` | 2 | write (**med**) |\n| **Undo** | `undo_list`, `undo_apply` | 2 | read / write |\n\nReversible writes record an inverse **undo descriptor** built from the real fetched\nbefore-state (`set_config_value` restores the prior subtree; `delete_config_path`\nre-creates it; `load_config` re-loads the snapshotted config; server state/weight\nrestore the prior value). The undo params match each tool's own signature, so the\ndescriptor replays as-is.\n\n### Per-platform support matrix\n\n| Capability | traefik | caddy | haproxy |\n|------------|:-------:|:-----:|:-------:|\n| Routes / services / upstream health | ✅ | ✅ | ✅ |\n| Middlewares list | ✅ | teaching note (inline handlers) | teaching note (haproxy.cfg) |\n| TLS cert inventory + expiry sweep | ✅ | ✅ | teaching note (.pem files) |\n| Error counters / error-rate RCA | ✅ (/metrics) | teaching note (no per-route counters) | ✅ (stats) |\n| Config snapshot / search | ✅ (rawdata, read-only) | ✅ | teaching note |\n| Config writes | teaching error → edit the **provider** | ✅ (the write surface) | teaching error → runtime writes |\n| Runtime server state / weight | teaching error → provider | teaching error → config tree | ✅ |\n\nUnsupported combinations **raise a teaching error that says what to use instead**\n— never a silent empty result.\n\n## Install\n\n```bash\nuv tool install proxy-aiops        # or: pipx install proxy-aiops\n```\n\n## Quick start\n\n### As a Claude Code plugin\n\nOne install gives an agent both the skill and the MCP server:\n\n```\n/plugin marketplace add AIops-tools/marketplace\n/plugin install proxy-aiops@aiops-tools\n```\n\nThe MCP server is fetched with [uv](https://docs.astral.sh/uv/) and pinned to the\npackage version this plugin declares, so an audit row can be traced back to the\ncode that wrote it. Credentials are still configured with `proxy-aiops init` — see below.\n\n### As a CLI or standalone MCP server\n\n```bash\nproxy-aiops init                     # wizard: pick platform (traefik/caddy/haproxy) + optional encrypted secret\nproxy-aiops doctor                   # verify config, secrets, and connectivity\nproxy-aiops overview                 # one-shot: version + route/service counts + upstream health\nproxy-aiops routes list              # normalised route table\nproxy-aiops services upstreams       # server-level upstream health\nproxy-aiops analyze health           # backend/upstream health RCA\nproxy-aiops analyze errors           # 5xx error-rate RCA\nproxy-aiops analyze conflicts        # shadowed/dead routes, redirect loops\nproxy-aiops certs --sweep            # TLS cert expiry sweep (traefik/caddy)\nproxy-aiops server state app web1 drain --dry-run   # governed haproxy write preview\nproxy-aiops config set apps/http/servers/srv0 '{\"listen\":[\":8080\"]}' --dry-run\n```\n\nRun the MCP server (stdio) for an agent:\n\n```bash\nproxy-aiops mcp                      # or: proxy-aiops-mcp\n```\n\n### MCP client config\n\n```json\n{\n  \"mcpServers\": {\n    \"proxy-aiops\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"proxy-aiops\", \"proxy-aiops-mcp\"],\n      \"env\": { \"PROXY_AIOPS_MASTER_PASSWORD\": \"your-master-password\" }\n    }\n  }\n}\n```\n\n> **Env-block caveat**: the `env` block is only needed when a credential is\n> stored (haproxy always; traefik/caddy only behind Basic auth). MCP clients do\n> **not** inherit your shell profile — set `PROXY_AIOPS_MASTER_PASSWORD` (and\n> `PROXY_AIOPS_CONFIG` / `PROXY_AIOPS_HOME` if you relocated them) explicitly in\n> the client config, or the server cannot unlock `secrets.enc`.\n\n## Configuration\n\n`~/.proxy-aiops/config.yaml` (non-secret connection details only):\n\n```yaml\ntargets:\n  - name: edge1\n    platform: traefik        # traefik | caddy | haproxy\n    base_url: http://192.0.2.10:8080\n    verify_ssl: true\n  - name: caddy1\n    platform: caddy\n    base_url: http://127.0.0.1:2019\n  - name: lb1\n    platform: haproxy\n    base_url: http://192.0.2.20:5555\n    username: dpapi          # Data Plane API user\n```\n\nThe **secret** — the HAProxy Data Plane API password, or an optional Basic-auth\npassword in front of Traefik/Caddy — is stored **encrypted** in\n`~/.proxy-aiops/secrets.enc` (Fernet + scrypt-derived key), never plaintext on\ndisk. Traefik and Caddy commonly run unauthenticated on localhost, so their\nsecret is **optional** (like a local socket); HAProxy's is required. Set it with\n`proxy-aiops secret set <target>` or the `init` wizard. The store is unlocked by\na master password from `PROXY_AIOPS_MASTER_PASSWORD` (non-interactive/MCP/CI) or\nan interactive prompt (CLI on a TTY). A legacy plaintext env var\n`PROXY_<TARGET>_SECRET` is honoured as a fallback (migrate with\n`proxy-aiops secret migrate`).\n\n## Governance\n\nEvery MCP tool — and every CLI write, which routes through the same governed\nfunctions — passes through `@governed_tool`. It records; it does not authorize\n(see above).\n\n- **Audit** — every call is logged to `~/.proxy-aiops/audit.db` (tool, params with\n  secrets redacted, status, duration, risk tier, and any operator-supplied\n  approver/rationale). The CLI writes the same row the MCP path does — there is no\n  unaudited entry point.\n- **Budget / runaway guard** — a safety backstop, not an authorization gate:\n  per-process token/call caps and a repeat-call circuit breaker stop a stuck agent\n  from burning unbounded calls/time (`PROXY_MAX_TOOL_CALLS`, `PROXY_RUNAWAY_MAX`,\n  …; disable the breaker with `PROXY_RUNAWAY_MAX=0`).\n- **Undo recording** — reversible writes record an inverse descriptor to\n  `~/.proxy-aiops/undo.db` from the fetched before-state (recording only; an\n  external orchestrator executes it). Undo params match the target tool's own\n  signature, so the descriptor replays as-is.\n- **Risk tier** — a descriptive label on the audit row derived from `risk_level`;\n  it gates nothing.\n- **Sanitisation** — all proxy-returned text is bounded + control-character\n  sanitised before it reaches the agent.\n\n## Platform support & verification status\n\n- **Platforms**: Traefik (API + /metrics), Caddy (admin API), HAProxy (Data Plane\n  API v2).\n- **Test coverage**: behaviour is validated against mocked JSON/metrics responses —\n  every module imports, every MCP tool carries the governance marker, the four flagship\n  analyses are unit-tested against synthetic telemetry, the support matrix is asserted\n  to raise teaching errors (never a silent no-op), and reversible writes are asserted to\n  record the correct inverse undo descriptor. The concrete REST paths are modelled from\n  each project's public API and have not yet been exercised against a live proxy. See\n  [docs/VERIFICATION.md](docs/VERIFICATION.md) for the checklist a live run must\n  satisfy. All three platforms are free and self-hostable (a small container-compose lab\n  with traefik + caddy + haproxy/dataplaneapi is a one-evening setup), and\n  `proxy-aiops doctor` — a health/info probe per platform — is the fastest live check.\n- **Routing note**: this tool operates reverse proxies / load balancers. Do NOT\n  use it for firewall rules — use firewall-aiops.\n- **Missing a capability?** Open an issue or PR at\n  [github.com/AIops-tools/Proxy-AIops](https://github.com/AIops-tools/Proxy-AIops)\n  — contributions and feedback welcome.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 12156,
  "sha": "af82c66e3597a978c686426be475af3fac34119e63a29107b905cbeec6113c43",
  "repo_slug": "aiops-tools/proxy-aiops",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_aiops_tools_proxy_aiops_174383c6/readme"
}