Uh oh!
There was an error while loading. Please reload this page.
feat(mcp): add ToolHive operator and mcp-gateway workloads - #62
Merged
Conversation
Install the ToolHive operator (0.44.0) via ArgoCD OCI-chart Applications and add workloads/mcp-gateway: a VirtualMCPServer aggregating a read-only in-cluster kubernetes-mcp-server plus MCPRemoteProxy backends for context7 and github (token injected server-side from a KSOPS secret). Point the opencode web deployment at the aggregated vmcp-gateway endpoint. External access is gated by Cloudflare Access (tfroot-cloudflare); the TunnelBinding lands in a follow-up once the CNAME exists.
xnoto
commented
Aug 26, 2026
ContributorAuthor
Paired tfroot-cloudflare PR: makeitworkcloud/tfroot-cloudflare#26 (must merge + apply first — see "Required sequence" above). |
xnoto added a commit
to makeitworkcloud/tfroot-cloudflare
that referenced
this pull request
Aug 26, 2026
## Summary Edge authentication for the new cluster MCP gateway (paired with makeitworkcloud/kustomize-cluster#62). - **`cf-tunnels.tf`** — adds `mcp` to the cluster-apps CNAME list. **This must be applied before the TunnelBinding lands in kustomize-cluster** (documented DNS race, error `81053`); the TunnelBinding PR follows this apply. - **`cf-access-mcp.tf`** — dedicated `mcp-gateway` Access service token (`duration = "forever"`, rotate via `client_secret_version`) + `self_hosted` application on `mcp.makeitwork.cloud`: `non_identity` service-token policy for headless agent clients (opencode, Claude Code, etc. send `CF-Access-Client-*` headers) and an admins GitHub-SSO policy for interactive debug. - **`outputs.tf`** — exposes the service-token `client_id` and `client_secret` (sensitive) so agent clients can be configured after apply. **Scope change during review:** the `cf-access-opencode.tf` gate was dropped — #25 deliberately removed the opencode Access gate because it breaks `opencode attach`; opencode web stays on the SOPS-managed server password. Re-gating needs an attach-compatible design first. ## Validation - `tofu fmt` ✅, `tofu init -backend=false` + `tofu validate` ✅ - `make test` ✅ (canonical pre-commit: validate, tflint, checkov, fmt, terraform-docs README regenerated) ## Not run - `tofu plan` / `tofu apply` — CI posts the plan here and applies on merge per the shared workflow. ## Post-apply 1. `tofu output mcp_gateway_service_token_client_id` / `tofu output -raw mcp_gateway_service_token_client_secret` → local agent sessions as `CF_ACCESS_CLIENT_ID` / `CF_ACCESS_CLIENT_SECRET` (keyring/env only). 2. Then the follow-up TunnelBinding PR in kustomize-cluster is safe to merge.
Uh oh!
There was an error while loading. Please reload this page.
xnoto added a commit
that referenced
this pull request
Aug 26, 2026
Follow-up to #62 as planned: TunnelBinding `mcp.makeitwork.cloud` → `http://vmcp-gateway.mcp.svc:4483`. Sequencing verified before opening: - `mcp` CNAME applied via tfroot-cloudflare#26 (no `81053` race) - Access app live: unauthenticated `GET https://mcp.makeitwork.cloud/mcp` → 302 to Access login - vMCP healthy: `tools/list` via port-forward returns 16 aggregated tools (context7×2, kubernetes×14) Post-merge validation: external `tools/list` with the service token; 302/403 without it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Kubernetes MCP gateway (Stacklok ToolHive) to the cluster and wires the opencode web service to it, giving every agentic session one universal, aggregated MCP backend.
operators/toolhive/— ToolHive operator0.44.0via two ArgoCD OCI-chart Applications (toolhive-operator-crdswave 0,toolhive-operatorwave 1). Chart resource defaults are emptied per the single-node policy; update check / usage metrics disabled.workloads/mcp-gateway/(newmcpnamespace):MCPGroup/gateway+VirtualMCPServer/gateway→ aggregated endpointhttp://vmcp-gateway.mcp.svc:4483/mcp(service name/port verified against the 0.44.0 operator source)MCPServer/kubernetes—containers/kubernetes-mcp-server:v0.0.66(digest-pinned) with--read-onlyand a dedicated ClusterRole that excludes Secrets (KSOPS-decrypted secrets must not become readable through the gateway)MCPRemoteProxy/context7— public, unauthenticatedMCPRemoteProxy/github—api.githubcopilot.comwithMCPExternalAuthConfigheaderInjection; the PAT is injected server-side from the KSOPS secretmcp-github(clients never hold it)VirtualMCPServerincomingAuth: anonymousis deliberate: ClusterIP-only, flannel doesn't enforce NetworkPolicy, and edge auth is Cloudflare Access (see paired tfroot-cloudflare PR)opencode — ConfigMap gains an
mcpblock pointing atvmcp-gateway. Remote-only by design: the opencode image (Alpine + static Bun binary, no python/uv/node) cannot run stdio MCPs, and its pod hardening forbids runtime installs.wait-for-crds— added the five ToolHive CRDs to the PreSync gate.Authentication model
mcp.makeitwork.cloud— service-token (non_identity) for agent clients + admins GitHub SSO for debug. Unauthenticated traffic dies at the edge.--read-only.Required sequence — read before merging
mcpCNAME and the Access applications). Do not merge this PR's TunnelBinding before that apply — the TunnelBinding is deliberately excluded from this PR to avoid the documented DNS race (81053); it lands as a small follow-up PR after the CNAME exists.sops workloads/mcp-gateway/github-secret.yaml(value must beBearer <pat>), commit, push. Until then only the github proxy is degraded; context7 + kubernetes work.workloads/mcp-gateway/tunnel-binding.yaml→mcp.makeitwork.cloud→http://vmcp-gateway.mcp.svc:4483.kubectl --context k3s get mcpservers,virtualmcpservers,mcpremoteproxies -n mcp, thenopencode mcp debug mcp-gatewayfrom a session.Local client config (after steps 1–4)
Validation
kustomize build operators/toolhive✅ (2 Applications),kustomize build workloads/apps✅ (10 objects)workloads/mcp-gatewaylocal build blocked by KSOPS exec plugin — pre-existing repo limitation, identical onmain(verified via stash); structure linted insteadpre-commit runon all changed files ✅ (check-yaml, KubeLinter, detect-private-key, secrets)Not done (explicit)
tofuplan/apply — paired tfroot PR, applies by repo owner