---
title: MCP Server
description: Model Context Protocol server for @specdiff/mcp: expose breaking-change detection to coding agents over stdio.
url: https://pr-1-b9e16090e83d.thally.app/specdiff/mcp
---

# MCP Server

Model Context Protocol server for @specdiff/mcp: expose breaking-change detection to coding agents over stdio.

## Installation

The `@specdiff/mcp` package provides a stdio-based MCP server that exposes Specdiff's breaking-change detection as four tools any MCP-compatible client can call.

No separate install step is needed. Configure your MCP client to launch the server with `npx`.

Requires Node.js 22 or later.

### Claude Code (`.mcp.json`)

Add the following to your project's `.mcp.json`:

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

### Claude Desktop (`claude_desktop_config.json`)

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

The server binary is `specdiff-mcp`. When started, it connects over stdio and logs `"specdiff-mcp listening on stdio"` to stderr.

## Tools

The server registers four tools. All results are returned as text content carrying JSON (or a formatted report string for `specdiff_format`). Failures return `isError: true` with a descriptive message.

### `specdiff_compare`

Compare two JSON Schema or OpenAPI 3.x documents and classify every change.

**Input fields:**

| Field | Type | Required | Description |
|---|---|---|---|
| `beforePath` | string | no | Path to the before document (JSON or YAML), relative to the server working directory |
| `afterPath` | string | no | Path to the after document (JSON or YAML), relative to the server working directory |
| `before` | string | no | Inline text of the before document (JSON or YAML); used when `beforePath` is omitted |
| `after` | string | no | Inline text of the after document (JSON or YAML); used when `afterPath` is omitted |
| `kind` | string | no | `"auto"`, `"openapi"`, or `"json-schema"`. Default: `"auto"` |
| `failOn` | string | no | `"breaking"`, `"warning"`, `"info"`, or `"none"`. Default: `"breaking"` |
| `ignoreRules` | string array | no | Rule codes to drop from the result |

For each side (before and after), provide either a file path or inline text. Providing neither is an error.

**Return shape:**

The result is a JSON object containing all fields of a `DiffResult` plus two additional fields:

- `passed` (boolean) -- `false` when a change meets or exceeds the `failOn` threshold
- `failOn` (string) -- the threshold that was applied

The `DiffResult` portion includes `changes` (array of `SchemaChange` objects with `code`, `severity`, `path`, `message`, and optional `before`/`after` values), `summary` (counts by severity), `maxSeverity`, and `kind`.

### `specdiff_explain_rule`

Look up a single rule by its code.

**Input:**

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | string | yes | The rule code to explain (for example, `"endpoint-removed"`) |

**Return:**

A JSON `RuleInfo` object with `code`, `defaultSeverity`, `title`, `description`, `remediation`, and `appliesTo`.

Returns an error if the code is not recognised, with the message: `"No rule named \"...\". Call specdiff_list_rules for the catalogue."`

### `specdiff_list_rules`

Return the full 45-rule catalogue.

**Input:** none.

**Return:** a JSON array of `RuleInfo` objects.

### `specdiff_format`

Render a `DiffResult` as human-readable text or Markdown.

**Input:**

| Field | Type | Required | Description |
|---|---|---|---|
| `result` | object | yes | A `DiffResult` object as returned by `specdiff_compare` |
| `format` | string | yes | `"text"` or `"markdown"` |

**Return:** the formatted report as a plain text string.

## Path security

All file paths provided to `specdiff_compare` are resolved against the server's working directory (the directory from which `specdiff-mcp` was launched). Any path that resolves outside that directory is rejected before the file system is touched. This keeps the server confined to the project tree.

For example, a `beforePath` of `"../../etc/passwd"` will produce an error rather than reading the file.

## Programmatic usage

Import `createSpecdiffServer` to embed the MCP server in your own process. It returns an un-connected `McpServer` instance from `@modelcontextprotocol/sdk`; you attach whichever transport you need.

```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());
```

### Exported functions

- `createSpecdiffServer(options?)` -- creates and returns an `McpServer` with all four Specdiff tools registered. Accepts an optional `SpecdiffServerOptions` object.
- `resolveInsideCwd(cwd, filePath)` -- resolves a path against `cwd` and throws an `Error` if the result escapes the directory.
- `parseDocumentText(text, fileName?)` -- parses text as JSON or YAML using the file extension as a hint. The `fileName` parameter defaults to `""`, in which case JSON is tried first with a YAML fallback.

### Exported constants

- `TOOL_NAMES` -- object mapping logical names to the registered tool name strings:

```json
{
  "compare": "specdiff_compare",
  "explainRule": "specdiff_explain_rule",
  "listRules": "specdiff_list_rules",
  "format": "specdiff_format"
}
```

### Exported types

- `SpecdiffServerOptions` -- configuration for `createSpecdiffServer`, with an optional `cwd` field (defaults to `process.cwd()`)