Files
Gitea-Tools/docs/architecture/adr-0001-mcp-control-plane-boundaries.md
T
sysadmin 6b6a8fb17d docs: ADR-0001 confirm+extend MCP Control Plane boundaries (#71)
Add docs/architecture/adr-0001-mcp-control-plane-boundaries.md. Confirms the
already-documented Control Plane direction and extends it to Jenkins and
GlitchTip: package/server boundaries (common, gitea-mcp, jenkins-mcp,
glitchtip-mcp/observability-mcp/ops-mcp, release-mcp), recommended GlitchTip
placement with alternatives, reaffirmed rules (one server per boundary,
service-local creds, read-only first, namespaced allowed_operations, audited
mutations, orchestrators are not credential sinks), hard phase-1 non-goals,
consequences, and explicit open owner decisions. Does not reopen the settled
direction.

Documentation only; no code behavior changed. No Jenkins/GlitchTip
implementation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:43:13 -04:00

8.2 KiB

ADR-0001: Confirm and extend the MCP Control Plane trust-boundary model for Jenkins and GlitchTip


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