Scavenge the /admin MCP into the core surface and decommission it (closes out #42) #244

Open
opened 2026-08-12 23:57:07 +00:00 by coilyco-ops · 0 comments
Member

The privileged /admin MCP has never run. ECO_ADMIN_ENABLED and ECO_STATE_DIR appear nowhere in the deploy repo, POST /admin returns 405 in prod, and it has gone un-missed since #42 was filed on 2026-07-03. Retire it: take the parts that earn their place, put them where they belong, delete the rest.

Why it wasn't missed

Not because the capabilities were worthless — because a third of them were already answered by the public surface. admin_live_status reads the same /info route get_server_status reads. admin_events_recent reads the same Chronicler store /replay/api/v1/events serves. Ten of the twelve read-only RCON queries have a public analogue: climate_statusget_climate, governmentget_government, currenciesget_currency, active_elections / civics_tickget_civics, online_players / meteor_status / world_timeget_server_status, population_changesget_region.

The surface was designed inside-out before the outside-in surface had grown to 22 tools. It then got overtaken.

Triage of all 14 tools

Scavenge into core /mcp (2)

Tool Disposition
admin_mods_installed Becomes public get_mods. A mod inventory carries no player names and no secrets. Lands with #243's tree and source reader.
admin_world_meta Fold the world-generator metadata (size, seed, cluster centers) into get_world rather than keeping it standalone.

Delete — already answered by the public surface (5)

admin_live_status, admin_service_health, admin_events_recent, admin_player_activity, admin_rcon_query.

RCON is the only one with unique reach — it is authoritative when the exporter mod is down, which is exactly when the public tools go quiet. It is not worth an ECO_RCON_PASSWORD in the public app to keep that. If liveness verification is ever needed during an outage, that is an operator script, not an MCP tool.

Hand to node-stats-kai-server instead (4)

admin_save_status, admin_backup_list, admin_log_tail, admin_log_grep.

These are host questions wearing an Eco costume: file sizes, file ages, log tails. node-stats-mcp already has stat_path, read_text_head, and a readable-root allowlist, is already registered in mcporter, and is already the tool an agent reaches for when asking about kai-server. Adding the EcoServer/Storage, EcoServer/Backup, and EcoServer/Logs roots to its allowlist delivers all four with zero eco-app code. (Confirmed the allowlist is the live gate: stat_path on the EcoServer tree today returns path is outside the readable-root allowlist.)

That is a repo boundary worth respecting anyway — eco-app is the game-data app; host introspection belongs to the host-introspection MCP.

Delete, and do not relocate (3)

admin_config_get, admin_config_diff, admin_mod_configs.

These read Configs/, which holds the Discord bot token and the server API token. They are the entire reason redaction.py and the three-level disclosure model exist. They do not belong on a public MCP, and they do not belong in node-stats either. Nothing has needed them in five weeks.

Decommission checklist

  • Delete src/eco_mcp_app/admin/ — 1,414 lines across server.py, state.py, rcon.py, redaction.py, runtime.py, __init__.py.
  • Delete tests/mcp/test_admin.py — 651 lines. Total removal ~2,065 lines plus docs/admin-mcp.md (111).
  • Remove from http_app.py: the NormalizeAdminPath middleware, ADMIN_ENABLED_ENV, the admin_enabled branch, the /admin Mount, and the admin session-manager arm of lifespan.
  • Close #42, linking here.

Trap for whoever does this: ECO_ADMIN_TOKEN and _resolve_admin_key() in http_app.py are not part of this surface. That is the Eco server's HTTP API key, used by the public /preview/items.json, /preview/food.json, /preview/item.json, /preview/price-history.json, and /preview/recipes.json fetches, and it is set in the deploy. It stays. Only ECO_ADMIN_ENABLED, ECO_STATE_DIR, ECO_ADMIN_BASE_URL, ECO_RCON_*, and ECO_ADMIN_ALLOW_RAW are dead. A careless grep for ADMIN breaks five live endpoints.

What this does to #243

#243 recommended putting the mods tree and AutoGen source reader on /admin, because /admin was the authenticated boundary. With /admin gone they go on core /mcp, and the concern I raised there needs a different answer: /mcp is public and unauthenticated, and Mods/AutoGen is SLG's generated game source.

Three ways to land it, in my order of preference:

  1. Metadata public, source gated. The tree tool goes public unconditionally — paths and sizes are not content. The C# reader sits behind page_auth.py, which already exists for the hidden /users/<hex> surface, so no second MCP is needed.
  2. Scope the reader to Mods/UserCode — our own mods, ours to serve — and let AutoGen be metadata-only.
  3. Ship both public and accept that generated content from a game the caller already owns is low-stakes redistribution.

Worth deciding before #243 is implemented, not after.

Acceptance

  • tools/list on /mcp gains get_mods; get_world gains the generator metadata.
  • The node-stats allowlist covers the three EcoServer roots, verified by a stat_path call that used to be refused.
  • No /admin route, no ECO_ADMIN_ENABLED branch, no admin/ package.
  • The five preview endpoints that use ECO_ADMIN_TOKEN still work after the deletion — explicit regression check, not an assumption.
  • #42 closed.

Refs: #42, #243, docs/admin-mcp.md, coilyco-flight-deck/node-stats-mcp.

The privileged `/admin` MCP has never run. `ECO_ADMIN_ENABLED` and `ECO_STATE_DIR` appear nowhere in the deploy repo, `POST /admin` returns 405 in prod, and it has gone un-missed since #42 was filed on 2026-07-03. Retire it: take the parts that earn their place, put them where they belong, delete the rest. ## Why it wasn't missed Not because the capabilities were worthless — because a third of them were already answered by the public surface. `admin_live_status` reads the same `/info` route `get_server_status` reads. `admin_events_recent` reads the same Chronicler store `/replay/api/v1/events` serves. Ten of the twelve read-only RCON queries have a public analogue: `climate_status` → `get_climate`, `government` → `get_government`, `currencies` → `get_currency`, `active_elections` / `civics_tick` → `get_civics`, `online_players` / `meteor_status` / `world_time` → `get_server_status`, `population_changes` → `get_region`. The surface was designed inside-out before the outside-in surface had grown to 22 tools. It then got overtaken. ## Triage of all 14 tools **Scavenge into core `/mcp` (2)** | Tool | Disposition | |---|---| | `admin_mods_installed` | Becomes public `get_mods`. A mod inventory carries no player names and no secrets. Lands with #243's tree and source reader. | | `admin_world_meta` | Fold the world-generator metadata (size, seed, cluster centers) into `get_world` rather than keeping it standalone. | **Delete — already answered by the public surface (5)** `admin_live_status`, `admin_service_health`, `admin_events_recent`, `admin_player_activity`, `admin_rcon_query`. RCON is the only one with unique reach — it is authoritative when the exporter mod is down, which is exactly when the public tools go quiet. It is not worth an `ECO_RCON_PASSWORD` in the public app to keep that. If liveness verification is ever needed during an outage, that is an operator script, not an MCP tool. **Hand to `node-stats-kai-server` instead (4)** `admin_save_status`, `admin_backup_list`, `admin_log_tail`, `admin_log_grep`. These are host questions wearing an Eco costume: file sizes, file ages, log tails. `node-stats-mcp` already has `stat_path`, `read_text_head`, and a readable-root allowlist, is already registered in mcporter, and is already the tool an agent reaches for when asking about kai-server. Adding the `EcoServer/Storage`, `EcoServer/Backup`, and `EcoServer/Logs` roots to its allowlist delivers all four with **zero eco-app code**. (Confirmed the allowlist is the live gate: `stat_path` on the EcoServer tree today returns `path is outside the readable-root allowlist`.) That is a repo boundary worth respecting anyway — eco-app is the game-data app; host introspection belongs to the host-introspection MCP. **Delete, and do not relocate (3)** `admin_config_get`, `admin_config_diff`, `admin_mod_configs`. These read `Configs/`, which holds the Discord bot token and the server API token. They are the entire reason `redaction.py` and the three-level disclosure model exist. They do not belong on a public MCP, and they do not belong in node-stats either. Nothing has needed them in five weeks. ## Decommission checklist - Delete `src/eco_mcp_app/admin/` — 1,414 lines across `server.py`, `state.py`, `rcon.py`, `redaction.py`, `runtime.py`, `__init__.py`. - Delete `tests/mcp/test_admin.py` — 651 lines. Total removal ~2,065 lines plus `docs/admin-mcp.md` (111). - Remove from `http_app.py`: the `NormalizeAdminPath` middleware, `ADMIN_ENABLED_ENV`, the `admin_enabled` branch, the `/admin` Mount, and the admin session-manager arm of `lifespan`. - Close #42, linking here. **Trap for whoever does this:** `ECO_ADMIN_TOKEN` and `_resolve_admin_key()` in `http_app.py` are **not** part of this surface. That is the Eco server's HTTP API key, used by the public `/preview/items.json`, `/preview/food.json`, `/preview/item.json`, `/preview/price-history.json`, and `/preview/recipes.json` fetches, and it is set in the deploy. It stays. Only `ECO_ADMIN_ENABLED`, `ECO_STATE_DIR`, `ECO_ADMIN_BASE_URL`, `ECO_RCON_*`, and `ECO_ADMIN_ALLOW_RAW` are dead. A careless grep for `ADMIN` breaks five live endpoints. ## What this does to #243 #243 recommended putting the mods tree and AutoGen source reader on `/admin`, because `/admin` was the authenticated boundary. With `/admin` gone they go on core `/mcp`, and the concern I raised there needs a different answer: `/mcp` is public and unauthenticated, and `Mods/AutoGen` is SLG's generated game source. Three ways to land it, in my order of preference: 1. **Metadata public, source gated.** The tree tool goes public unconditionally — paths and sizes are not content. The C# reader sits behind `page_auth.py`, which already exists for the hidden `/users/<hex>` surface, so no second MCP is needed. 2. **Scope the reader to `Mods/UserCode`** — our own mods, ours to serve — and let AutoGen be metadata-only. 3. **Ship both public** and accept that generated content from a game the caller already owns is low-stakes redistribution. Worth deciding before #243 is implemented, not after. ## Acceptance - `tools/list` on `/mcp` gains `get_mods`; `get_world` gains the generator metadata. - The node-stats allowlist covers the three EcoServer roots, verified by a `stat_path` call that used to be refused. - No `/admin` route, no `ECO_ADMIN_ENABLED` branch, no `admin/` package. - The five preview endpoints that use `ECO_ADMIN_TOKEN` still work after the deletion — explicit regression check, not an assumption. - #42 closed. Refs: #42, #243, `docs/admin-mcp.md`, `coilyco-flight-deck/node-stats-mcp`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/eco-app#244
No description provided.