# MCP schema compatibility: input and output breaking changes

> Learn why accepting a new input enum value preserves callers while returning a new output value can break them, with reproducible MCP contract diffs.

**MCP input and output schemas have opposite compatibility directions.** A server
can usually accept more inputs without invalidating old calls. Returning more
possible outputs can break consumers that relied on the old result contract.
Checking whether a JSON Schema changed is not enough: you must check which side
of the call it describes.

## Is adding an enum value a breaking change?

Suppose a tool accepts or returns a `status` property:

```json
{ "type": "string", "enum": ["open", "closed"] }
```

The next release adds `archived`:

```json
{ "type": "string", "enum": ["open", "closed", "archived"] }
```

| Where this schema appears | Effect on an existing caller                               | Engine rule                | Severity     |
| ------------------------- | ---------------------------------------------------------- | -------------------------- | ------------ |
| `inputSchema`             | Every previously accepted value remains accepted.          | `tool.input.enum.widened`  | NON_BREAKING |
| `outputSchema`            | A result can now contain a value the caller never handled. | `tool.output.enum.widened` | BREAKING     |

This verdict concerns the declared contract. It does not prove that a handler
implements the declaration correctly. See both complete tool definitions and
engine findings in the [account-free example lab](/examples#widen-input-enum).
Its normalized before/after snapshots and JSON findings are downloadable.

## Is making an argument required a breaking change?

Yes, when an existing input property changes from optional to required. A call
that omits the property used to validate and now fails.

For a `search` tool with `query` and `limit`, changing `required: ["query"]` to
`required: ["query", "limit"]` emits `tool.input.required.added` at `BREAKING`.
Adding an entirely new required input property is also breaking. Keeping an
existing default during migration lets callers adopt the property before it
becomes mandatory. [Inspect the exact example](/examples#required-input).

Other common input changes include removing a tool or property, narrowing an
enum, tightening a numeric bound, or disallowing additional properties. Read the
[generated rule reference](/docs/rules) for their individual rules and migration
hints; not every keyword has the same behavior.

## What about output properties?

Consumers rely on the shape the server promised. Removing a guaranteed output
property or making it optional can invalidate that assumption. An output schema
is a declaration for structured results; a comparison cannot verify results the
server actually returns. Keep handler tests that exercise those results.

The MCP specification describes [tool schemas and structured content](https://modelcontextprotocol.io/specification/2026-07-28/server/tools).
The compatibility severities and stable rule ids here are MCP Inspect's product
rules, rather than severities assigned by the protocol specification.

## What happens with unknown JSON Schema keywords?

If a changed keyword is not modeled by the engine, the finding is `BREAKING`.
It does not silently become an additive change. Review the keyword's semantics
and the raw declarations before approving an exception. This conservative rule
keeps an unrecognized constraint from producing a misleading clean check.

## Compare your server before shipping

For a public HTTP endpoint, [create a hosted account](https://app.mcprobe.dev/signup),
add its final MCP URL, and capture a baseline. After deploying a candidate to
that endpoint, choose **Capture again** and review Changes. This tracks endpoint
history; it cannot block a release that already happened.

For a check before merge, the [CLI](/docs/cli) and [CI Action](/docs/github-action)
compare captured contracts with the same engine. These currently require
approved preview builds; public package releases are pending. The npm package
named `mcp-inspect` belongs to another project.

Schema compatibility is only one part of the contract. Continue with
[description and annotation changes](/docs/mcp-tool-description-changes) or
[monitoring a third-party server](/docs/monitor-mcp-server-changes).
