Mount the live Mods tree read-only and add two MCP tools over it: a metadata-only mod inventory and an AutoGen C# source reader #243

Open
opened 2026-08-12 23:46:16 +00:00 by coilyco-ops · 1 comment
Member

Extends the #42 privileged surface with the one on-disk root it never got tools for in depth: the live Mods/ tree, including Eco's generated AutoGen C#.

Why this is cheaper than #42 made it sound

#42 scoped a whole node-pinned deployment — node pin, hostPath mounts, loopback pin, tailnet sidecar. Two of those already exist. The ${NAME}-app Deployment in coilyco-bridge/deploy/services/eco-app/deploy/main.yml is already nodeSelector: kubernetes.io/hostname: kai-server, and already carries a hostAliases pin for the Eco host.

So this needs no new deployment: a hostPath volume for /home/kai/Steam/steamapps/common/EcoServer/Mods with readOnly: true, a volumeMount, and ECO_STATE_DIR pointing at a root containing it. admin/state.py already owns every relative path and verifies resolution stays under the root through symlinks, so the safety half is written.

That also means this lands a real slice of #42 phase 2 — one of the four mounts, on the pod that already exists — rather than waiting for the full privileged deployment.

The two tools

1. admin_mods_tree — metadata only, never content.

Walks Mods/ and returns relative path, type, size, mtime, and extension per entry, plus per-top-level-directory rollups (file count, total bytes, extension histogram). No file contents at any disclosure level.

This must be summary-first from day one. Eco's AutoGen is thousands of generated .cs files; a flat enumeration would land straight in the #240 family-3 response-cap problem. Default to rollups plus top-N, with a bounded subtree argument (resolved under the root, not a free path) and depth / limit caps to walk into detail.

It does not replace admin_mods_installed. That one answers "which mods are installed, at what version, and what's configured but missing" from manifests. This one answers "what files are actually on disk". Different questions; keep both.

2. admin_mod_source — full text, C# only.

Reads one .cs file under a fixed root and returns its text. Extension allowlist, not a general file reader. Arguments: a relative path (resolved and checked under the root, symlink-safe, per the existing _fixed_path contract) and a bounded max_bytes defaulting to something an MCP client can actually consume — call it 64 KB, with an explicit truncated: true and totalBytes when it clips, so a caller knows to page rather than silently getting half a file.

Discovery comes from tool 1; this one only reads.

The decision I want a second opinion on

Which surface do these go on?

/mcp is public and unauthenticated — I can call tools/list on https://eco-app.coilysiren.me/mcp from anywhere with no credential. Mods/AutoGen is SLG's generated game source, and Mods/UserCode may carry private mods from eco-ops. Serving that verbatim over the public MCP is republishing someone else's game content to the internet, which is a licensing question rather than a technical one.

Recommendation: both tools go on the /admin surface, which already assumes an authenticated, non-public boundary and already has the disclosure-level machinery. Concretely that means setting ECO_ADMIN_ENABLED on the existing pod and mounting only Mods — not all four #42 roots — so the blast radius stays at "the mods tree" and Configs/ secrets stay unmounted.

If the metadata tool should be public and only the source reader privileged, that split works too: tool 1 has no licensing exposure, since paths and sizes aren't content.

Why the AutoGen half is worth the trouble

Mods/AutoGen is the authoritative, per-server, post-mod definition of every item, recipe, skill, and block — the same ground truth the Eco Gnome DataExporter reads. #242 currently proposes reading recipes from a vendored vanilla snapshot pinned to July, because that was the only source available. A C# reader over the live tree is a way to verify that snapshot against the running server, and eventually to replace it for modded content. Worth sequencing the two together.

Acceptance

  • The mount is readOnly: true and covers Mods only.
  • admin_mods_tree answers against the live tree without exceeding the response cap, at default arguments, on a tree with thousands of files.
  • admin_mod_source refuses any path that resolves outside the root, and any extension outside the allowlist, with a test for each.
  • Neither tool accepts a free-form absolute path.
  • docs/admin-mcp.md gains the two tools and the new mount in its filesystem-boundary section.

Open questions

  • Roots. AutoGen only, or UserCode too? UserCode is where private eco-ops mods would sit, so it may want a separate flag.
  • Shape. I could not verify the live tree from here — /home/kai/Steam/steamapps/common/EcoServer/Mods is outside the node-stats MCP's readable-root allowlist, so the layout above is from Eco's documented structure and #42's notes, not from a listing. One look on the host before implementing would confirm the directory names and rough file counts.
  • Extensions. .cs only, or also the .csproj / .json that sit beside it?

Refs: #42 (parent, still open — phases 1 and 3 landed, phase 2 deploy did not), #242 (Eco Gnome data plane), #240 (response-size findings), docs/admin-mcp.md.

Extends the #42 privileged surface with the one on-disk root it never got tools for in depth: the live `Mods/` tree, including Eco's generated `AutoGen` C#. ## Why this is cheaper than #42 made it sound #42 scoped a whole node-pinned deployment — node pin, hostPath mounts, loopback pin, tailnet sidecar. Two of those already exist. The `${NAME}-app` Deployment in `coilyco-bridge/deploy/services/eco-app/deploy/main.yml` is **already** `nodeSelector: kubernetes.io/hostname: kai-server`, and already carries a `hostAliases` pin for the Eco host. So this needs no new deployment: a `hostPath` volume for `/home/kai/Steam/steamapps/common/EcoServer/Mods` with `readOnly: true`, a `volumeMount`, and `ECO_STATE_DIR` pointing at a root containing it. `admin/state.py` already owns every relative path and verifies resolution stays under the root through symlinks, so the safety half is written. That also means this lands a real slice of #42 phase 2 — one of the four mounts, on the pod that already exists — rather than waiting for the full privileged deployment. ## The two tools **1. `admin_mods_tree` — metadata only, never content.** Walks `Mods/` and returns relative path, type, size, mtime, and extension per entry, plus per-top-level-directory rollups (file count, total bytes, extension histogram). No file contents at any disclosure level. This must be summary-first from day one. Eco's `AutoGen` is thousands of generated `.cs` files; a flat enumeration would land straight in the #240 family-3 response-cap problem. Default to rollups plus top-N, with a bounded `subtree` argument (resolved under the root, not a free path) and `depth` / `limit` caps to walk into detail. It does **not** replace `admin_mods_installed`. That one answers "which mods are installed, at what version, and what's configured but missing" from manifests. This one answers "what files are actually on disk". Different questions; keep both. **2. `admin_mod_source` — full text, C# only.** Reads one `.cs` file under a fixed root and returns its text. Extension allowlist, not a general file reader. Arguments: a relative `path` (resolved and checked under the root, symlink-safe, per the existing `_fixed_path` contract) and a bounded `max_bytes` defaulting to something an MCP client can actually consume — call it 64 KB, with an explicit `truncated: true` and `totalBytes` when it clips, so a caller knows to page rather than silently getting half a file. Discovery comes from tool 1; this one only reads. ## The decision I want a second opinion on **Which surface do these go on?** `/mcp` is public and unauthenticated — I can call `tools/list` on `https://eco-app.coilysiren.me/mcp` from anywhere with no credential. `Mods/AutoGen` is SLG's generated game source, and `Mods/UserCode` may carry private mods from eco-ops. Serving that verbatim over the public MCP is republishing someone else's game content to the internet, which is a licensing question rather than a technical one. Recommendation: both tools go on the **`/admin`** surface, which already assumes an authenticated, non-public boundary and already has the disclosure-level machinery. Concretely that means setting `ECO_ADMIN_ENABLED` on the existing pod and mounting only `Mods` — not all four #42 roots — so the blast radius stays at "the mods tree" and `Configs/` secrets stay unmounted. If the metadata tool should be public and only the source reader privileged, that split works too: tool 1 has no licensing exposure, since paths and sizes aren't content. ## Why the AutoGen half is worth the trouble `Mods/AutoGen` is the authoritative, per-server, post-mod definition of every item, recipe, skill, and block — the same ground truth the Eco Gnome DataExporter reads. #242 currently proposes reading recipes from a vendored vanilla snapshot pinned to July, because that was the only source available. A C# reader over the live tree is a way to verify that snapshot against the running server, and eventually to replace it for modded content. Worth sequencing the two together. ## Acceptance - The mount is `readOnly: true` and covers `Mods` only. - `admin_mods_tree` answers against the live tree without exceeding the response cap, at default arguments, on a tree with thousands of files. - `admin_mod_source` refuses any path that resolves outside the root, and any extension outside the allowlist, with a test for each. - Neither tool accepts a free-form absolute path. - `docs/admin-mcp.md` gains the two tools and the new mount in its filesystem-boundary section. ## Open questions - **Roots.** `AutoGen` only, or `UserCode` too? UserCode is where private eco-ops mods would sit, so it may want a separate flag. - **Shape.** I could not verify the live tree from here — `/home/kai/Steam/steamapps/common/EcoServer/Mods` is outside the node-stats MCP's readable-root allowlist, so the layout above is from Eco's documented structure and #42's notes, not from a listing. One look on the host before implementing would confirm the directory names and rough file counts. - **Extensions.** `.cs` only, or also the `.csproj` / `.json` that sit beside it? Refs: #42 (parent, still open — phases 1 and 3 landed, phase 2 deploy did not), #242 (Eco Gnome data plane), #240 (response-size findings), `docs/admin-mcp.md`.
Author
Member

Superseded in one respect by #244: /admin is being decommissioned rather than finished, so the recommendation in "The decision I want a second opinion on" — put both tools on the privileged surface, enable ECO_ADMIN_ENABLED, mount only Mods — no longer applies.

Everything else here stands, and gets simpler. The tools go on core /mcp. The hostPath mount is unchanged and still cheap, because ${NAME}-app is already node-pinned to kai-server; it just no longer needs ECO_ADMIN_ENABLED alongside it. Note that admin/state.py holds the symlink-safe path resolution this depends on, and #244 deletes that package — so the resolution helper needs lifting into the core module before the delete lands, or these two tools inherit a path-safety gap. Sequence #243 first, or move the helper as part of #244.

The licensing question the /admin recommendation was answering still needs an answer. #244 lists three options: metadata public with the C# reader behind the existing page_auth.py, or scope the reader to Mods/UserCode only, or ship both public. My preference is the first.

admin_mods_installed also lands here per #244 — it becomes public get_mods and should be built alongside the tree tool rather than ported separately.

Superseded in one respect by #244: `/admin` is being decommissioned rather than finished, so the recommendation in "The decision I want a second opinion on" — put both tools on the privileged surface, enable `ECO_ADMIN_ENABLED`, mount only `Mods` — no longer applies. Everything else here stands, and gets simpler. The tools go on core `/mcp`. The hostPath mount is unchanged and still cheap, because `${NAME}-app` is already node-pinned to kai-server; it just no longer needs `ECO_ADMIN_ENABLED` alongside it. Note that `admin/state.py` holds the symlink-safe path resolution this depends on, and #244 deletes that package — so the resolution helper needs lifting into the core module **before** the delete lands, or these two tools inherit a path-safety gap. Sequence #243 first, or move the helper as part of #244. The licensing question the `/admin` recommendation was answering still needs an answer. #244 lists three options: metadata public with the C# reader behind the existing `page_auth.py`, or scope the reader to `Mods/UserCode` only, or ship both public. My preference is the first. `admin_mods_installed` also lands here per #244 — it becomes public `get_mods` and should be built alongside the tree tool rather than ported separately.
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#243
No description provided.