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

SeverityMeansCI default
BREAKINGA correct existing caller can stop working.fail
POTENTIALLY_BREAKINGBehaviour or model-visible semantics changed.warn
NON_BREAKINGStrictly additive or widening.pass
DOCUMENTATIONProse changed too little to plausibly move a model.pass

Severity is assigned by pure code. No model participates in it.