Proposal: first-party MCP server (`awa mcp serve`) exposing operator surfaces as tools
- Dominant language
- Rust
- Stars
- 32
- Forks
- 5
- Avg merge
- 15h 21m
- Merged PRs (30d)
- 21
Description
## Motivation
Operators increasingly drive infrastructure through agents (Claude Code / Desktop, IDE agents, custom automations). Today an agent operating awa has to shell out to `awa` CLI commands or hand-write SQL against surfaces we explicitly document as internal. A first-party MCP (Model Context Protocol) server makes the *supported* surfaces — admin reads, diagnostics, DLQ/batch operations, cron control — available to agents as typed, discoverable tools with the same contract guarantees as the CLI's `--json` output.
awa is unusually well positioned for this:
- The **descriptor catalog** (ADR-022) already gives code-declared, self-describing queue/job-kind metadata — exactly what an agent needs to orient ("what runs here, what does it mean").
- `awa doctor` (#373) is designed as structured operational diagnostics with `--json`; as an MCP tool it becomes the agent's first call in any incident.
- The **stability policy** (docs/stability.md, #369) already promises stable `--json` schemas for the CLI; MCP tools can reuse the same response types via the `awa-api` crate split (#143) instead of inventing a third contract.
- The surface taxonomy from ADR-027 extends naturally: the MCP server is a **private operator surface**, deployed like the admin API, never public.
Real-world shape this serves (from operating awa in production): an on-call human asks an agent "why is rescue failing?" — the agent calls `doctor`, `storage_status`, `job_dump`, finds a wedged unique-key conflict (#388), proposes the `cancel` mutation, and the human approves it. Every step typed, audited, and inside the supported surface.
## Proposed scope
**`awa mcp serve`** (subcommand in `awa-cli`, or a feature-gated binary — open question), speaking MCP over **stdio** (local/spawned) and **streamable HTTP** (remote), built on the official Rust MCP SDK (`rmcp`).
### Tier 1 — read-only tools (default-on)
| Tool | Backed by |
| --- | --- |
| `doctor` | #373 checks, `--json` schema |
| `storage_status` | `awa storage status` |
| `queue_list` / `queue_counts` | admin ops (exact + `queue_counts_fast`) |
| `job_get` / `job_dump` / `job_search` | admin ops, `terminal_jobs` read surface |
| `dlq_depth` / `dlq_list` | ADR-020 surfaces |
| `cron_list` | cron admin |
| `fleet_status` | `runtime_instances` snapshots (#368 health semantics) |
| `batch_ops_list` / `batch_ops_get` | ADR-030 |
| `descriptors` | ADR-022 catalog |
### Tier 2 — mutating tools (opt-in flag, e.g. `--allow-mutations`)
`job_retry`, `job_cancel`, `dlq_retry`, `dlq_move`, `cron_pause`/`cron_resume`, `batch_ops_preview`/`batch_ops_submit`/`batch_ops_cancel`. Every mutating call emits the same structured audit log line as the admin API (#343's audit requirement). MCP's tool-annotation hints (`readOnlyHint`/`destructiveHint`) set accurately so agent harnesses can gate confirmation UX.
### Tier 3 — producer tools (separate opt-in, maybe never)
`enqueue` is deliberately **not** in scope for the first cut: agents inserting work is a different risk class, and the SQL producer contract (#342) plus language SDKs already cover programmatic producers. Revisit with field evidence.
## Security posture (aligns with D5 / #343)
- Binds loopback by default; non-loopback bind without auth means read-only + banner, exactly like `awa serve`.
- Token auth reuses `AWA_ADMIN_TOKEN`; the HTTP transport sits behind the same proxy patterns documented for the admin UI.
- Mutations always off unless explicitly enabled; Tier-2 enablement is a deploy-time decision, not a client-negotiated one.
## Non-goals
- Not a workflow engine interface (PRD non-goal stands; no tools that compose jobs into DAGs).
- Not a replacement for the admin UI or CLI — same operations, third front-end, one shared contract (via `awa-api` types).
- No public/multi-tenant exposure; this is a private operator surface per the ADR-027 taxonomy.
## Dependencies / sequencing
#143 (`awa-api` crate) and #373 (`awa doctor`) provide the response types and the flagship tool; #343 provides auth; #369 defines the compatibility promise the tool schemas inherit. All are 0.7-milestoned — hence proposing this for **v0.8.0**, where it also pairs well with the post-canonical, single-engine surface.
## Open questions
1. Subcommand in `awa-cli` (pulls `rmcp` into the CLI build) vs. a separate `awa-mcp` crate/binary published alongside?
2. Tool-schema versioning: pin to the stability policy's CLI `--json` promise, or version the MCP tool set independently?
3. Should `doctor` remediation guidance (e.g. #388's workaround SQL) be returned as MCP *prompts*/resources so agents get runbooks, not just data?
4. Rate limiting / concurrency caps for read tools against production databases (reuse `queue_counts_fast` guidance).
If the direction lands, next step is an ADR (next free number) plus a spike wiring `doctor` + `storage_status` + `queue_counts` over stdio.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reading docs/stability.md, ADR-022, ADR-027, and the linked issues #143, #343, #369, and #373. Then compare the awa-cli entry points and awa-api crate plan while evaluating the stdio spike for doctor, storage_status, and queue_counts using rmcp. Done means an ADR resolves the open architecture, schema, security, and transport questions and defines the v0.8.0 scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, rust
- Domain
- api, backend-api-design, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100