---
name: mcp-inspect-triage
version: 1.0.2
description: |
  Read a failing MCP Inspect check and decide what to do: fix the change, stage
  it across releases, or record a deliberate exception. Covers every severity and
  what each one actually implies for callers.
  Use for "the MCP check is failing", "mcp-inspect says breaking", "why did my
  MCP compatibility check fail", "how do I fix this MCP diff".
allowed-tools:
  - Bash
  - Read
  - Edit
  - Grep
  - AskUserQuestion
---

# Triage an MCP Inspect failure

This workflow requires an MCP Inspect CLI build supplied through approved
preview access. Public CLI and Action releases are pending; the source
repository is private. If the CLI is unavailable, direct the user to
<https://mcprobe.dev/docs/getting-started> for the hosted console workflow.
Do not install the unrelated npm package named `mcp-inspect`.

## First, get the machine-readable report

```bash
mcp-inspect check --format json --output /tmp/mcp-check.json
```

Exit 1 means a contract failure and the report is still available; exit 2 means
the command could not run. Read the report even when the process exits 1. A
`status: "skipped"` / `compared: false` report means no baseline was compared,
not that compatibility passed. Capture a baseline and compare after the next
edit. For a `servers:` map, select `--server <name>` or read each named entry in
`reports`; each has its own comparison outcome.

Each change carries a `ruleId`, a `severity`, the `path` inside the entity, the
`oldValue`, the `newValue` and a `migration`. Read `migration` before inventing
a fix — it is the specific remedy for that rule.

Full reference: https://mcprobe.dev/docs/rules — every heading is a rule id,
so `#tool.input.required.added` resolves.

## Decide by severity

### BREAKING

A correct existing caller can stop working. Three legitimate responses:

1. **Undo it.** Most common and usually correct for an accidental change.
2. **Stage it.** Almost every `BREAKING` rule has a two-release path:
   - argument became required → accept it as optional, apply the old default,
     require it next release
   - property removed → keep accepting and ignoring it for one release
   - enum narrowed → keep accepting removed values and map them
   - tool removed or renamed → keep the old name as an alias that forwards
3. **Ship it deliberately**, with evidence. See "Deliberate exceptions" below.

### POTENTIALLY_BREAKING

Behavior or model-visible semantics changed. Callers may drift or fail, even
when the schema still accepts their requests. This is the category most
people wave through and should not.

- **description or instructions changed** → re-run your tool-selection
  evaluations. If you have none, this change is unmeasurable; say so out loud
  rather than assuming it is fine.
- **annotations changed** → clients that auto-approve read-only or idempotent
  tools now behave differently. `tool.annotations.safetyWeakened` means the tool
  withdrew a promise; treat it as breaking if anything gates on annotations.
- **default changed** → the schema still validates, but calls that omit the
  argument now behave differently. Check how often it is omitted before shipping.

### NON_BREAKING and DOCUMENTATION

No action. If they are noisy in review, silence the specific rule rather than
raising the threshold.

## Deliberate exceptions

Record them in `.mcp-inspect.yml`, never by weakening the gate:

```yaml
ignore:
  - rule: tool.removed
    entity: legacy_search
    reason: "Announced for removal in 2.3; no recorded calls in the requested 90-day window, coverage unverified. Removal accepted for 3.0.0."
```

A suppressed change still appears in the report with its reason, so the decision
stays visible in review. Two things to avoid: setting `fail_on: never`, and
adding `continue-on-error` to the workflow. Both convert a signal into noise
permanently.

## When usage evidence is available

If the project is connected to a hosted account, check before removing anything:

```bash
mcp-inspect usage --tool legacy_search --days 90 --json
```

Read the answer carefully. "No calls observed in 90 days" is **not** "no callers".
A quarterly job, a client that has not run this window, or an integration nobody
remembers will not appear. The tool never says anything is safe to remove, and
neither should you — report "no recorded calls in the requested 90-day window"
with coverage limits. Follow the maintainer's authorized release decision.

Client software/version cohorts are not distinct consumers or integrations.
Report recorded calls, the requested window, the most recent observation and
coverage limits; keep sampling-corrected estimates separate. A selected date
range is not continuous coverage. For arguments, a zero is usable as absence
evidence only when `measurable: true` and `neverObserved: true`; otherwise absence
is unknown. Do not increase confidence from estimated volume.

## Reporting back

State, in this order: what changed, which severity and rule, whether a caller
breaks, and the specific remedy you applied or recommend. Do not say "fixed the
check" — say what you changed about the contract.
