Eco MCP battery phase 1: scaffold the privileged /admin MCP + redaction against a local state checkout (#42) #59
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Phase 1 of the Eco MCP battery (#42) - the inside-out privileged MCP that lets warded agents (and, later, Kai via claude.ai) inspect on-disk Eco server state. This issue is the first, fully non-destructive slice: prove the tools and the redaction on real files, with no deploy and no live-server touch. MCP-only, no REST (per #42's refinements).
Scope (phase 1 only)
/admin, feature-flagged (ECO_ADMIN_ENABLED, default off) so the public deployment never exposes it.eco_save_status(Game.eco/Game.db size + age),eco_backup_list(Backup/ count, cadence, newest/oldest),eco_config_get(named.eco/.diff.json).public(names hashed),operator(names shown, secrets stripped),raw(operator + secrets, default DENY). Defaultoperator. Secrets (Discord bot token, server-api-token, any token in Configs) never returned aboveraw.../../.ssh.Out of scope (later #42 phases)
Node-local k3s deploy (hostPath RO, node-pin, loopback) is phase 2. Chronicler/logs/live-runtime tool groups are phase 3. The Authelia OAuth overlay for the claude.ai path is deploy-side (see the deploy overlay-slot issue). No REST surface.
Guardrails
Read-only, local files only, no live-server interaction, no deploy. This slice runs entirely against sample/local state files.
Acceptance
/adminmount feature-flagged off by default; the public app is unchanged when the flag is unset.rawdefault-DENY and secret-stripping).ward exec test/ward exec lint/ward exec smokegreen.docs/FEATURES.mdnotes the privileged MCP as feature-flagged/experimental.Parent
#42. Access model + REST-out decisions are in #42's 2026-07-05 comment.
🔒 Reserved by
ward agent --driver claude— containerengineer-claude-eco-app-59on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T03:39:12Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).
— Claude (she/her), via
ward agentWARD-OUTCOME: done - privileged /admin MCP (3 tools, 3 redaction levels, enum-not-path) scaffolded feature-flagged off, landed on main.
Retro, in my own voice:
This one went smoothly, which honestly made me a little suspicious, so I over-invested in the redaction tests. The shape of the problem is small and the existing
build_server/http_appmount pattern gave me a clean template to mirror, so the second MCP dropped in without fighting me.Two things worth noting. First, redaction ordering: a key like
DiscordTokenmatches both the name regex and the secret regex, and getting that precedence wrong would leak a token as a "hashed name". I made secret classification win unconditionally and pinned it with a test. Second, the raw level: "default DENY" only means something if there's a lever to lift it, so I gated it behindECO_ADMIN_ALLOW_RAWrather than leavingrawpermanently dead or permanently open.Small friction: backup cadence needs real mtimes, and git doesn't preserve those, so the fixture copies the sample tree into tmp_path and sets mtimes with os.utime. And ward's repo-verb audit refused to run until the branch had an upstream, so I pushed the branch before the final green run.
Confidence is high on the Python surface (372 tests green, lint clean, and I drove a real HTTP round-trip through the mounted /admin to confirm secret-stripping end to end). The redaction is deliberately conservative (broad name regex, secret-wins), so if anything it over-redacts rather than under.
Rough edges / follow-ups worth filing: the
.eco-that-isn't-valid-JSON fallback path returns raw text and only structurally redacts JSON, so a non-JSON config gets name/secret redaction skipped - fine for the sample configs (all JSON) but worth hardening if a real server ships a non-JSON.eco. And the enum of known configs is hand-maintained; phase 2/3 may want it derived from what's actually on disk. Both are out of scope for this non-destructive slice.