cad-mcp is live at cad-mcp.d-ma.be (deployment topology: mathias/brain wiki wing:agentsquad/facts/cad-live-on-koala-topology-and-wiring.md) but isn't wired as a local plugin MCP for sessions running on koala itself, unlike brain/infra which already are.
Pattern to follow (.mcp.json in this repo)
both existing entries go through Tailscale Serve on koala, not the public hostname -- the public path exits through Cloudflare + NPM to reach a k3s service on the same machine most sessions run on, which imposes rate limits and message-size caps. Serve terminates TLS locally with a real Tailscale cert and proxies to the NodePort over loopback, satisfying the default-deny-ingress NetworkPolicy with no cluster change (mathias/skills#24).
cad's k8s Service is already type: NodePort -- confirmed live: kubectl get svc -n cad cad -> 8081:31877/TCP is the MCP port (JSON-RPC + SSE, tool: cad_status). No infra-repo change required for this one, unlike gitea-mcp (companion issue).
Do
tailscale serve --bg --https=8445 http://127.0.0.1:31877 on koala (next free port after 8444).
(confirm the exact env var name against whatever ESO secret backs CAD_STATIC_TOKEN in k3s/apps/cad/ -- the fact doc names the secret CAD_STATIC_TOKEN, the local env var convention elsewhere is <SERVICE>_MCP_TOKEN, reconcile before wiring.)
Wire the token into wherever koala sources BRAIN_MCP_TOKEN/INFRA_MCP_TOKEN today (~/.op-env) so ${CAD_MCP_TOKEN} resolves.
Risk to check BEFORE wiring, not after
brain is currently in .mcp.json's _disabled block: "parked until hyperguild#9 fixes static Bearer precedence -- claude MCP client does OAuth discovery on 401 and ignores the header, breaking on Dex (no dynamic client registration)". cad-mcp's own topology doc says it serves /.well-known/oauth-protected-resourceunauthenticated by design (v0.6.0 fix, so claude.ai OAuth discovery works) alongside the CAD_STATIC_TOKEN bearer fallback -- structurally the same shape that broke brain. This may hit the identical client-side bug. Verify a static-bearer local-plugin connection actually works end-to-end (not just that the header is sent) before considering this done; if it hits the same wall, this issue is blocked on hyperguild#9, not miswired.
Acceptance
claude mcp list (or equivalent) shows cad connected, not erroring into an OAuth redirect.
cad_status tool callable from a koala session.
If blocked by the OAuth-discovery bug, this issue says so explicitly and links hyperguild#9 rather than staying vague.
cad-mcp is live at `cad-mcp.d-ma.be` (deployment topology: `mathias/brain` wiki `wing:agentsquad/facts/cad-live-on-koala-topology-and-wiring.md`) but isn't wired as a local plugin MCP for sessions running on koala itself, unlike `brain`/`infra` which already are.
## Pattern to follow (`.mcp.json` in this repo)
both existing entries go through Tailscale Serve on koala, not the public hostname -- the public path exits through Cloudflare + NPM to reach a k3s service on the *same machine* most sessions run on, which imposes rate limits and message-size caps. Serve terminates TLS locally with a real Tailscale cert and proxies to the NodePort over loopback, satisfying the default-deny-ingress NetworkPolicy with no cluster change (mathias/skills#24).
Current state, confirmed live:
```
tailscale serve status
https://koala.tail30472e.ts.net:8443 -> 127.0.0.1:30330 (brain)
https://koala.tail30472e.ts.net:8444 -> 127.0.0.1:30342 (infra)
```
## cad-mcp specifics (no cluster change needed)
`cad`'s k8s Service is already `type: NodePort` -- confirmed live: `kubectl get svc -n cad cad` -> `8081:31877/TCP` is the MCP port (JSON-RPC + SSE, tool: `cad_status`). No infra-repo change required for this one, unlike gitea-mcp (companion issue).
## Do
1. `tailscale serve --bg --https=8445 http://127.0.0.1:31877` on koala (next free port after 8444).
2. Add to `.mcp.json`:
```json
"cad": {
"type": "http",
"url": "https://koala.tail30472e.ts.net:8445/mcp",
"headers": { "Authorization": "Bearer ${CAD_MCP_TOKEN}" }
}
```
(confirm the exact env var name against whatever ESO secret backs `CAD_STATIC_TOKEN` in `k3s/apps/cad/` -- the fact doc names the secret `CAD_STATIC_TOKEN`, the local env var convention elsewhere is `<SERVICE>_MCP_TOKEN`, reconcile before wiring.)
3. Wire the token into wherever koala sources `BRAIN_MCP_TOKEN`/`INFRA_MCP_TOKEN` today (`~/.op-env`) so `${CAD_MCP_TOKEN}` resolves.
## Risk to check BEFORE wiring, not after
`brain` is currently in `.mcp.json`'s `_disabled` block: *"parked until hyperguild#9 fixes static Bearer precedence -- claude MCP client does OAuth discovery on 401 and ignores the header, breaking on Dex (no dynamic client registration)"*. cad-mcp's own topology doc says it serves `/.well-known/oauth-protected-resource` **unauthenticated by design** (v0.6.0 fix, so claude.ai OAuth discovery works) alongside the CAD_STATIC_TOKEN bearer fallback -- structurally the same shape that broke brain. This may hit the identical client-side bug. Verify a static-bearer local-plugin connection actually works end-to-end (not just that the header is sent) before considering this done; if it hits the same wall, this issue is blocked on hyperguild#9, not miswired.
## Acceptance
- `claude mcp list` (or equivalent) shows `cad` connected, not erroring into an OAuth redirect.
- `cad_status` tool callable from a koala session.
- If blocked by the OAuth-discovery bug, this issue says so explicitly and links hyperguild#9 rather than staying vague.
Unauthenticated probe returns 401, so the path is right and auth is enforced — not a 404, not a hang, not an OAuth redirect.
Blocked
Step 3 — "wire the token into wherever koala sources BRAIN_MCP_TOKEN" — cannot be done from this host. CAD_STATIC_TOKEN lives in the AgentSecrets vault, and koala's op identity sees only HomeLab:
$ op vault list
ID NAME
uormr2z26h5zz3nlbgarfcnx24 HomeLab
$ op run --env-file=<(echo 'T=op://HomeLab/CAD_STATIC_TOKEN/password') -- ...
[ERROR] could not resolve item UUID for item CAD_STATIC_TOKEN:
could not find item CAD_STATIC_TOKEN in vault uormr2z26h5zz3nlbgarfcnx24
$ op run --env-file=<(echo 'T=op://AgentSecrets/CAD_STATIC_TOKEN/password') -- ...
[ERROR] "AgentSecrets" isn't a vault in this account.
That is infra#224, the known gap where koala's service account cannot see AgentSecrets.
The item name comes from the ExternalSecret (cad-static-token → remoteRef.key: CAD_STATIC_TOKEN, property: password), read by reference only. No secret value was retrieved, printed or transformed at any point, and the in-cluster secret was deliberately not read — extracting it to route around the vault would defeat the reason it lives there.
The risk this issue named did not materialise
Both #32 and #33 warned this might hit the OAuth-discovery bug that parked brain. Two observations against that: brain is not parked any more — it is live in mcpServers and its tools worked throughout today's session — and cad's 401 is a plain token rejection, not an OAuth challenge. So the fear was reasonable and appears to be stale. It cannot be fully ruled out until a valid token is presented, because a client that ignores a good header would look identical from the outside.
Recorded, not enabled
.mcp.json gains a _parked block (7ba01ab) holding the exact entry, with the blocker in the file. A live entry that cannot authenticate would fail on every session start on this host, which is worse than an absent one.
To finish, in order:
Resolve infra#224, or add a HomeLab-visible reference for the same secret.
CAD_MCP_TOKEN=op://<vault>/CAD_STATIC_TOKEN/password in ~/.op-env.
Move the entry from _parked into mcpServers.
Then, and only then, this issue's acceptance test: cad_status callable from a koala session.
Naming note for step 2, which the issue asked to reconcile: the local convention is <SERVICE>_MCP_TOKEN, so CAD_MCP_TOKEN pointing at the CAD_STATIC_TOKEN item — env var named for the client, item named for the server.
Serve port is up and the proxy works; the wiring is **blocked on vault visibility**, and not on what this issue predicted.
## Done
`tailscale serve --bg --https=8445 http://127.0.0.1:31877` (run by Mathias on koala):
```
https://koala.tail30472e.ts.net:8445 (tailnet only)
|-- / proxy http://127.0.0.1:31877
```
Unauthenticated probe returns **401**, so the path is right and auth is enforced — not a 404, not a hang, not an OAuth redirect.
## Blocked
Step 3 — "wire the token into wherever koala sources `BRAIN_MCP_TOKEN`" — cannot be done from this host. `CAD_STATIC_TOKEN` lives in the **AgentSecrets** vault, and koala's `op` identity sees only HomeLab:
```
$ op vault list
ID NAME
uormr2z26h5zz3nlbgarfcnx24 HomeLab
$ op run --env-file=<(echo 'T=op://HomeLab/CAD_STATIC_TOKEN/password') -- ...
[ERROR] could not resolve item UUID for item CAD_STATIC_TOKEN:
could not find item CAD_STATIC_TOKEN in vault uormr2z26h5zz3nlbgarfcnx24
$ op run --env-file=<(echo 'T=op://AgentSecrets/CAD_STATIC_TOKEN/password') -- ...
[ERROR] "AgentSecrets" isn't a vault in this account.
```
That is **infra#224**, the known gap where koala's service account cannot see AgentSecrets.
The item name comes from the ExternalSecret (`cad-static-token` → `remoteRef.key: CAD_STATIC_TOKEN`, `property: password`), read by reference only. No secret value was retrieved, printed or transformed at any point, and the in-cluster secret was deliberately not read — extracting it to route around the vault would defeat the reason it lives there.
## The risk this issue named did not materialise
Both #32 and #33 warned this might hit the OAuth-discovery bug that parked `brain`. Two observations against that: `brain` is **not** parked any more — it is live in `mcpServers` and its tools worked throughout today's session — and cad's 401 is a plain token rejection, not an OAuth challenge. So the fear was reasonable and appears to be stale. It cannot be fully ruled out until a valid token is presented, because a client that ignores a good header would look identical from the outside.
## Recorded, not enabled
`.mcp.json` gains a `_parked` block (`7ba01ab`) holding the exact entry, with the blocker in the file. A live entry that cannot authenticate would fail on every session start on this host, which is worse than an absent one.
To finish, in order:
1. Resolve infra#224, or add a HomeLab-visible reference for the same secret.
2. `CAD_MCP_TOKEN=op://<vault>/CAD_STATIC_TOKEN/password` in `~/.op-env`.
3. Move the entry from `_parked` into `mcpServers`.
4. Then, and only then, this issue's acceptance test: `cad_status` callable from a koala session.
Naming note for step 2, which the issue asked to reconcile: the local convention is `<SERVICE>_MCP_TOKEN`, so `CAD_MCP_TOKEN` pointing at the `CAD_STATIC_TOKEN` item — env var named for the client, item named for the server.
Correcting my previous comment: the blocker I named was wrong, and the brain had the answer.
op vault list returning HomeLab only is not the whole story. koala carries a second, scoped service account at ~/.op-agent-write.env (koala-agentsecrets-write). infra#224 was closed on 2026-08-04 by provisioning exactly that, deliberately, rather than widening koala-homelab. So citing #224 as an open blocker was wrong twice — it is closed, and the capability exists.
With the right token sourced, cad authenticates:
$ set -a; . ~/.op-agent-write.env; set +a
$ op vault list
s2hsj4qipqvfynxzijmhszpdy4 AgentSecrets
$ op run --env-file=/tmp/probe.env -- curl -X POST .../8445/mcp -H "Authorization: Bearer $CAD_MCP_TOKEN" ...
200
{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"tools":{}},"protocolVersion":"2025-03-26",
"serverInfo":{"name":"cad","version":"aed2aaf"}}}
A real MCP initialize result from cad aed2aaf. Nothing about the service, the NodePort, the Serve proxy or the token is broken. The OAuth-discovery risk this issue flagged did not materialise either.
What is actually blocking
Delivery into the session environment. By design, no single identity on koala reads both vaults — koala-homelab (HomeLab only) resolves ~/.op-env, koala-agentsecrets-write (AgentSecrets only) lives in a separate file. The session env comes from one op run --env-file ~/.op-env, so it structurally cannot carry an AgentSecrets reference.
And the obvious workaround is a trap, which is why I tested it before proposing it:
BRAIN_MCP_TOKEN=op://HomeLab/... # known-good
GITEA_MCP_STATIC_TOKEN=op://AgentSecrets/...
$ op run --env-file=/tmp/mixed.env -- sh -c '[ -n "$BRAIN_MCP_TOKEN" ] && echo resolved'
[ERROR] "AgentSecrets" isn't a vault in this account.
op run aborts the entire file. Adding the line to ~/.op-env would leave brain and every other token unresolved at next session start — it breaks what works today to fix what does not.
Filed as mathias/infra#329, recommending a third read-only AgentSecrets token plus two-pass resolution, rather than widening koala-homelab (which would undo what #224 deliberately chose).
.mcp.json's _parked reason is corrected in c377c23 — the entry is right, the token name is right, and the note now says the tokens work and the delivery does not.
Step 4 of this issue's acceptance (cad_status callable from a koala session) is one env-var away, not one debugging session away.
Correcting my previous comment: the blocker I named was wrong, and the brain had the answer.
**`op vault list` returning HomeLab only is not the whole story.** koala carries a *second*, scoped service account at `~/.op-agent-write.env` (`koala-agentsecrets-write`). infra#224 was closed on 2026-08-04 by provisioning exactly that, deliberately, rather than widening `koala-homelab`. So citing #224 as an open blocker was wrong twice — it is closed, and the capability exists.
With the right token sourced, cad authenticates:
```
$ set -a; . ~/.op-agent-write.env; set +a
$ op vault list
s2hsj4qipqvfynxzijmhszpdy4 AgentSecrets
$ op run --env-file=/tmp/probe.env -- curl -X POST .../8445/mcp -H "Authorization: Bearer $CAD_MCP_TOKEN" ...
200
{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"tools":{}},"protocolVersion":"2025-03-26",
"serverInfo":{"name":"cad","version":"aed2aaf"}}}
```
A real MCP `initialize` result from `cad aed2aaf`. Nothing about the service, the NodePort, the Serve proxy or the token is broken. The OAuth-discovery risk this issue flagged did not materialise either.
## What is actually blocking
Delivery into the session environment. By design, no single identity on koala reads both vaults — `koala-homelab` (HomeLab only) resolves `~/.op-env`, `koala-agentsecrets-write` (AgentSecrets only) lives in a separate file. The session env comes from one `op run --env-file ~/.op-env`, so it structurally cannot carry an AgentSecrets reference.
And the obvious workaround is a trap, which is why I tested it before proposing it:
```
BRAIN_MCP_TOKEN=op://HomeLab/... # known-good
GITEA_MCP_STATIC_TOKEN=op://AgentSecrets/...
$ op run --env-file=/tmp/mixed.env -- sh -c '[ -n "$BRAIN_MCP_TOKEN" ] && echo resolved'
[ERROR] "AgentSecrets" isn't a vault in this account.
```
`op run` aborts the entire file. Adding the line to `~/.op-env` would leave `brain` and every other token unresolved at next session start — it breaks what works today to fix what does not.
Filed as **mathias/infra#329**, recommending a third read-only AgentSecrets token plus two-pass resolution, rather than widening `koala-homelab` (which would undo what #224 deliberately chose).
`.mcp.json`'s `_parked` reason is corrected in `c377c23` — the entry is right, the token name is right, and the note now says the tokens work and the delivery does not.
Step 4 of this issue's acceptance (`cad_status` callable from a koala session) is one env-var away, not one debugging session away.
Narrowing this one: the shared _parked reason covered cad and gitea together, and it has now been disproven for gitea only (#33) — gitea-mcp is pass-through-authenticated, so it needed no AgentSecrets token at all.
cad is not in that position. It presents CAD_MCP_TOKEN, a dedicated static token in the AgentSecrets vault, so the identity split from infra#224 is a genuine blocker here and this issue stands as written.
Worth checking before doing the identity work, though: if cad-mcp could accept a pass-through credential the session already holds, this issue collapses the same way #33 did. Cheap to test — probe https://koala.tail30472e.ts.net:8445/mcp with a initialize call using each already-present token and see whether any returns 200.
Narrowing this one: the shared `_parked` reason covered **cad and gitea together**, and it has now been disproven for gitea only (#33) — gitea-mcp is pass-through-authenticated, so it needed no AgentSecrets token at all.
**cad is not in that position.** It presents `CAD_MCP_TOKEN`, a dedicated static token in the AgentSecrets vault, so the identity split from infra#224 is a genuine blocker here and this issue stands as written.
Worth checking before doing the identity work, though: if cad-mcp could accept a pass-through credential the session already holds, this issue collapses the same way #33 did. Cheap to test — probe `https://koala.tail30472e.ts.net:8445/mcp` with a `initialize` call using each already-present token and see whether any returns 200.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
cad-mcp is live at
cad-mcp.d-ma.be(deployment topology:mathias/brainwikiwing:agentsquad/facts/cad-live-on-koala-topology-and-wiring.md) but isn't wired as a local plugin MCP for sessions running on koala itself, unlikebrain/infrawhich already are.Pattern to follow (
.mcp.jsonin this repo)both existing entries go through Tailscale Serve on koala, not the public hostname -- the public path exits through Cloudflare + NPM to reach a k3s service on the same machine most sessions run on, which imposes rate limits and message-size caps. Serve terminates TLS locally with a real Tailscale cert and proxies to the NodePort over loopback, satisfying the default-deny-ingress NetworkPolicy with no cluster change (mathias/skills#24).
Current state, confirmed live:
cad-mcp specifics (no cluster change needed)
cad's k8s Service is alreadytype: NodePort-- confirmed live:kubectl get svc -n cad cad->8081:31877/TCPis the MCP port (JSON-RPC + SSE, tool:cad_status). No infra-repo change required for this one, unlike gitea-mcp (companion issue).Do
tailscale serve --bg --https=8445 http://127.0.0.1:31877on koala (next free port after 8444)..mcp.json:CAD_STATIC_TOKENink3s/apps/cad/-- the fact doc names the secretCAD_STATIC_TOKEN, the local env var convention elsewhere is<SERVICE>_MCP_TOKEN, reconcile before wiring.)BRAIN_MCP_TOKEN/INFRA_MCP_TOKENtoday (~/.op-env) so${CAD_MCP_TOKEN}resolves.Risk to check BEFORE wiring, not after
brainis currently in.mcp.json's_disabledblock: "parked until hyperguild#9 fixes static Bearer precedence -- claude MCP client does OAuth discovery on 401 and ignores the header, breaking on Dex (no dynamic client registration)". cad-mcp's own topology doc says it serves/.well-known/oauth-protected-resourceunauthenticated by design (v0.6.0 fix, so claude.ai OAuth discovery works) alongside the CAD_STATIC_TOKEN bearer fallback -- structurally the same shape that broke brain. This may hit the identical client-side bug. Verify a static-bearer local-plugin connection actually works end-to-end (not just that the header is sent) before considering this done; if it hits the same wall, this issue is blocked on hyperguild#9, not miswired.Acceptance
claude mcp list(or equivalent) showscadconnected, not erroring into an OAuth redirect.cad_statustool callable from a koala session.Serve port is up and the proxy works; the wiring is blocked on vault visibility, and not on what this issue predicted.
Done
tailscale serve --bg --https=8445 http://127.0.0.1:31877(run by Mathias on koala):Unauthenticated probe returns 401, so the path is right and auth is enforced — not a 404, not a hang, not an OAuth redirect.
Blocked
Step 3 — "wire the token into wherever koala sources
BRAIN_MCP_TOKEN" — cannot be done from this host.CAD_STATIC_TOKENlives in the AgentSecrets vault, and koala'sopidentity sees only HomeLab:That is infra#224, the known gap where koala's service account cannot see AgentSecrets.
The item name comes from the ExternalSecret (
cad-static-token→remoteRef.key: CAD_STATIC_TOKEN,property: password), read by reference only. No secret value was retrieved, printed or transformed at any point, and the in-cluster secret was deliberately not read — extracting it to route around the vault would defeat the reason it lives there.The risk this issue named did not materialise
Both #32 and #33 warned this might hit the OAuth-discovery bug that parked
brain. Two observations against that:brainis not parked any more — it is live inmcpServersand its tools worked throughout today's session — and cad's 401 is a plain token rejection, not an OAuth challenge. So the fear was reasonable and appears to be stale. It cannot be fully ruled out until a valid token is presented, because a client that ignores a good header would look identical from the outside.Recorded, not enabled
.mcp.jsongains a_parkedblock (7ba01ab) holding the exact entry, with the blocker in the file. A live entry that cannot authenticate would fail on every session start on this host, which is worse than an absent one.To finish, in order:
CAD_MCP_TOKEN=op://<vault>/CAD_STATIC_TOKEN/passwordin~/.op-env._parkedintomcpServers.cad_statuscallable from a koala session.Naming note for step 2, which the issue asked to reconcile: the local convention is
<SERVICE>_MCP_TOKEN, soCAD_MCP_TOKENpointing at theCAD_STATIC_TOKENitem — env var named for the client, item named for the server.Correcting my previous comment: the blocker I named was wrong, and the brain had the answer.
op vault listreturning HomeLab only is not the whole story. koala carries a second, scoped service account at~/.op-agent-write.env(koala-agentsecrets-write). infra#224 was closed on 2026-08-04 by provisioning exactly that, deliberately, rather than wideningkoala-homelab. So citing #224 as an open blocker was wrong twice — it is closed, and the capability exists.With the right token sourced, cad authenticates:
A real MCP
initializeresult fromcad aed2aaf. Nothing about the service, the NodePort, the Serve proxy or the token is broken. The OAuth-discovery risk this issue flagged did not materialise either.What is actually blocking
Delivery into the session environment. By design, no single identity on koala reads both vaults —
koala-homelab(HomeLab only) resolves~/.op-env,koala-agentsecrets-write(AgentSecrets only) lives in a separate file. The session env comes from oneop run --env-file ~/.op-env, so it structurally cannot carry an AgentSecrets reference.And the obvious workaround is a trap, which is why I tested it before proposing it:
op runaborts the entire file. Adding the line to~/.op-envwould leavebrainand every other token unresolved at next session start — it breaks what works today to fix what does not.Filed as mathias/infra#329, recommending a third read-only AgentSecrets token plus two-pass resolution, rather than widening
koala-homelab(which would undo what #224 deliberately chose)..mcp.json's_parkedreason is corrected inc377c23— the entry is right, the token name is right, and the note now says the tokens work and the delivery does not.Step 4 of this issue's acceptance (
cad_statuscallable from a koala session) is one env-var away, not one debugging session away.Narrowing this one: the shared
_parkedreason covered cad and gitea together, and it has now been disproven for gitea only (#33) — gitea-mcp is pass-through-authenticated, so it needed no AgentSecrets token at all.cad is not in that position. It presents
CAD_MCP_TOKEN, a dedicated static token in the AgentSecrets vault, so the identity split from infra#224 is a genuine blocker here and this issue stands as written.Worth checking before doing the identity work, though: if cad-mcp could accept a pass-through credential the session already holds, this issue collapses the same way #33 did. Cheap to test — probe
https://koala.tail30472e.ts.net:8445/mcpwith ainitializecall using each already-present token and see whether any returns 200.