Rule reference
Every change MCP Inspect can report, with its default severity and what to do about it. Generated from the diff engine, so it cannot drift.
Each rule has a stable id. .mcp-inspect.yml silences by id, the JSON and
SARIF reports carry it, and every heading on this page is a link target — so
an annotation in your CI can point straight at the rule that produced it.
Renaming a rule would break customers' configs, so a classification change adds a new id and keeps the old one emitting until a major version.
# .mcp-inspect.yml
ignore:
- rule: tool.icons.changed
- rule: tool.description.changed
entity: legacy_*
reason: "Legacy tools are being rewritten; churn is expected."
severity_overrides:
tool.annotations.safetyWeakened: BREAKING
#Index
Server and protocol — server.capability.added · server.capability.changed · server.capability.removed · server.extension.added · server.extension.changed · server.extension.removed · server.identity.changed · server.instructions.changed · server.protocolVersion.changed · server.surface.scopeNarrowed · server.version.added · server.version.dropped
Tool input schemas — tool.input.added · tool.input.constraint.changed · tool.input.constraint.loosened · tool.input.constraint.tightened · tool.input.default.changed · tool.input.deprecated.added · tool.input.deprecated.removed · tool.input.description.changed · tool.input.enum.narrowed · tool.input.enum.widened · tool.input.header.changed · tool.input.property.added · tool.input.property.addedRequired · tool.input.property.removed · tool.input.removed · tool.input.required.added · tool.input.required.removed · tool.input.schema.changed · tool.input.type.changed · tool.input.type.narrowed · tool.input.type.widened
Tool output schemas — tool.output.added · tool.output.constraint.changed · tool.output.constraint.loosened · tool.output.constraint.tightened · tool.output.default.changed · tool.output.deprecated.added · tool.output.deprecated.removed · tool.output.description.changed · tool.output.enum.narrowed · tool.output.enum.widened · tool.output.header.changed · tool.output.property.added · tool.output.property.addedRequired · tool.output.property.removed · tool.output.removed · tool.output.required.added · tool.output.required.removed · tool.output.schema.changed · tool.output.type.changed · tool.output.type.narrowed · tool.output.type.widened
Tools — tool.added · tool.annotations.added · tool.annotations.changed · tool.annotations.removed · tool.annotations.safetyWeakened · tool.description.changed · tool.icons.changed · tool.meta.changed · tool.removed · tool.renamed · tool.title.changed · tool.ui.resourceUri.added · tool.ui.resourceUri.changed · tool.ui.resourceUri.removed · tool.ui.visibility.narrowed · tool.ui.visibility.widened
Resource templates — resourceTemplate.added · resourceTemplate.annotations.changed · resourceTemplate.description.changed · resourceTemplate.meta.changed · resourceTemplate.mimeType.changed · resourceTemplate.name.changed · resourceTemplate.removed · resourceTemplate.title.changed
Resources — resource.added · resource.annotations.changed · resource.description.changed · resource.meta.changed · resource.mimeType.changed · resource.name.changed · resource.removed · resource.title.changed · resource.ui.csp.narrowed · resource.ui.csp.widened · resource.ui.domain.changed · resource.ui.permissions.added · resource.ui.permissions.removed · resource.ui.widgetDescription.changed
Prompts — prompt.added · prompt.argument.added · prompt.argument.addedRequired · prompt.argument.description.changed · prompt.argument.nowOptional · prompt.argument.nowRequired · prompt.argument.removed · prompt.description.changed · prompt.removed · prompt.title.changed
#Server and protocol
#server.capability.added
Default severity: NON_BREAKING
A capability is now advertised.
#server.capability.changed
Default severity: POTENTIALLY_BREAKING
e.g. listChanged or subscribe flipped.
Check that clients relying on the previous flag still behave correctly.
#server.capability.removed
Default severity: BREAKING
capabilities.tools / resources / prompts / … withdrawn.
Clients gate whole feature sets on this capability. Restore it, or announce the removal a release ahead.
#server.extension.added
Default severity: NON_BREAKING
A new extension is advertised.
#server.extension.changed
Default severity: POTENTIALLY_BREAKING
An extension's settings object changed.
Extension settings are part of the negotiated contract; version the extension id if this is not backwards compatible.
#server.extension.removed
Default severity: BREAKING
An advertised extension is gone; clients negotiated for it.
A client that negotiated this extension will lose the behaviour it asked for. Restore it, or fall back to core behaviour explicitly.
#server.identity.changed
Default severity: DOCUMENTATION
serverInfo.name / version / title changed.
#server.instructions.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
The instructions string changed. It is in the model's context.
Instructions are in the model's context on every conversation. Re-run any evaluation that depends on how this server is used.
#server.protocolVersion.changed
Default severity: POTENTIALLY_BREAKING
The negotiated revision changed. Different rules now apply.
Confirm clients on the previous revision can still reach this server, and keep the old version in supportedVersions until they have moved.
#server.surface.scopeNarrowed
Default severity: POTENTIALLY_BREAKING
A list result went cacheScope: public → private: the surface now varies by authorization, so this snapshot describes one caller's view, not the server's.
This surface now varies by authorization, so a snapshot describes one caller's view. Capture baselines with a consistent credential or this diff will report phantom changes.
#server.version.added
Default severity: NON_BREAKING
A new protocol version is supported.
#server.version.dropped
Default severity: BREAKING
A previously supported protocol version is gone.
Restore the version, or confirm no client still negotiates it.
#Tool input schemas
#tool.input.added
Default severity: NON_BREAKING
An absent outputSchema appeared.
#tool.input.constraint.changed
Default severity: BREAKING
pattern, format, const, multipleOf, $ref or a oneOf branch set changed: not orderable.
The two constraints are not orderable, so compatibility cannot be established structurally. Verify by hand.
#tool.input.constraint.loosened
Default severity: NON_BREAKING
A bound moved outward.
Consumers validating results against the old bound will start rejecting them.
#tool.input.constraint.tightened
Default severity: BREAKING
A bound moved inward (minLength, maximum, additionalProperties: false, uniqueItems, allOf branch added, anyOf branch removed).
Input that was valid is now rejected. Loosen the bound, or stage the change.
#tool.input.default.changed
Default severity: POTENTIALLY_BREAKING
A default was added, removed or changed. The schema still validates; the behavior does not match.
The schema still validates, but calls that omit this argument now behave differently. Check telemetry for how often it is omitted before shipping.
#tool.input.deprecated.added
Default severity: NON_BREAKING
deprecated: true appeared on a property.
Check usage before removing it in a later release.
#tool.input.deprecated.removed
Default severity: NON_BREAKING
A property is no longer marked deprecated.
#tool.input.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
A property description or title changed. Models read these when filling arguments.
Models read property descriptions when filling arguments. A changed one can change what gets passed.
#tool.input.enum.narrowed
Default severity: BREAKING
Values removed from an enum.
Callers passing a removed value will now fail. Accept the old values and map them for one release.
#tool.input.enum.widened
Default severity: NON_BREAKING
Values added to an enum.
Consumers switching exhaustively on this enum will not handle the new values.
#tool.input.header.changed
Default severity: BREAKING
x-mcp-header added, removed or changed: it alters how the call is transmitted over HTTP.
x-mcp-header changes how the call is transmitted over HTTP, so intermediaries routing on the mirrored header will stop matching.
#tool.input.property.added
Default severity: NON_BREAKING
A new optional property.
#tool.input.property.addedRequired
Default severity: BREAKING
A new property that is immediately required.
Every existing call omits this property and will now fail validation. Add it as optional with a default, then require it a release later.
#tool.input.property.removed
Default severity: BREAKING
A property is gone.
Accept and ignore the property for one release so existing callers keep working, then remove it.
#tool.input.removed
Default severity: BREAKING
A declared outputSchema disappeared.
A client that generated types from this schema loses them. Restore the schema, or release the removal as a major version.
#tool.input.required.added
Default severity: BREAKING
Optional → required.
Accept calls that omit it for at least one release, applying the previous default, then require it.
#tool.input.required.removed
Default severity: NON_BREAKING
Required → optional.
Consumers may assume this field is always present in a result. Keep emitting it, or release the change as a major version.
#tool.input.schema.changed
Default severity: BREAKING
The completeness net. A difference the structured walk does not model. See §9.
This schema keyword is not modelled by the diff engine, so the change is reported as breaking until a human confirms otherwise.
#tool.input.type.changed
Default severity: BREAKING
Type sets are not comparable.
The type sets are not comparable, so no existing caller is guaranteed to still work.
#tool.input.type.narrowed
Default severity: BREAKING
The type set shrank.
Keep accepting the removed types and coerce them for one release.
#tool.input.type.widened
Default severity: NON_BREAKING
The type set grew.
Consumers typed against the narrower schema will not handle the new types.
#Tool output schemas
#tool.output.added
Default severity: NON_BREAKING
An absent outputSchema appeared.
#tool.output.constraint.changed
Default severity: BREAKING
pattern, format, const, multipleOf, $ref or a oneOf branch set changed: not orderable.
The two constraints are not orderable, so compatibility cannot be established structurally. Verify by hand.
#tool.output.constraint.loosened
Default severity: BREAKING
A bound moved outward.
Consumers validating results against the old bound will start rejecting them.
#tool.output.constraint.tightened
Default severity: NON_BREAKING
A bound moved inward (minLength, maximum, additionalProperties: false, uniqueItems, allOf branch added, anyOf branch removed).
Input that was valid is now rejected. Loosen the bound, or stage the change.
#tool.output.default.changed
Default severity: POTENTIALLY_BREAKING
A default was added, removed or changed. The schema still validates; the behavior does not match.
The schema still validates, but calls that omit this argument now behave differently. Check telemetry for how often it is omitted before shipping.
#tool.output.deprecated.added
Default severity: NON_BREAKING
deprecated: true appeared on a property.
Check usage before removing it in a later release.
#tool.output.deprecated.removed
Default severity: NON_BREAKING
A property is no longer marked deprecated.
#tool.output.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
A property description or title changed. Models read these when filling arguments.
Models read property descriptions when filling arguments. A changed one can change what gets passed.
#tool.output.enum.narrowed
Default severity: NON_BREAKING
Values removed from an enum.
Callers passing a removed value will now fail. Accept the old values and map them for one release.
#tool.output.enum.widened
Default severity: BREAKING
Values added to an enum.
Consumers switching exhaustively on this enum will not handle the new values.
#tool.output.header.changed
Default severity: BREAKING
x-mcp-header added, removed or changed: it alters how the call is transmitted over HTTP.
x-mcp-header changes how the call is transmitted over HTTP, so intermediaries routing on the mirrored header will stop matching.
#tool.output.property.added
Default severity: NON_BREAKING
A new optional property.
#tool.output.property.addedRequired
Default severity: NON_BREAKING
A new property that is immediately required.
Every existing call omits this property and will now fail validation. Add it as optional with a default, then require it a release later.
#tool.output.property.removed
Default severity: BREAKING
A property is gone.
Accept and ignore the property for one release so existing callers keep working, then remove it.
#tool.output.removed
Default severity: BREAKING
A declared outputSchema disappeared.
A client that generated types from this schema loses them. Restore the schema, or release the removal as a major version.
#tool.output.required.added
Default severity: NON_BREAKING
Optional → required.
Accept calls that omit it for at least one release, applying the previous default, then require it.
#tool.output.required.removed
Default severity: BREAKING
Required → optional.
Consumers may assume this field is always present in a result. Keep emitting it, or release the change as a major version.
#tool.output.schema.changed
Default severity: BREAKING
The completeness net. A difference the structured walk does not model. See §9.
This schema keyword is not modelled by the diff engine, so the change is reported as breaking until a human confirms otherwise.
#tool.output.type.changed
Default severity: BREAKING
Type sets are not comparable.
The type sets are not comparable, so no existing caller is guaranteed to still work.
#tool.output.type.narrowed
Default severity: NON_BREAKING
The type set shrank.
Keep accepting the removed types and coerce them for one release.
#tool.output.type.widened
Default severity: BREAKING
The type set grew.
Consumers typed against the narrower schema will not handle the new types.
#Tools
#tool.added
Default severity: NON_BREAKING
A new tool appears.
#tool.annotations.added
Default severity: POTENTIALLY_BREAKING
An annotation appeared. Agents use these to decide whether to call.
Confirm clients that filter tools by annotation still see this one.
#tool.annotations.changed
Default severity: POTENTIALLY_BREAKING
An annotation's value changed.
Confirm clients that filter or rank tools by annotation still behave as intended.
#tool.annotations.removed
Default severity: POTENTIALLY_BREAKING
An annotation disappeared.
A client filtering on this annotation will no longer match this tool.
#tool.annotations.safetyWeakened
Default severity: POTENTIALLY_BREAKING
readOnlyHint/idempotentHint left true, or destructiveHint/openWorldHint left false. The tool withdrew a promise. Escalate this rule to BREAKING in config if you gate on annotations.
The tool withdrew a behavioural promise. Clients that auto-approve read-only or idempotent tools will now prompt, or worse, will have already auto-approved a tool that is no longer read-only. Set severity_overrides.tool.annotations.safetyWeakened to BREAKING if you gate on annotations.
#tool.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
description changed. This is the primary tool-selection signal.
The description is the primary tool-selection signal. Re-run your evaluations: a model may now pick this tool where it did not, or stop picking it where it did.
#tool.icons.changed
Default severity: DOCUMENTATION
icons changed.
#tool.meta.changed
Default severity: NON_BREAKING
_meta changed. Emitted for every _meta change; the MCP Apps keys are also interpreted by the tool.ui.* rules below (§7.1).
#tool.removed
Default severity: BREAKING
A tool is gone.
Keep the tool deprecated for at least one release. Review observed usage and unmeasured consumers before removal; no observed calls is not proof of no dependency.
#tool.renamed
Default severity: BREAKING
A removal and an addition share an identical schema fingerprint, one candidate each way. Reported as one change instead of two.
Keep the old name as an alias that forwards to the new one for at least one release. Agents have the old name in their context and in cached tool lists.
#tool.title.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
title changed. Clients display it; models read it.
#tool.ui.resourceUri.added
Default severity: NON_BREAKING
The tool now links a ui:// template, so hosts render its results with a UI.
#tool.ui.resourceUri.changed
Default severity: POTENTIALLY_BREAKING
The tool links a different template. Hosts may have prefetched and cached the old one.
Hosts may have prefetched and cached the old template. Keep serving the old URI for a release, and make sure the new template accepts the structuredContent this tool returns.
#tool.ui.resourceUri.removed
Default severity: POTENTIALLY_BREAKING
The tool no longer links a UI template. Calls succeed; hosts fall back to text and users lose the UI.
Hosts fall back to plain text, so calls still succeed, but users lose the UI they had. If this is intentional, say so in the release notes; otherwise restore _meta.ui.resourceUri.
#tool.ui.visibility.narrowed
Default severity: BREAKING
The tool lost the "model" audience (hosts drop it from the agent's tool list) or the "app" audience (hosts reject the UI's calls).
Without "model" the host takes the tool out of the agent's tool list, which is a removal for every agent; without "app" the host rejects calls from the UI. Keep the previous visibility for a release, or add a replacement first.
#tool.ui.visibility.widened
Default severity: NON_BREAKING
The tool gained the "model" or "app" audience.
#Resource templates
#resourceTemplate.added
Default severity: NON_BREAKING
A new uriTemplate.
#resourceTemplate.annotations.changed
Default severity: POTENTIALLY_BREAKING
—
#resourceTemplate.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
—
#resourceTemplate.meta.changed
Default severity: NON_BREAKING
_meta changed.
#resourceTemplate.mimeType.changed
Default severity: BREAKING
—
Consumers parsing the body by its declared type will fail.
#resourceTemplate.name.changed
Default severity: POTENTIALLY_BREAKING
—
#resourceTemplate.removed
Default severity: BREAKING
A uriTemplate is gone.
Clients constructing URIs from this template will stop being able to.
#resourceTemplate.title.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
—
#Resources
#resource.added
Default severity: NON_BREAKING
A new resource URI.
#resource.annotations.changed
Default severity: POTENTIALLY_BREAKING
audience / priority etc. changed.
Annotations like audience and priority steer which resources a client surfaces.
#resource.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
description changed.
#resource.meta.changed
Default severity: NON_BREAKING
_meta changed. Emitted for every _meta change, alongside any resource.ui.* rule.
#resource.mimeType.changed
Default severity: BREAKING
A consumer parsing the body will fail.
Consumers parsing the body by its declared type will fail.
#resource.name.changed
Default severity: POTENTIALLY_BREAKING
Models select resources by name.
Models select resources by name; a rename changes what gets read.
#resource.removed
Default severity: BREAKING
A resource URI is gone.
Clients holding this URI will start getting errors. Keep it, or redirect it.
#resource.title.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
title changed.
#resource.ui.csp.narrowed
Default severity: BREAKING
An origin left a UI template's CSP list, so the host blocks the template's requests to it.
The host builds the template's Content-Security-Policy from these lists, so requests to a removed origin are blocked. Remove the origin only after the template stops using it.
#resource.ui.csp.widened
Default severity: NON_BREAKING
An origin was added to a UI template's CSP list.
#resource.ui.domain.changed
Default severity: POTENTIALLY_BREAKING
The UI template's dedicated origin was set, unset or changed. Anything keyed on the origin must follow.
The template now runs on a different origin. Update anything keyed on the old one (OAuth redirect URIs, CORS and API-key allowlists) before releasing.
#resource.ui.permissions.added
Default severity: NON_BREAKING
The template requests a new sandbox permission.
#resource.ui.permissions.removed
Default severity: POTENTIALLY_BREAKING
The template no longer requests a sandbox permission (camera, microphone, geolocation, clipboardWrite).
The host stops granting this browser capability to the template. Confirm the template detects its absence instead of failing.
#resource.ui.widgetDescription.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
openai/widgetDescription changed. ChatGPT puts it in the model's context when the template loads.
ChatGPT puts this summary in the model's context when the template loads. Re-run any evaluation that depends on how the model talks about the UI.
#Prompts
#prompt.added
Default severity: NON_BREAKING
A new prompt.
#prompt.argument.added
Default severity: NON_BREAKING
A new optional argument.
#prompt.argument.addedRequired
Default severity: BREAKING
A new required argument.
Every existing invocation omits it. Add it as optional first.
#prompt.argument.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
—
#prompt.argument.nowOptional
Default severity: NON_BREAKING
Required → optional.
#prompt.argument.nowRequired
Default severity: BREAKING
Optional → required.
Accept invocations that omit it for at least one release.
#prompt.argument.removed
Default severity: BREAKING
An argument is gone.
Accept and ignore the argument for one release, then remove it.
#prompt.description.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
—
#prompt.removed
Default severity: BREAKING
A prompt is gone.
Clients invoking this prompt by name will start getting errors.
#prompt.title.changed
Default severity: DOCUMENTATION or POTENTIALLY_BREAKING
—
#Severities
| Severity | Means | CI default |
|---|---|---|
BREAKING | A correct existing caller can stop working. | fail |
POTENTIALLY_BREAKING | Behaviour or model-visible semantics changed. | warn |
NON_BREAKING | Strictly additive or widening. | pass |
DOCUMENTATION | Prose changed too little to plausibly move a model. | pass |
Severity is assigned by pure code. No model participates in it.