# ADR-0001: Confirm and extend the MCP Control Plane trust-boundary model for Jenkins and GlitchTip - **Status:** Proposed - **Date:** 2026-07-02 - **Issue:** #71 - **Supersedes / relates to:** confirms and extends [`docs/tool-boundaries.md`](../tool-boundaries.md), [`docs/safety-model.md`](../safety-model.md), [`docs/credential-isolation.md`](../credential-isolation.md), [`docs/release-workflows.md`](../release-workflows.md), [`docs/gitea-execution-profiles.md`](../gitea-execution-profiles.md). Umbrella tracking: #75. Applied to docs by: #79. --- ## 1. Context The MCP Control Plane direction is **already decided** in the existing architecture docs. This ADR does **not** reopen that decision. It exists to: 1. **Confirm** the established model in one authoritative place, and 2. **Extend** it to the two concrete services now under consideration — **Jenkins** (CI/CD visibility) and **GlitchTip** (error/observability). What the existing docs already establish (and this ADR reaffirms): - The project is named **MCP Control Plane** and is intended to group the packages `common`, `gitea-mcp`, `jenkins-mcp`, `ops-mcp`, and `release-mcp` (`tool-boundaries.md`). - **One MCP server per trust boundary**; there is no single "everything" server (`tool-boundaries.md`). - **Separate credentials per service**, each server instantiated with its own dedicated `.env`; strict isolation — e.g. `gitea-mcp` has no Jenkins or Ops tokens (`credential-isolation.md`). - **All mutating actions are audited and require confirmation**; production actions need a hard gate; **secrets are redacted** from logs, tool output, and storage (`safety-model.md`). - The execution-profile model — `allowed_operations` / `forbidden_operations` (forbidden wins), deny-by-default, fail-closed, verified identity via `gitea_whoami`, self-review/self-merge prevention, token-by-reference only (`gitea-execution-profiles.md`). That doc **already names GlitchTip** as a boundary `gitea-mcp` must **not** absorb. - A future **`release-mcp` orchestrator** may coordinate across packages but must be **"coordination, not consolidation"** — it must not hold every service's credentials (`release-workflows.md`). `gitea-execution-profiles.md` is explicit: `gitea-mcp` "must **not** add or absorb Jenkins, Ops, GlitchTip, Release, deploy, rollback, migration, restart, or production behavior." This ADR builds directly on that rule. ## 2. Decision ### 2.1 Repository shape This repository (`Gitea-Tools`) is, in practice, the **`gitea-mcp` package** of the Control Plane. Jenkins and GlitchTip work **must not** be added to it. Recommended direction: extract the Control Plane into a dedicated **`mcp-control-plane` monorepo** (as the existing docs already name) with one package per boundary, and treat this repo either as the seed of that monorepo's `gitea-mcp` package or as a package that is moved into it. The final choice (monorepo now vs. later; move vs. seed) is an **open owner decision** (§5). Until that is settled, the operative rule stands: **no Jenkins/GlitchTip code lands in this repo.** ### 2.2 Package / server boundaries | Package | Trust boundary | Phase-1 posture | |---|---|---| | `common` | Shared, credential-free library (profile schema, audit/redaction helpers, API/pagination/failure client, `allowed_operations` model). **Holds no credentials.** | Extract shared pieces only as approved (§5) | | `gitea-mcp` | Source-control & work items (issues, PRs, comments). Gitea creds only. | Exists (this repo) | | `jenkins-mcp` | CI/CD visibility. Jenkins creds only. | **Read-only** build status/visibility | | GlitchTip boundary — `glitchtip-mcp` (recommended), or `observability-mcp`, or fold into `ops-mcp` | Error/event observability. GlitchTip creds only. | **Read-only** error/event listing | | `ops-mcp` | Live host/health/status/log checks. Ops creds only. | Read-only (per existing docs) | | `release-mcp` / orchestrator | Coordinates across boundaries; composes other servers' tools. **Not a credential sink.** | Design-only in phase 1 | **Recommended GlitchTip placement:** a dedicated **`glitchtip-mcp`** server. Rationale — GlitchTip has its own API surface and its own credential, and error tracking is a distinct trust boundary from live host checks; a dedicated server is the cleanest fit for "one server per trust boundary." - **Alternative A — `observability-mcp`:** a broader observability boundary that could later also cover metrics/log/error sources beyond GlitchTip. Choose this if you expect several observability backends and want one boundary for them. - **Alternative B — fold into `ops-mcp`:** minimizes package count, but mixes app-error observability with host/health checks; acceptable only if kept strictly read-only and the credentials are still GlitchTip-specific. Least recommended because it blurs two boundaries. The final name/placement is an **open owner decision** (§5). Downstream issues (#73 GlitchTip read tools, #79 doc updates, #80 labels) must use whatever name is chosen here. ### 2.3 Rules (reaffirmed, now spanning all boundaries) - **One MCP server per trust boundary.** No single "everything" MCP server. - **Separate credentials per service; tokens remain service-local.** Each server has its own `.env`; e.g. a GlitchTip server never holds Gitea write tokens. - **Read-only first.** New service surfaces (Jenkins, GlitchTip) begin read-only. - **Mutations require explicit `allowed_operations`**, namespaced per service (e.g. `gitea.issue.create`, `jenkins.build.read`, `glitchtip.event.read`); `forbidden_operations` always overrides; deny-by-default; fail-closed. - **Mutating actions require audit logging** with verified identity and outcome, and secret redaction (per `safety-model.md`). - **Orchestrators coordinate; they must not become credential sinks.** Cross-service workflows compose per-service tools; no orchestrator centralizes all tokens. ## 3. Phase-1 non-goals (hard) - **No Jenkins build triggers.** - **No deploy triggers.** - **No parameterized job launches.** - **No automatic GlitchTip-to-Gitea issue filing.** - **No GlitchTip MCP server holding Gitea write credentials.** - **No Jenkins or GlitchTip code inside `mcp_server.py`** (the `gitea-mcp` entrypoint). ## 4. Consequences - Jenkins/GlitchTip work proceeds as **design/read-only** first, in their own packages/servers, gated behind this ADR's decisions. - The `gitea-mcp` monolith (`mcp_server.py`) does not grow to host other services; that pressure is redirected to separate packages and the `common` extraction (relates to the #65 refactor, which remains independent). - Cross-service "file a Gitea issue from a GlitchTip error" becomes an **orchestrator/runbook** concern (composing GlitchTip-read + Gitea-write tools), never a single dual-credential server (see #74/#78). - Naming/label decisions (#80) and doc updates (#79) inherit the choices here. ## 5. Open owner decisions These are intentionally **not** decided by this ADR and must be resolved by the repo owner before the corresponding implementation issues proceed: 1. **Monorepo vs. this repo.** Does a separate `mcp-control-plane` repo get created now (with `gitea-mcp` moved into it), or does this repo become the monorepo, or does it stay Gitea-only for now while others live elsewhere? 2. **GlitchTip placement.** `glitchtip-mcp` (recommended), `observability-mcp`, or folded into `ops-mcp`? 3. **Cross-service filing mechanism.** Should GlitchTip-to-Gitea filing be an **LLM runbook only**, or a carefully constrained **orchestrator workflow** (`release-mcp`) with dry-run + explicit invocation + Gitea profile gating? 4. **`common` package scope.** Which shared pieces are approved for extraction into `common` now — profile schema, audit/redaction, API client (pagination/failure handling), `allowed_operations` model — versus deferred? ## 6. References - [`docs/tool-boundaries.md`](../tool-boundaries.md) - [`docs/safety-model.md`](../safety-model.md) - [`docs/credential-isolation.md`](../credential-isolation.md) - [`docs/release-workflows.md`](../release-workflows.md) - [`docs/gitea-execution-profiles.md`](../gitea-execution-profiles.md) - Tracking/umbrella: #75 · Doc application: #79 · Jenkins design: #72/#77 · GlitchTip design: #73 · Cross-service filing: #74/#78 · Labels: #80