---
title: MCP server
description: Reference for the @specdiff/mcp package, which exposes Specdiff as an MCP server for AI coding agents.
url: https://pr-1-ee19382a0710.thally.app/specdiff/mcp
---

# MCP server

Reference for the @specdiff/mcp package, which exposes Specdiff as an MCP server for AI coding agents.

`@specdiff/mcp` exposes Specdiff as a [Model Context Protocol](https://modelcontextprotocol.io/) server so
AI coding agents can detect breaking changes in JSON Schema and OpenAPI
documents without shelling out to a CLI.

The server registers four tools -- `specdiff_compare`, `specdiff_explain_rule`,
`specdiff_list_rules`, and `specdiff_format` -- over stdio. All tool results are
text content containing JSON (or a rendered report for `specdiff_format`).
Failures are returned as results with `isError: true` and a message rather than
thrown, so agents can read and act on them.

## Setup

Add the server to your MCP client configuration. No global install is needed;
`npx` fetches the package on first use.

### Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "specdiff": {
      "command": "npx",
      "args": ["-y", "@specdiff/mcp"]
    }
  }
}
```

### Claude Code and other MCP clients

Add to `.mcp.json` in your project root:

```json
{
  "mcpServers": {
    "specdiff": {
      "command": "npx",
      "args": ["-y", "@specdiff/mcp"]
    }
  }
}
```

## Tools

### specdiff_compare

Compare two JSON Schema or OpenAPI 3.x documents and detect breaking, warning,
and informational changes.

**Input fields** (all optional via schema validation):

| Field | Type | Description |
|---|---|---|
| `beforePath` | string | Path to the before document (JSON or YAML), relative to the server working directory |
| `afterPath` | string | Path to the after document (JSON or YAML), relative to the server working directory |
| `before` | string | Inline JSON or YAML text for the before document. Used when `beforePath` is omitted |
| `after` | string | Inline JSON or YAML text for the after document. Used when `afterPath` is omitted |
| `kind` | `"auto"`, `"openapi"`, or `"json-schema"` | Force the document kind. Defaults to `"auto"`, which detects from the `openapi` key |
| `failOn` | `"breaking"`, `"warning"`, `"info"`, or `"none"` | Severity threshold used to compute `passed`. Defaults to `"breaking"` |
| `ignoreRules` | string array | Rule codes to drop from the result |

Each side (before and after) requires either a file path or inline text. Provide
`beforePath` or `before`, and `afterPath` or `after`.

**Output:** A `DiffResult` JSON object with two additional fields:

- `passed` (boolean) -- `false` when any change reaches or exceeds the `failOn` threshold.
- `failOn` (string) -- the threshold that was applied.

**Error conditions:**

- Missing both path and inline text for a side returns `isError: true` with
  a message like `"Provide either beforePath or before."`.
- A path that escapes the working directory returns `isError: true` with
  `"Path ... is outside the server's working directory ..."`.
- An unknown rule code in `ignoreRules` returns `isError: true` with
  `"Unknown rule code in ignoreRules: ..."`.

### specdiff_explain_rule

Return the title, default severity, description, and remediation advice for a
single rule.

**Input:**

| Field | Type | Description |
|---|---|---|
| `code` | string | The rule code to look up, such as `"endpoint-removed"` |

**Output:** A `RuleInfo` JSON object with `code`, `defaultSeverity`, `title`,
`description`, `remediation`, and `appliesTo` fields.

Returns `isError: true` with `"No rule named \"...\". Call specdiff_list_rules for the catalogue."` when the code is unknown.

### specdiff_list_rules

Return the full rule catalogue as an array of `RuleInfo` objects. Takes no
input.

**Output:** A JSON array of all 45 rules with `code`, `defaultSeverity`,
`title`, `description`, `remediation`, and `appliesTo` for each.

### specdiff_format

Render a `DiffResult` (as returned by `specdiff_compare`) into a human-readable
report.

**Input:**

| Field | Type | Description |
|---|---|---|
| `result` | DiffResult object | The diff result to format. Extra fields beyond the base schema are preserved |
| `format` | `"text"` or `"markdown"` | Output format. Markdown is suitable for pull request descriptions |

**Output:** The rendered report as plain text.

## Path confinement

All file paths passed to `specdiff_compare` are resolved relative to the
server's working directory (the directory from which `specdiff-mcp` was
launched). If a resolved path falls outside that directory, the tool rejects it
with an error before touching the file system. Launch `specdiff-mcp` from your
project root so document paths resolve correctly.

## Programmatic embedding

You can create and connect the MCP server from your own code instead of using
the `specdiff-mcp` binary:

```ts
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createSpecdiffServer } from "@specdiff/mcp";

const server = createSpecdiffServer({ cwd: process.cwd() });
await server.connect(new StdioServerTransport());
```

`createSpecdiffServer` returns an un-connected `McpServer` instance from
`@modelcontextprotocol/sdk` with all four tools registered. You choose the
transport -- `StdioServerTransport` for stdio, or any other transport the SDK
supports.

## Exported types and constants

The `@specdiff/mcp` package exports the following for programmatic use:

- **`createSpecdiffServer(options?)`** -- creates the MCP server. Accepts a
  `SpecdiffServerOptions` object with an optional `cwd` field (defaults to
  `process.cwd()`).
- **`TOOL_NAMES`** -- a constant object mapping logical names to the registered
  tool strings: `compare` maps to `"specdiff_compare"`, `explainRule` to `"specdiff_explain_rule"`,
  `listRules` to `"specdiff_list_rules"`, and `format` to `"specdiff_format"`.
- **`SpecdiffServerOptions`** -- the options type accepted by
  `createSpecdiffServer`.
- **`resolveInsideCwd(cwd, filePath)`** -- resolves a path inside a directory,
  throwing when it escapes.
- **`parseDocumentText(text, fileName?)`** -- parses JSON or YAML text using the
  file extension as a hint.