Skip to main content

ADR-0021: Registry & Gateway Architecture (MCP + LLM)

  • Status: Accepted (founder approval 2026-07-06, upsquad-ai/upsquad-core#1682)
  • Date: 2026-07-06
  • Decision owners: Founder (sign-off), Principal Architect (author), Backend SME (Context Engine / gateway), DevOps (GKE LOE), Product Manager (PRD #1674)
  • Related:
    • PRD upsquad-ai/upsquad-core#1674
    • ADR-0020 — dual-runtime worker types (#1627)
    • upsquad-ai/upsquad-core#1647 (+ its W2 dependency for grants reaching agents)
    • upsquad-ai/upsquad-core#1642 / #1643 — Org v2.4
    • LiteLLM dev facade PR #1632

Status

Accepted — founder approval 2026-07-06 (via GitHub comment on #1682).

Context

Founder requirements driving this ADR:

  • MCPs must be registry-mandatory (no ad-hoc upstreams).
  • Each MCP gets a stable per-MCP proxy URL.
  • Team binding with team-owner/Manager approval; cascade via Org v2.4 resolver + the core#1647 snapshot work.
  • User-composable group proxies that aggregate multiple MCPs without tool-name conflicts.
  • Per-tool deterministic guardrails set at team level (e.g. args.amount <= N, response filters).
  • The same architecture pattern applied to LLM models (model registry + gateway), not just MCP tools.

This ADR captures ONE architecture pattern with TWO instances: MCP (tools) registry+gateway and LLM (models) registry+gateway.

Basis: adversarially verified research (deep-research workflow, 9 findings, 0 refuted), code-grounded architect passes over the current ContextForge-based mcp-proxy + Go registry, and DevOps/LOE assessments.

Decisions

1. Registry unification. proxy_upstreams becomes a projection of mcp_servers + mcp_server_units — a single source of truth. The registry gains probe-time tool-schema capture, versioning, and status = pending | approved | disabled. Schema modelled on the official MCP registry (namespaced names, ownership verification, designed for private-subregistry federation — verified 6-0).

2. Proxy technology. KEEP the ContextForge-based mcp-proxy + Go registry (ContextForge's two-tier auth verified 9-0 as the reference multi-tenant pattern). Envoy stays edge-only. NO rebuild. Envoy AI Gateway verified 12-0 as the strongest k8s-native alternative (MCPRoute aggregation, session multiplexing, OAuth termination, native per-tool CEL) — a formal RE-EVALUATION GATE at GKE migration.

3. URL scheme. App-layer path routing: /mcp/{registry-id} and /mcp/group/{id}; the edge keeps ONE coarse route. Each URL serves per-path RFC 9728 protected-resource metadata (spec-mandated, verified 6-0).

4. Auth. Gateway terminates OAuth; token passthrough is NORMATIVELY BANNED (verified 9-0, spec verbatim). Per-upstream tokens via RFC 8693 token exchange; RFC 8707 audience binding mandatory; confused-deputy prevention (per-client consent + client registry) required for dynamic client registration (verified 6-0).

5. Groups. Register-time conflict rejection for authored groups + automatic {server}__{tool} prefixing as safety net (industry consensus verified 15-0). Group session-map = one client session → N upstream sessions. v1: streamable-HTTP upstreams only (SSE federation unsupported industry-wide); reject callback-requiring upstreams.

6. Per-tool guardrails. Policy store in Postgres keyed (team, server, tool); ARGUMENT rules as CEL expressions + RESPONSE filters (DLP/regex/redaction); evaluated in our proxy plugin chain; policies EMIT portable CEL so they can compile onto Envoy AI Gateway post-GKE. Team-level semantics ride the Org v2.4 guardrail axis (unconditional push down home chain).

7. State discipline. Group session-map + snapshot caches in REDIS, never in-process (multi-replica GKE requirement).

8. Approval. MCP↔team attach requires team Manager approval (org_units.manager_member_id, Org v2.4 authority); binding is inert until approved.

9. LLM instance of the pattern. Model catalog + BYOK vault + team_model_allowlists (exists) + internal/aigateway + Anthropic-format facade (replaces dev LiteLLM; ties to PRD #1674); same team binding / approval / guardrail semantics.

10. No service mesh now. Ambient mesh + sidecar + SPIFFE re-evaluated at GKE (verified: zero industry evidence of established practice on mesh L7 MCP awareness / per-agent sidecars / SPIFFE propagation — nothing to adopt yet).

GKE Transition

Sequencing decision = COMPOSE-FIRST. Rework analysis: throwaway is 3-5% (~half a day) — a few Envoy routes / compose defs. GKE-first would block the entire build 3-4 weeks and collide with the live Org v2.4 migrations on the same tables.

GKE migration facts (DevOps LOE): foundation ~80% exists (VPC / WIF / Artifact Registry / tunnel live; CloudSQL stopped with data; some kustomize manifests + 1 ArgoCD app). GkeStack is an EMPTY STUB.

Work items: fill GkeStack (M), missing manifests — ai-gateway / client / spa / pgbouncer / migrate-jobs (M), ArgoCD app-of-apps (M), CloudSQL reactivate (S), Memorystore recreate (S), Secrets → Secret Manager + ESO (M), Gateway API ingress + Cloudflare cutover (M), Managed Prometheus (M), CI rewire (M), cutover + rollback (M).

Total: 6-9 person-weeks, 3-4 weeks calendar, +$450-600/mo.

Autopilot constraints: no privileged daemonsets, no host networking, resource minimums, ollama impractical (prod = BYOK, drop).

What changes at GKE for THIS architecture: host Envoy → Gateway API; Envoy-AI-Gateway re-eval (decision 2 gate); ambient mesh for mTLS/identity; per-tenant worker pods make sidecars meaningful; SPIFFE identity revisit.

What stays identical: all app-layer routing, registries, policy store, session state (already Redis), plugins.

Alternatives Considered

  • Adopt Envoy AI Gateway now — rejected: k8s-CRD-native, no compose deployment.
  • Adopt agentgateway / MetaMCP — rejected: replaces the working governed proxy, loses our audit/idempotency plugins.
  • GKE-first sequencing — rejected: blocks build 3-4 weeks, collides with Org v2.4 migrations.
  • Build-nothing / static config — rejected: registry mandate + team cascade impossible.

Consequences

Positive

  • Single source of truth (registry) removes proxy_upstreams drift; versioned, probe-captured schemas.
  • One pattern reused for MCP and LLM → shared binding/approval/guardrail machinery.
  • Portable CEL policies keep an exit path onto Envoy AI Gateway at GKE.
  • Compose-first keeps the entire build unblocked; ~half a day of throwaway.
  • Redis-first state is GKE-multi-replica-ready from day one.

Negative

  • Continued dependency on the ContextForge upstream project (roadmap / maintenance risk).
  • Group session-map complexity (1→N session fan-out, lifecycle, cleanup).
  • Two proxy technologies coexist (our plugin proxy + edge Envoy) until the GKE re-eval gate.

Risks

  • MCP auth spec churn (RFC 9728 / 8693 / 8707 / confused-deputy guidance still evolving) — may force follow-up work.
  • SSE / callback upstreams unsupported in v1 → some real-world MCPs excluded until federation matures.
  • Envoy AI Gateway re-eval could reverse decision 2, incurring migration cost of the plugin chain.