ci-triage-mcp
Provides tools for triaging GitHub Actions CI failures, including fetching pipeline runs, extracting failure signals from logs and test artifacts, and cross-referencing local history of past failures.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ci-triage-mcpWhy did the last run of playwright-typescript-framework fail on main?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ci-triage-mcp
Ask Claude why your last CI run failed. Get a real answer built from parsed logs, not a guess from raw text.
Pipeline · Guardrail · Setup · Tools · Extractors · Dashboard
This is an MCP server for Claude Desktop and Claude Code. You ask, in conversation, why a GitHub Actions run failed; Claude fetches the run, and this server deterministically extracts the actual failure signal -- test name, class, assertion message, stack trace -- from JUnit/Surefire XML, ESLint, tsc, Prettier, or Maven console output. Claude never reads a raw log to guess what went wrong; it reasons over structured data a real parser produced.
No API key, no server to deploy, nothing running unattended. The "LLM" is whichever Claude client is already open when you ask -- same design as k6-loadtest-mcp.
Why this exists instead of just pasting a log into Claude
The LLM plans and explains. Code fetches and parses. The two never trade places.
Pasting a 2,000-line CI log into a chat works, but it wastes context on install/browser-download noise and leaves the model guessing at which lines actually matter. This server does the mechanical part in real parsers -- JUnit/Surefire XML via a proper XML parser, not regex on a raw log wherever structured output exists -- so what Claude sees is already reduced to the handful of lines that are the failure. It also remembers: a local history store means "this test has failed the same way 3 times this month" is something the tool tells you, not something you have to recall.
You: Why did the last run of playwright-typescript-framework fail on main?
Claude: Fetched run 30298934612, extracted 14 failure signals across the run's failed
shards, and cross-referenced them against local history...
This run mixes one real bug with a batch of environment flakiness:
🔴 Real bug -- axe-core flags a WCAG 2 AA color-contrast violation on the
products, cart, and checkout pages (3 signals, one shared breadcrumb
component: #6d68cf on #0a0a11, a 4.25:1 ratio against the 4.5:1 minimum).
🟡 Not a bug -- 11 more signals (API timeouts, cancelled page loads) across
unrelated specs all point at one shard losing connectivity to
playground.krishanchawla.com mid-run, not broken tests.
Fix the breadcrumb's text-accent token once; rerun the flaky shard once the
target's back up.Condensed, but the real shape of it -- this is an actual run this project's own live-testing was validated against (see Extractors), not a hypothetical.
Related MCP server: claude-rag-mcp
Pipeline
flowchart TD
A["you: 'why did the last run of\nplaywright-typescript-framework fail?'"] --> B[fetch_pipeline_run]
B --> C{artifact named\njunit/surefire?}
C -->|yes| D[download + unzip artifact\nparse JUnit/Surefire XML]
C -->|no, or expired| E[get_job_log\nparse ESLint / tsc / Prettier / Maven console]
D --> F[extract_failure_signal\nstructured FailureSignal + signature]
E --> F
F --> G[find_similar_past_failures\nlocal history lookup]
G --> H[Claude writes the explanation\nfrom structured data]
H -. optional .-> I[record_triage_note\nlocal only, no confirmation needed]
H -. optional, ask first .-> J[publish_triage\n→ shared dashboard]
G1["Guardrail: allowedRepos,\nnot agent-editable"]
B -. enforced before every fetch .-> G1
style G1 fill:#6552D0,color:#fff,stroke:#333
style J stroke-dasharray: 4 3triage_pipeline_failure chains fetch → download/parse every relevant artifact and failed job's
log → history lookup, in one call, and falls back to job-log parsing per artifact rather than
aborting the whole run if one has expired. The granular tools exist for targeting one specific job.
Guardrail
Actions data (runs, job logs, artifacts) is only ever fetched for repos listed in allowedRepos
in ~/.ci-triage-mcp/config.json (empty by default). The tools cannot add to this list
themselves -- the same shape as k6-loadtest-mcp's host allowlist: an agent-authored call,
legitimate or prompt-injected, doesn't get to expand its own blast radius. Add a repo yourself
once you've confirmed you're authorized to read its Actions data:
{ "allowedRepos": ["krishanchawla/playwright-typescript-framework", "krishanchawla/selenium-java-framework"] }Setup
Prerequisites: Node.js 18+, and a GitHub token available -- either the GITHUB_TOKEN env var, or
the gh CLI already logged in (gh auth login); this server falls back
to gh auth token automatically. This is your own local credential, used to call GitHub's API
on your own behalf -- nothing is ever stored server-side or embedded in a deployed service, which
is deliberate (see Why not just call an LLM API directly).
npm install
npm run buildTry the extractors locally first
npm run harness # runs every parser against fixtures/ and checks the counts -- no GitHub callsTry it against a real repo, without going through MCP
npm run live-check <owner> <repo> [branch] # defaults to krishanchawla/playwright-typescript-framework mainRequires a real token (GITHUB_TOKEN or gh auth login). Exercises the same fetch → extract →
history-match logic triage_pipeline_failure wires together, printed directly instead of over MCP
transport -- useful for checking a parser against a real log before trusting it in conversation.
This is how every bug documented in Extractors below was actually found.
Both playwright-typescript-framework and selenium-java-framework also have a standing demo
branch (their main branches stay clean, ready-to-clone framework skeletons -- see each repo's own
README) that exists specifically to give this project real, current CI failures to test against,
instead of hoping main's last 30 runs happen to include one:
npm run live-check krishanchawla playwright-typescript-framework demoRegister with Claude Desktop / Claude Code
Claude Code, from a terminal:
claude mcp add ci-triage-mcp -- node /absolute/path/to/ci-triage-mcp/dist/index.jsIf GITHUB_TOKEN isn't already in your shell environment and you're not relying on gh auth token, set it at registration time instead of in your current shell -- the server won't see a
variable set afterward in some other terminal:
claude mcp add ci-triage-mcp -e GITHUB_TOKEN=<token> -- node /absolute/path/to/ci-triage-mcp/dist/index.jsClaude Desktop, edit claude_desktop_config.json:
{
"mcpServers": {
"ci-triage-mcp": {
"command": "node",
"args": ["/absolute/path/to/ci-triage-mcp/dist/index.js"]
}
}
}Fully quit and restart Claude Desktop/Claude Code after registering or changing this -- it
spawns the server once at startup and won't notice config/env changes made afterward, including a
rebuilt dist/. This bites people (it bit me while building this) far more often than it should.
Then add the repos you want triaged to allowedRepos (see Guardrail), and
ask, e.g.:
Why did the last run of playwright-typescript-framework's CI fail on main?
Tools
Tool | Purpose |
| Resolve a run (by ID, or latest failure on a branch) -> jobs + artifacts |
| One job/artifact -> structured |
| Read-only local history lookup by signature |
| Persist your explanation to local history (no confirmation needed -- local file only) |
| All of the above chained for a whole run |
| Publish to a dashboard -- not deployed publicly yet, works against a self-hosted instance |
Extractors
Source | Parser | Used for |
JUnit / Surefire XML | real XML parser ( | any repo that uploads |
Playwright | line-pattern parser, validated against real logs |
|
ESLint stylish ( | line-pattern parser |
|
tsc ( | line-pattern parser | same lint job's type-check step |
Prettier ( | line-pattern parser | same lint job's format-check step |
Maven/Surefire console "Results" block | line-pattern parser, validated against a real log |
|
selenium-java-framework has never had a failed CI run on its own -- there was nothing real to
validate the Maven console parser against, so it shipped tested only against a hand-written
fixture. To actually check it rather than leave that as a guess: a throwaway branch with one
assertion deliberately flipped ($39.50 → $999.99), opened as a PR (triggers the same workflow,
touches main's history not at all), triaged for real once it failed, then closed unmerged. The
parser correctly pulled the AssertJ diff
(expected:<"$[999.99]"> but was:<"$[39.50]">), test name, class, and line straight out of the
real console output on the first try -- see PR #1
(closed) for the actual run this validated against.
Five bugs live-testing against real playwright-typescript-framework runs has actually surfaced,
in the order they were found:
GitHub prefixes every line of a raw job log with an ISO-8601 timestamp (stripped once at the source in
github.ts,getJobLog). If you add a new text-based parser, write its regexes against already-stripped content -- every fixture infixtures/is pre-stripped for exactly this reason.A
expect(x).toEqual(y)failure against a large object opens with a pretty-printed JSON dump before anything readable --parsePlaywrightListprefers the annotated> N | expect(...)source line instead when the message would otherwise just be a bareError: [.Playwright retries re-print the same failure block. A test that retries twice re-dumps the same (sometimes huge) error text three times into what
parsePlaywrightListtreats as one failure's block -- one accessibility assertion against a large violations object produced a ~60KBstackTraceon a single signal this way.src/extract/truncate.tscaps every extractedstackTraceat 4000 chars now, in every parser, not just this one.An artifact GitHub still lists (with a real file size) can still 410 on download once it's past its retention window --
listArtifactsdoesn't reflect expiry, only the download attempt does.triage_pipeline_failurenow catches each artifact's download individually and falls back to job-log parsing for that job instead of aborting the whole call.The bare-JSON-opener fix above only ever applied to
parsePlaywrightList, notparseJUnitXml. Playwright's own JUnit reporter truncates a<failure message="...">attribute the exact same way its list reporter's first line gets truncated -- so the preferred path (real XML) was producing a worse message ("[") than the fallback path (scraped console text) for the identical failure. The message-picking logic is now shared (src/extract/message.ts) so the two parsers can't drift on this again.
Why not just call an LLM API directly
Because that would mean an Anthropic API key living on a public-facing server, paid for per call and reachable if that server is ever compromised -- a materially different (and worse) risk than anything else in this project. This server never calls an LLM API at all: it's tool calls that the already-running Claude Desktop/Code session decides to make, under whatever plan you're already paying for. Nothing here would need to change if you're using Claude Free, Pro, or Max -- the server doesn't know or care.
Dashboard
dashboard/ is an optional Spring Boot + Thymeleaf app, sibling to k6-loadtest-mcp's own
dashboard/, that publish_triage posts a triage result to -- gives it a real, shareable URL
instead of living only in one Claude conversation. Same design as the load-test dashboard: a
plain jar with its own embedded server, H2 file-backed storage, bearer-token-gated ingest
separate from HTTP-Basic-gated (or public-demo, unauthenticated) viewing.
What it adds beyond just listing runs:
Category breakdown chart across every extracted signal, not just each run's headline category -- a single run routinely mixes categories (the Example above is real: one CI run produced a genuine accessibility regression and an unrelated cluster of infra timeouts, and counting at the signal level is the only way that doesn't get hidden behind whichever one happened to run first).
Recurrence tracking -- every signal is matched against prior triage runs for the same repo by its stable
signature; the detail page shows "seen N× before" instead of treating every failure as novel, and the list page surfaces a standing "Recurring failures" panel.Narrative-first detail page -- the LLM's explanation and suggested fix are the headline content, with raw stack traces behind a
<details>disclosure per signal, not the other way around.A 14-day run-volume sparkline per repo, so a rising or falling triage rate is visible at a glance, not just a bare run count.
Build and run it locally
cd dashboard
mvn -q package # -> target/ci-triage-dashboard.jar
DASHBOARD_API_TOKEN=<pick-a-token> java -jar target/ci-triage-dashboard.jarThen point dashboardUrl in ~/.ci-triage-mcp/config.json at it (e.g.
"http://localhost:8081" while testing locally) and set CI_TRIAGE_DASHBOARD_TOKEN to match, on
the MCP server's own registration (see Setup for why it has to be set there, not a
shell env var).
Deploying it
Same posture as k6-loadtest-mcp's dashboard -- a self-contained jar with its own embedded
server (Spring Boot 4 / Jakarta EE, needs Tomcat 11+ if you ever did drop it into an external
container, which there's no reason to). Run it via systemd with:
Env var | Required | Purpose |
| yes, to accept triage results | Bearer token |
| no | HTTP Basic guarding every page except |
| yes, for correct links | Externally visible base URL used to build the shareable links |
| no | Public-demo-mode only: comma-separated |
| no | Public-demo-mode only: auto-prune triage runs older than N days. Unset keeps everything forever. |
| no (default | Port the embedded server listens on -- deliberately different from the load-test dashboard's |
Roadmap
Artifact upload for
selenium-java-framework. The console parser works (see Extractors), but atarget/surefire-reports/upload-artifact step (mirroring whatplaywright-typescript-frameworkalready does) would let it use the real JUnit XML parser instead -- structured XML over scraping console output whenever it's available at all.CI on this repo itself.
npm run harnessruns the extractor fixtures locally but nothing runs it on push -- a.github/workflowsjob that fails loudly on a broken parser would be a cheap, honest thing for a CI-triage tool to be missing.Actually deploy the dashboard to the VPS and wire
dashboardUrlthere -- built, verified locally, and now proven end-to-end against a real triage result (see the Dashboard screenshots above), just not yet live anywhere public.live-check.tsandtriage_pipeline_failurereimplement the same fetch → extract pipeline independently. They drifted once already --live-check.tsalready caught per-artifact download failures individually, buttriage_pipeline_failuredidn't until a live test against the actual MCP tool caught the gap. Worth factoring into one shared function both call, so a fix to one can't silently miss the other again.
Available Tools
6 toolsextract_failure_signalDeterministically extract failure signal from a job's log or a JUnit/Surefire artifactA
Turns a noisy raw CI log (or a downloaded JUnit/Surefire XML artifact) into structured FailureSignal entries -- test name, class, message, stack trace, and a stable signature -- using real parsers (JUnit/Surefire XML, ESLint stylish, tsc, Prettier, Maven console), not an LLM guessing from raw text. Prefer passing artifactName when fetch_pipeline_run listed one matching /junit|surefire/i for this run; otherwise this reads the job's own console log.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | Repository name, e.g. "playwright-typescript-framework" | |
| jobId | Yes | Job ID from fetch_pipeline_run's jobs list. | |
| owner | Yes | Repository owner/org, e.g. "krishanchawla" | |
| runId | Yes | ||
| artifactName | No | Artifact name from fetch_pipeline_run's artifacts list, if using structured XML instead of the job log. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses that the operation reads a log or artifact and uses 'real parsers (JUnit/Surefire XML, ESLint stylish, tsc, Prettier, Maven console), not an LLM guessing from raw text.' This adds valuable behavioral context beyond a simple 'extract' verb, implying deterministic, read-only behavior. It does not discuss edge cases or errors, but the read-only nature is clear through 'reads' and 'extract.'
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences that are information-dense: the first defines the transformation and output, the second provides usage guidance. There is no filler or repetition of schema field names. It is well-structured and front-loaded with the primary purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema and no annotations, so the description must cover return semantics. It does list the output fields (test name, class, message, stack trace, signature), which is helpful. However, it does not explain behaviors when no failure signal is found, how errors are handled, or whether the output is always a list. It also doesn't address potential edge cases like missing artifacts or malformed logs, leaving some ambiguity for a parser tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 80% (4 of 5 parameters have descriptions). The description adds meaning for artifactName by explaining it selects structured XML instead of the job log. However, runId lacks any description in either the schema or the description, and the description does not compensate for that gap. Overall, it meets the baseline but doesn't significantly elevate parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action ('Turns a noisy raw CI log or a downloaded JUnit/Surefire XML artifact into structured FailureSignal entries') with a defined resource (the log or artifact) and output (test name, class, message, stack trace, signature). It distinguishes from siblings by focusing on extraction/parsing rather than fetching, searching, recording, or triaging.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance: 'Prefer passing artifactName when fetch_pipeline_run listed one matching /junit|surefire/i for this run; otherwise this reads the job's own console log.' This provides a clear conditional for when to use the artifact vs the log. It does not explicitly name alternative sibling tools for the same task, but the conditional context is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_pipeline_runFetch a CI/CD pipeline run's jobs and artifactsA
Resolves a GitHub Actions run (by runId, or the most recent failed run on a branch) and lists its jobs and artifacts. Only works for repos listed in allowedRepos in ~/.ci-triage-mcp/config.json -- add a repo there yourself first (see guardrails.ts).
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | Repository name, e.g. "playwright-typescript-framework" | |
| owner | Yes | Repository owner/org, e.g. "krishanchawla" | |
| runId | No | Specific run ID. Omit to use the latest failed run on `branch`. | |
| branch | No | Branch to search when runId is omitted. | main |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description carries the full burden of behavioral disclosure. It discloses key behaviors: the resolution logic (runId vs. latest failed run), the output (jobs and artifacts), and a significant restriction (allowedRepos config requirement, referencing guardrails.ts). It does not mention whether the operation is read-only, but 'lists' implies no side effects. The description adds context beyond a bare schema, covering important operational constraints, though it could go further (e.g., error handling or rate limits).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences, front-loaded with the main purpose in the first sentence and the key prerequisite in the second. Every phrase earns its place—no fluff or redundancy. It is appropriately sized for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the essential aspects for an agent to use this tool: what it does (fetch jobs/artifacts), how it selects the run (runId or latest failed on branch), and a critical prerequisite (allowedRepos config). Since there is no output schema, the description directly states the return content ('jobs and artifacts'), which is sufficient. It lacks some detail like error cases or return format specifics, but given the moderate complexity and clear title, it is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides 100% coverage, describing all four parameters (owner, repo, runId, branch) with examples and defaults. The tool description itself adds no additional parameter-specific information; it only mentions runId and branch conceptually, but the schema already explains them. Per the rubric, this is a baseline 3 since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Resolves a GitHub Actions run (by runId, or the most recent failed run on a branch) and lists its jobs and artifacts.' This is specific with a verb ('Resolves', 'lists'), a resource (GitHub Actions run), and outputs (jobs/artifacts). It also distinguishes itself from sibling tools (e.g., extract_failure_signal, find_similar_past_failures) which focus on analyzing or recording triage, not fetching raw run data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear functional context: it fetches a run's jobs and artifacts, with an explicit resolution mode ('by runId, or the most recent failed run on a branch'). It also mentions a critical prerequisite: 'Only works for repos listed in allowedRepos in ~/.ci-triage-mcp/config.json -- add a repo there yourself first.' While it does not explicitly name alternative tools or say 'use this when...', the purpose is clear enough for an agent to infer when to use it, and the prerequisite offers important usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_similar_past_failuresLook up whether these failure signatures have been seen beforeA
Read-only lookup against a local history store (~/.ci-triage-mcp/history.json) of failure signatures this tool has previously extracted or recorded for this repo. Use this to say "this has happened N times before" instead of treating every failure as novel. Doesn't modify history -- see record_triage_note to persist your own explanation for future lookups.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | "owner/repo", e.g. "krishanchawla/playwright-typescript-framework" | |
| signatures | Yes | signature values from extract_failure_signal's FailureSignal entries |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It explicitly states the tool is read-only, 'Doesn't modify history', and identifies the local store path. It doesn't cover edge cases like missing history file, but the key behavioral guarantees are clearly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no fluff. The first sentence front-loads the action and target store; the second adds usage context and an explicit pointer to the write alternative. Every phrase earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 2-parameter lookup tool with no output schema, the description covers purpose, usage, storage location, safety, and alternatives. It doesn't describe return format or edge cases, but the core context is sufficient for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for both parameters, so the baseline is 3. The description adds a small connection between signatures and extract_failure_signal's FailureSignal entries, but mostly repeats what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Look up') and a clear resource: a local history store of failure signatures for the repo. It clearly distinguishes itself from siblings by contrasting with record_triage_note, making the tool's unique role obvious.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it: to say 'this has happened N times before' instead of treating failures as novel. It also points to record_triage_note for persisting explanations, providing a clear alternative and exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
publish_triagePublish a triage result to the dashboardA
Sends a triage's explanation and signals to a deployed ci-triage-dashboard instance, returning a shareable URL. Requires "dashboardUrl" in ~/.ci-triage-mcp/config.json and the CI_TRIAGE_DASHBOARD_TOKEN env var -- neither is set by default. ci-triage-dashboard (see dashboard/) exists and works but isn't deployed anywhere public yet (see README roadmap), so this will currently fail with a clear "not configured" error until dashboardUrl is set. Ask the user before calling this once it is configured -- publishing may make the triage readable by others.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | Repository name, e.g. "playwright-typescript-framework" | |
| owner | Yes | Repository owner/org, e.g. "krishanchawla" | |
| runId | Yes | ||
| signals | Yes | ||
| summary | Yes | ||
| category | Yes | ||
| suggestedFix | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully bears the transparency burden. It discloses that publishing 'may make the triage readable by others,' warns that the tool will currently fail with a 'not configured' error, and instructs to ask the user first. This reveals side effects, failure behavior, and an important usage constraint beyond what the schema or annotations could convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately front-loaded with the primary action, then prerequisites, current status, and a final warning. It is somewhat verbose, but each sentence contributes necessary operational context. A tighter version could combine the configuration prerequisites, but the structure is logical and not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (7 params, no output schema) and lack of annotations, the description covers the key operational context: what it does, what's needed to run, current deployment reality, and the need for user consent. It mentions the return value (shareable URL) but does not detail response structures or additional error cases beyond configuration. This is near-complete for the tool's purpose.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers only 29% of parameters (only repo and owner have descriptions), so the description must compensate. It mentions 'explanation and signals,' which loosely maps to summary/category and the signals array, but it does not elaborate on individual parameter meanings like runId or suggestedFix. This partial coverage merits a 3, as it adds some context but leaves many parameters to inference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Sends a triage's explanation and signals to a deployed ci-triage-dashboard instance, returning a shareable URL.' This uses a specific verb ('sends') and resource ('dashboard instance'), and differentiates it from siblings like record_triage_note by focusing on external publishing rather than local recording.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage context: prerequisites (dashboardUrl and CI_TRIAGE_DASHBOARD_TOKEN), current deployment status, and a clear instruction to 'Ask the user before calling this once it is configured.' It does not name alternatives, but the warning about failure and permission-seeking make when-to-use clear. Slightly short of a 5 because it doesn't explicitly contrast with sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_triage_notePersist this triage's explanation to local historyA
Appends your explanation for a failure signature to the local history store, and bumps its occurrence count. Local file write only -- safe to call without asking the user first, unlike publish_triage which sends data to a shared dashboard. Do this after explaining a failure so future find_similar_past_failures calls have something useful to surface.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | "owner/repo" | |
| summary | Yes | Your plain-language explanation of the root cause. | |
| category | Yes | ||
| signature | Yes | ||
| suggestedFix | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of disclosing behavior. It reveals the tool performs a local file write only, is safe to call without asking the user, and appends/increments occurrence count. It does not cover edge cases like failure handling or file locking, but provides strong transparency for a simple local operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences: first states the action and effect, second clarifies safety and contrast with publish_triage, third gives sequential context. Every sentence is information-dense with no filler. Front-loaded with the primary purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple local-write tool with no output schema, the description covers purpose, safety, usage context, and workflow integration with sibling tools. The main gap is insufficient parameter semantics for two of the five fields, but overall the tool is adequately contextualized within its triage pipeline.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is low (40%), and the description does not compensate. It references 'failure signature' and 'explanation' conceptually but does not add meaning for the signature or suggestedFix parameters, nor clarify the relationship between repo/signature/category beyond what the schema already states. The description adds little value beyond the schema's sparse field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('appends') and resource ('explanation for a failure signature to the local history store'), and clearly states it also bumps occurrence count. It distinguishes itself from the sibling publish_triage by explicitly contrasting local write vs. shared dashboard.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance ('Do this after explaining a failure') and names the alternative (publish_triage) with a clear differentiator (local vs. shared dashboard). It also ties the action to the purpose of enabling future find_similar_past_failures calls, making the usage context unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
triage_pipeline_failureFetch, extract, and cross-reference a failed run in one callA
Convenience tool that chains fetch_pipeline_run -> (download every JUnit/Surefire-looking artifact for the run, and every failed job's log) -> extract_failure_signal's parsers -> find_similar_past_failures. Returns everything needed to write the explanation in one call. Use the granular tools instead when you want to target one specific job. The response includes a dashboardConfigured flag -- if true, ask the user whether they'd like this triage published before calling publish_triage; don't publish automatically.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | Repository name, e.g. "playwright-typescript-framework" | |
| owner | Yes | Repository owner/org, e.g. "krishanchawla" | |
| runId | No | Specific run ID. Omit to use the latest failed run on `branch`. | |
| branch | No | main |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden. It discloses the entire pipeline chain, including downloading artifacts/logs and running parsers/search, and mentions the dashboardConfigured flag behavior. It doesn't mention potential performance costs of downloading artifacts or any side effects, but overall it's quite transparent about how the tool behaves.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two dense sentences that front-load the purpose and chain, then add a usage alternative and a critical publishing caution. It is efficient but slightly long; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex chained tool with no output schema or annotations, the description covers the pipeline, what it returns at a high level, and a key behavioral caveat. It lacks a detailed return structure, but for the purpose of selecting and invoking the tool, it is sufficiently complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75% (branch lacks a description), so baseline is 3. The description does not add parameter-level details beyond what the schema already provides, but the composite nature implies the parameters align with fetch_pipeline_run. No extra meaning is added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states this is a convenience tool that chains fetch_pipeline_run, artifact/log downloads, extract_failure_signal's parsers, and find_similar_past_failures, returning everything needed to write an explanation. It explicitly distinguishes itself from granular siblings by advising to use those when targeting a specific job.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use (want a full triage in one call) and when not to (when targeting one specific job, use granular tools). Also provides a post-call guideline about asking the user before publishing if dashboardConfigured is true.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a distinct role in the triage pipeline: fetching runs, extracting signals, finding history, recording notes, and publishing. The convenience tool 'triage_pipeline_failure' overlaps with the granular tools but its description clearly positions it as a chaining wrapper, so misselection is unlikely.
All tool names follow a consistent verb_noun pattern in snake_case: fetch_pipeline_run, extract_failure_signal, find_similar_past_failures, record_triage_note, triage_pipeline_failure, publish_triage. No mixed conventions or vague verbs.
Six tools is well-scoped for a CI triage server. Each tool covers a necessary step in the workflow without redundancy, and the count is within the ideal 3-15 range.
The toolset covers the full triage cycle: fetch, extract, lookup, record, and publish. Minor gaps include no update/delete for history notes and no tool to configure allowed repos, but these are config/support concerns rather than core workflow gaps.
Maintenance
Related MCP Connectors
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
An MCP server that gives your AI access to the source code and docs of all public github repos
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server giving Claude AI access to 22+ NYC public-record databases for real estate due diligence
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server that spawns autonomous Claude Code agents in GitHub repos, enabling task delegation with persistent state, multi-step workflows, and job monitoring.47942Apache 2.0
- AlicenseNot gradedqualityCmaintenanceMCP server providing RAG context and failure capture for Claude Code, enabling semantic search across project knowledge and storing/analyzing failures.1MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that pushes GitHub Actions CI/CD results and PR events into Claude Code sessions, enabling automatic investigation and remediation.131MIT
- AlicenseAqualityCmaintenanceMCP server for GitHub Actions CI failure triage. It wraps the gh CLI to fetch PR checks, failed jobs, and tail/grep failed job logs with ANSI/timestamp stripping and root-cause extraction.5MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/krishanchawla/ci-triage-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server