Add docs/architecture/jenkins-readonly-build-status-design.md: implementation-ready design notes for the jenkins-mcp read-only tool set — minimum tools (whoami, list_jobs, latest_build, build_status, get_build, gated console_tail), safe return-field allowlist (url, number, timestamp, duration, branch, result, commit), fail-closed failure behavior (unknown job, unreachable, 5xx, auth, malformed JSON), bounded+redacted console tail behind a distinct jenkins.console.read operation, per-service credential/ profile requirements (token by reference, fail closed), explicit exclusions (build/deploy triggers, parameterized launches), job addressing with mapping deferred to #77, and a mocked-Jenkins testing strategy. Design only; no implementation, no code behavior changed, no Jenkins code in mcp_server.py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7.5 KiB
Jenkins Read-Only Build Status Tools — Design Notes
- Status: Design (implementation-ready notes; no implementation in this repo)
- Issue: #72 (parent umbrella: #75; boundary decision: ADR-0001, #71)
- Related: #77 (repo/branch/PR → job mapping, designed separately)
- Date: 2026-07-02
1. Purpose and scope
Define the minimum read-only Jenkins MCP tool set that lets an LLM answer: "Did the latest build for this project/branch succeed or fail?" — plus enough detail (build URL, number, timing, result) to report or investigate.
Phase 1 is strictly read-only, per ADR-0001
(adr-0001-mcp-control-plane-boundaries.md):
- Excluded: build triggers.
- Excluded: deploy triggers.
- Excluded: parameterized job launches.
- Excluded: job creation/deletion/config changes, queue manipulation, node management — any Jenkins mutation whatsoever.
2. Boundary placement
These tools belong to the jenkins-mcp package/server of the MCP Control
Plane — never inside gitea-mcp (mcp_server.py in this repo).
Consequences (from tool-boundaries.md, credential-isolation.md, ADR-0001):
jenkins-mcpruns as its own server process with its own.env.- Jenkins credentials never enter the Gitea MCP runtime, and Gitea
credentials never enter
jenkins-mcp. - This document lands in this repo only because the repo currently hosts the Control Plane's architecture docs; the code ships elsewhere (owner decision #1 of ADR-0001).
3. Minimum read-only tool set
| Tool | Purpose |
|---|---|
jenkins_whoami |
Verify authenticated Jenkins identity + active profile (mirror of gitea_whoami; fail-closed identity proof before anything else) |
jenkins_list_jobs |
List visible jobs (supports folder paths), with pagination bounds |
jenkins_latest_build |
The primary question: latest build of a job (or job+branch for multibranch) → status summary |
jenkins_build_status |
Status of a specific build number (job, number) |
jenkins_get_build |
Full safe detail of a build (fields in §4) |
jenkins_console_tail |
Bounded, redacted tail of a build's console log (§6) — optional, approval-gated addition |
All tools are GET-only against the Jenkins JSON API (/api/json,
.../lastBuild/api/json, .../consoleText). No tool issues POST/PUT/DELETE.
4. Return payloads (safe fields)
jenkins_latest_build / jenkins_build_status / jenkins_get_build return:
| Field | Source | Notes |
|---|---|---|
job |
request | Fully-qualified job path (folders joined with /) |
build_number |
number |
int |
result |
result |
SUCCESS / FAILURE / UNSTABLE / ABORTED / NOT_BUILT; null → IN_PROGRESS when building=true |
building |
building |
bool |
url |
url |
Build URL |
branch |
multibranch job name / SCM action | Best-effort; omitted when unknown |
timestamp |
timestamp |
ISO-8601 UTC (converted from epoch ms) |
duration_seconds |
duration |
0/omitted while building |
commit_sha |
SCM build action | Best-effort; omitted when unknown |
Rules: no raw Jenkins payload passthrough (allowlist projection only); no
Authorization header, token, or crumb material in any output or error
(reuse the shared redaction approach of safety-model.md §3 / gitea_audit).
5. Failure behavior (fail closed, clear, safe)
| Condition | Behavior |
|---|---|
| Unknown job | Explicit {"found": false, "job": "<path>", "error": "job not found"} — never guess or fuzzy-match a job name (hard rule; see also #77) |
| Jenkins unreachable (DNS/timeout/conn refused) | Clear "network error contacting Jenkins: <redacted reason>"; no retry storm — mirror gitea_auth.api_request timeout + failure conversion |
| 502/503/504 | Explicit "Jenkins upstream unavailable" |
| 401/403 | "Jenkins auth failed / insufficient permissions" — without echoing credentials or the request's auth material |
| Malformed JSON | "malformed JSON response from Jenkins" (no raw-body dump) |
| Missing profile/creds | Fail closed before any network call (§7) |
6. Console tail safety (jenkins_console_tail)
Console logs are the highest-risk surface (secrets, tokens, internal hosts routinely leak into build logs). If included at all (owner may defer it):
- Bounded: hard server-side cap (default: last 200 lines AND ≤ 64 KiB, whichever is smaller; caller may request less, never more).
- Redacted: pass through the shared secret redactor (token/
Basic/Bearer/ password/key-value patterns) before returning; redaction failure ⇒ return an error, never the raw text. - Default off: summary fields (
result, failing stage if cheaply available) are preferred; the tail requires an explicitallowed_operationsentry (jenkins.console.read) distinct from plainjenkins.build.read.
7. Credentials and profile requirements
Follows the per-service profile model (gitea-execution-profiles.md, extended
by #76):
- Env/config:
JENKINS_URL,JENKINS_USER,JENKINS_TOKEN_SOURCE_NAME(name-of-secret only — value resolved at runtime, never logged/committed). - Profile: e.g.
jenkins-readonlywith namespacedallowed_operations: ["jenkins.read", "jenkins.build.read"](+jenkins.console.readonly if the tail tool is approved);forbidden_operations: ["jenkins.build.trigger", "jenkins.deploy", "jenkins.job.configure"]as belt-and-braces even though no mutating tool exists. - Missing URL/user/token/profile ⇒ fail closed with a clear message.
- Since every tool is read-only, no confirmation gates are needed — but
identity (
jenkins_whoami) must still work so workflows can prove which Jenkins account they act as.
8. Job addressing and mapping
Tools accept an explicit fully-qualified job path (folder-aware:
folder/subfolder/job). How a repo/branch/PR resolves to that job path is
out of scope here and designed in #77, with these fixed constraints:
- No silent guessing of job names — unmapped input returns an explicit "no mapping" result.
- Multibranch pipelines address a branch job as
<job>/<branch>with proper URL-encoding of branch names (e.g.feature%2Fx).
9. Testing strategy (for the implementing package)
Mocked-Jenkins unit tests only (no live Jenkins in unit CI), mirroring this
repo's conventions (docs/developer-testing-guidelines.md):
- Patch the HTTP client; assert method is always
GETand URL shape is correct (folders, multibranch encoding). - Success projections: field allowlist exactly as §4; unknown fields dropped.
result=null + building=true⇒IN_PROGRESS.- Unknown job ⇒ found:false, no fuzzy match, no API retry.
- Timeout/DNS/5xx/malformed-JSON ⇒ safe errors, no secret/credential leakage (explicit no-token-in-error assertions).
- Console tail: cap enforcement (lines and bytes), redaction applied, redaction
failure ⇒ error not raw text, gated behind
jenkins.console.read. - Profile gate: missing/insufficient profile ⇒ no network call
(
mock_api.assert_not_called()pattern).
10. Implementation-readiness checklist
Ready to implement in jenkins-mcp once:
- ADR-0001 owner decision #1 (where
jenkins-mcplives) is made. - #76 profile schema exists (or a minimal
jenkins-readonlyprofile is hand-rolled to the same rules). - #77 mapping design is accepted (or tools ship path-addressed only, mapping deferred).
Explicitly not unlocked by this document: build triggers, deploys,
parameterized launches, any Jenkins code in mcp_server.py.