feat(chart): generic ward-mcp Helm chart - one runtime image, guardfile as ConfigMap, Authelia route (ward-mcp ships it) #8
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?
What
The generic ward-mcp Helm chart - the distribution vehicle ward-mcp ships (ward-mcp#6). One chart, one runtime image, many releases: the
.mcp.kdlrides in as chart values (a ConfigMap), and the chart templates all the k8s exposure. Adding an MCP becomes a values file +helm upgrade, no per-guardfile image build.Templates
.mcp.kdlfrom--set-file spec=..., mounted into the runtime at/spec/<name>.mcp.kdl.ward-mcp serve /spec/<name>.mcp.kdl --http :8080, the token injected as env.publicvstailnet-onlyvalues toggle. This is deploy#30's fleet auth-overlay, generalized for ward-mcp servers.value env <VAR>.Values (the deploy-supplied surface)
spec(the .mcp.kdl, via --set-file),route.host,route.public(bool),secret.<ENV>refs,image.tag, resource limits. deploy consumes the chart per-MCP with one values file (deploy#61 skillsmp, deploy#46 forgejo).Runtime contract this targets (pin it; the runtime issue implements it)
ward-mcp serve /spec/<name>.mcp.kdl --http :8080/mcpvalue env <VAR>.mcp.kdlread from the mounted path, not bakedSequencing
Buildable against the pinned contract above in parallel with the runtime; finalize the mount path / port / health probe once the runtime lands. Ships in the ward-mcp repo (the product distributes as image + chart), consumed by deploy as values.
Related: ward-mcp#6 (distribution decision), the ward-mcp runtime issue (the image the chart runs), deploy#30 (fleet auth overlay), deploy#61 / deploy#46 (first consumers).
🔒 Reserved by
ward agent --driver claude— containerengineer-claude-ward-mcp-8on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-07T09:33:54Z). 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).
run seed context — what this run is carrying (ward#609)
coilyco-flight-deck/ward-mcp#8· branchissue-8· driverclaude· workflowdirect-mainengineer-claude-ward-mcp-8· wardv0.419.0· dispatched2026-07-07T09:33:54ZIssue body as seeded:
… (truncated to 2000 chars; full body is on this issue)
Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.419.0).
— Claude (she/her), via
ward agentWARD-OUTCOME: done - generic ward-mcp Helm chart (spec-as-ConfigMap, token Secret wiring, public/tailnet Authelia route toggle) landed on main, closes #8.
This one went smoothly, mostly because the raw material was already sitting in
/substrate/deploy. reddit-mcp'smain.ymlis the entire deploy#30 auth overlay written out longhand, and agent-proxy's chart is a clean Helm skeleton. The work was really generalizing the former into the shape of the latter - lift the ForwardAuth + oauth2-proxy + RFC 9728 metadata sidecar out of one hardcoded service and parameterize host/client-id/audiences/SSM-paths. Having both references verbatim meant almost no guessing.What took the most thought was the
secretvalues surface: the issue's--set secret.SKILLSMP_API_KEY=<ref>example wants a map of env-var -> source, but a source can be either an SSM path (mint an ExternalSecret) or an existing Secret ref. I settled on string-vs-map detection (kindIs) so both forms live in one key, and verified the ExternalSecret only renders when at least one entry is a bare string.Confidence is high on the templating itself -
helm lint+helm templatepiped through a YAML parser pass for both a public read (13 docs) and a tailnet-only write (4 docs), and I eyeballed the fiddly bits (the@kubernetescrdmiddleware ref form, the well-known JSON, the args). The honest caveat is I can't render against a live cluster from here, so the runtime contract (mount path,:8080,/mcp, probe) is pinned rather than proven - it finalizes once the runtime image (inbox#164) actually exists. I also had to reconcile README/DESIGN, which previously declared all exposure out-of-scope-lives-in-deploy; the reconciliation hinges on the chart being spec-opaque, so the interior-only scope genuinely still holds.Rough edges worth a follow-up: the fleet's NodePort convention (30000 + last-three) can't be auto-derived from
:8080without collisions, so it stays a per-MCP values knob the deploy operator must pick by hand - fine, but easy to fumble. And the defaultimage.repositorypoints at the public Forgejo path to keep this repo public-safe; deploy must override it to the in-cluster registry mirror or pulls will miss.