Co-authored-by: jcwalker3 <jcwalker3@yahoo.com> Co-committed-by: jcwalker3 <jcwalker3@yahoo.com>
8.2 KiB
GlitchTip Read-Only Error/Event Tools — Design Notes
- Status: Design (implementation-ready notes; no implementation in this repo)
- Issue: #73 (umbrella: #75; boundary decision: ADR-0001, #71)
- Related: #74 (GlitchTip→Gitea filing workflow — composes these read tools), #78 (dedup/linking, child of #74), #76 (per-service profile schema)
- Date: 2026-07-02
1. Purpose and scope
Define the minimum read-only GlitchTip MCP tool set that lets an LLM answer: "What unresolved errors does project X have (by environment/release), and what is this specific error?" — with privacy-safe output suitable for LLM context, issue bodies, and audit logs.
Strictly read-only, per ADR-0001:
- No mutation tools — no resolving/ignoring/assigning issues, no comment posting, no project/team/key administration, no deletes.
- No automatic GlitchTip→Gitea filing (that is #74's orchestrated, explicitly-invoked workflow; it composes these read tools and Gitea write tools — never one dual-credential server).
- This server never holds Gitea write credentials.
2. Boundary placement (namespace pending)
These tools belong to the GlitchTip observability boundary of the MCP Control
Plane — glitchtip-mcp (ADR-0001's recommendation), observability-mcp, or
folded into ops-mcp. ADR-0001 open owner decision #2 picks the name; this
design does not assume it. Tool names below use the glitchtip_ prefix for
readability and rename mechanically with the decision.
Fixed regardless of the name (per tool-boundaries.md,
credential-isolation.md):
- Own server process, own
.env, GlitchTip credentials only. - No Gitea, Jenkins, or Ops tokens in this runtime; no GlitchTip token anywhere else.
3. API surface note (Sentry compatibility)
GlitchTip implements a Sentry-compatible REST API (/api/0/... — organizations,
projects, issues, events). The design targets GlitchTip's documented subset
only; Sentry-only endpoints must not be assumed. The implementation should pin
against a tested GlitchTip version and treat missing endpoints/fields as
degraded-but-safe (omit field, never crash).
4. Minimum read-only tool set
| Tool | Purpose |
|---|---|
glitchtip_whoami |
Verify authenticated identity + active profile (mirror of gitea_whoami; fail-closed identity proof) |
glitchtip_list_projects |
Projects visible to the token (org-scoped), with pagination bounds |
glitchtip_list_unresolved |
Unresolved issues for a project, filterable (§6), sorted by last-seen |
glitchtip_get_issue |
Safe detail of one issue (fields §5) |
glitchtip_recent_events |
Recent events for an issue (summaries only, §5) |
glitchtip_search |
Issue search within a project (query + filters §6) |
All tools are GET-only. No tool issues PUT/POST/DELETE.
5. Privacy: field-level allowlist (the core rule)
Error events routinely contain PII and secrets (request bodies, cookies, headers, tokens, user emails/IPs, local variables). Therefore: allowlist projection only — raw event/issue payloads are never passed through.
Issue-level safe fields (glitchtip_list_unresolved, glitchtip_get_issue, glitchtip_search)
| Field | Notes |
|---|---|
issue_id |
GlitchTip issue ID (dedup key for #78) |
fingerprint |
When available (dedup key for #78) |
title / culprit |
Error type + short message/transaction — redactor-passed |
project |
Slug |
level |
error/warning/… |
status |
unresolved/… |
environment |
When filtered/available |
release |
Version string |
first_seen / last_seen |
ISO-8601 UTC |
event_count / user_count |
Numbers only — never user identities |
permalink |
GlitchTip web URL (the "link, not dump" principle) |
Event-level safe fields (glitchtip_recent_events)
event_id, timestamp, level, environment, release, redactor-passed
message, and a stack summary only: top N (default 5) frames as
module/filename:function:line — in-app frames preferred.
Redact / omit — never returned
Request headers; cookies; auth/session fields; user emails, usernames, IPs;
request/form bodies; query strings; local variables; full raw stack frames
(source context lines); SDK/device metadata beyond platform name; breadcrumbs;
any extra/context blobs.
Full raw frames or request context require a separate, explicitly approved
operation (glitchtip.event.read_raw) that is absent from default profiles —
same pattern as jenkins.console.read in the #72 design. Even then, output
passes the shared secret redactor; redaction failure ⇒ error, never raw text.
Default output = fingerprint / release / summary + permalink. The permalink carries the human to the full data in GlitchTip's own UI, where its access control applies — the MCP layer does not re-serve raw payloads.
6. Filtering and pagination
Filters (all optional, combinable): project (required for issue/event
queries), environment, release, fingerprint, free-text query
(GlitchTip search syntax, e.g. is:unresolved).
Pagination: cursor-based per the API. Bounds: per-page cap 50; default overall
cap 100 items; hard cap max_pages (default 10) against runaway loops —
mirroring gitea_auth.api_get_all. Truncation is explicit in the return
("truncated": true) — never silent.
7. Credentials and profile requirements
Per-service profile model (gitea-execution-profiles.md, extended by #76):
- Env/config:
GLITCHTIP_URL,GLITCHTIP_ORG,GLITCHTIP_TOKEN_SOURCE_NAME(secret name only; value resolved at runtime, never logged/committed). - Profile: e.g.
glitchtip-readonlywith namespacedallowed_operations: ["glitchtip.read", "glitchtip.event.read"](+glitchtip.event.read_rawonly with explicit approval);forbidden_operations: ["glitchtip.issue.mutate", "glitchtip.admin"]belt-and-braces though no mutating tool exists. - Missing URL/org/token/profile ⇒ fail closed before any network call.
- Read-only ⇒ no confirmation gates; identity (
glitchtip_whoami) must work so workflows can prove which account they read as.
8. Failure behavior (fail closed, clear, safe)
| Condition | Behavior |
|---|---|
| Unknown project/issue | Explicit {"found": false, ...} — no fuzzy matching |
| GlitchTip unreachable (DNS/timeout) | "network error contacting GlitchTip: <redacted reason>" — mirror gitea_auth.api_request conversion |
| 502/503/504 | "GlitchTip upstream unavailable" |
| 401/403 | "GlitchTip auth failed / insufficient permissions" — no credential echo |
| 429 | Honor Retry-After with capped jittered backoff (as gitea_auth) |
| Malformed JSON | "malformed JSON response from GlitchTip" — no raw-body dump |
| Missing profile/creds | Fail closed before any network call (§7) |
All error text passes the shared secret redactor.
9. Testing strategy (mocked; for the implementing package)
Mocked-GlitchTip unit tests only, per docs/developer-testing-guidelines.md:
- Assert method is always
GET; URL/filter/cursor shape correct. - Projection tests: response fixtures containing emails, IPs, cookies, headers, request bodies, locals, full frames ⇒ none appear in output (explicit negative assertions per §5's redact list).
- Stack summary: top-N frame cap enforced; source-context lines absent.
- Pagination: per-page/overall/max-pages caps; explicit
truncatedflag. - Filters: environment/release/fingerprint/query passed through correctly.
- Failure matrix of §8 incl. no-token-in-error assertions.
- Profile gate: missing/insufficient profile ⇒ no network call
(
mock_api.assert_not_called()pattern). read_rawop absent ⇒ raw-frame request refused without an API call.
10. Implementation-readiness checklist
Ready to implement once:
- ADR-0001 owner decision #2 (namespace/placement) is made — mechanical
rename of the
glitchtip_prefix if needed. - ADR-0001 owner decision #1 (repo home) is made.
- #76 profile schema exists (or a minimal
glitchtip-readonlyprofile is hand-rolled to the same rules). - A pinned GlitchTip version is chosen for API-subset testing (§3).
Explicitly not unlocked by this document: any GlitchTip mutation, any automatic Gitea filing (#74 designs that as a gated, explicitly-invoked orchestrated workflow), any Gitea credentials in this boundary.