Skip to content

MCP Gateway

The MCP-Client Gateway is SARC’s outbound MCP path: the portal can take human-approved, audited write actions against external systems (Phase 1: GitHub) via that provider’s MCP server. Read-only AI access lives in the MCP server.

Source-of-truth runbook: docs/ci/mcp-gateway.md in the repo. This page is a public-facing summary.

portal pod ──HTTP (per-request Bearer PAT)──▶ github-mcp-server sidecar ──▶ GitHub API
│ (in-cluster Deployment)
└─ src/lib/mcp/{transport,registry,guardrails,gateway}.ts
└─ /api/mcp/{propose,execute} ◀── McpProposePanel UI (/admin/mcp)

The prod portal image is Next.js standalone (non-root, no npx), so MCP servers run as separate in-cluster workloads reached over HTTP — never spawned from the portal pod. No PAT is baked into the sidecar; the per-tenant token arrives per-request in the Authorization header.

  1. POST /api/mcp/propose?tenant=<slug> with { provider, tool, args }. Side-effect-free. Returns { provider, tool, argsSha, marker, preview }. Available to any non-AUDITOR member.
  2. Operator reviews the preview (the exact args + the artifact body that would be created, carrying an idempotency marker <!-- sarc-mcp:<sha> -->).
  3. POST /api/mcp/execute?tenant=<slug> with { provider, tool, args, argsSha }. ADMIN only. The server recomputes argsSha(args) and rejects with 409 if it differs from the approved sha. Guardrails re-checked, then the write executes via the sidecar; the result (e.g. the new issue URL) is returned.
  • classify(provider, tool) returns safe | compliance-critical. Code/PR writes, deploy/release triggers, and CR mutations are compliance-critical and always blocked from the in-portal execute path.
  • assertWriteAllowed (fail-closed) throws 403 for compliance-critical tools AND for any tool not on the Phase-1 write allow-list. Unknown/renamed tools are rejected, never allowed by default.

Phase-1 write allow-list (in karc-portal/src/lib/mcp/registry.ts):

  • github:issue_write (with method: "create" | "update")
  • github:add_issue_comment

Compliance-critical tools (blocked):

  • create_pull_request, merge_pull_request, update_pull_request
  • create_or_update_file, push_files, delete_file
  • create_branch, create_release, run_workflow, create_deployment
  • create_change_request, update_change_request

These are the writes that, if available behind portal-side approval, would bypass the CI-attested compliance pipeline. They stay on the CI-attested path.

  • ADMIN approves and executes. AUDITOR and non-ADMIN members see the preview read-only (no Approve button).
  • Each execute writes exactly one hash-chained AuditLog row (action = mcp.tool.<provider>.<tool>), with argsSha + an ok flag. Raw args are never stored — only the hash.

Enablement checklist (per cloud / per tenant)

Section titled “Enablement checklist (per cloud / per tenant)”
  1. Set mcp.github.enabled=true in the karc-portal Helm values. Image pinned to ghcr.io/github/github-mcp-server:v1.0.4.
  2. Set envVars.MCP_GITHUB_SERVER_URL=http://<release>-github-mcp:8080/ (trailing / — v1.0.x mounts MCP at root, no --endpoint-path flag).
  3. Enable the mcp.gateway feature flag in the AI kill-switch matrix AND the per-tenant agentDispatchEnabled switch. Both required.
  4. Tenant’s GitHub PAT (githubToken) must be set with issues scope.
  5. Rollout the portal Deployment so the ConfigMap envVar change takes effect (the chart has no checksum annotation): kubectl rollout restart deploy/karc-portal -n karc-<env>.

Operator UI to drive the demo: /t/<tenant>/admin/mcp. ADMIN-only. The page surfaces a 3-row prereqs strip (mcp.gateway / agentDispatchEnabled / GitHub PAT) so a missing prereq is visible before the form is filled.

  • Phase 2 — recipe wiring (problem-investigate-fix proposes issue + work-item + problem); ADO + GitLab sidecars; comment/label/cross-link tools.
  • Phase 3 — CR writes, deploy triggers, code changes — each gated behind portal-side parity with CI Kosli attestation + change-window enforcement.