Skip to main content
Glama
README.md
# mcp-deprecate

[![CI](https://github.com/shurugiken/mcp-deprecate/actions/workflows/ci.yml/badge.svg)](https://github.com/shurugiken/mcp-deprecate/actions/workflows/ci.yml)
[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Scan an MCP server for protocol features **deprecated or removed by the [2026-07-28 specification release candidate](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/)**, and get a dated migration checklist.

The 2026-07-28 RC is the largest revision of the Model Context Protocol since launch โ€” it makes the protocol stateless, removes the `initialize` handshake and `Mcp-Session-Id`, and deprecates Roots, Sampling, and Logging. The spec ships the deprecation list as prose with a [12-month feature-lifecycle policy](https://modelcontextprotocol.io/community/feature-lifecycle), but no tooling to find where your code is affected. `mcp-deprecate` is that tooling.

It ships as three surfaces over one rule engine: a **CLI**, a **GitHub Action** CI gate, and an **MCP server**.

## What it flags

Two severities, and the difference matters:

| Severity | Meaning | Examples |
|---|---|---|
| ๐Ÿ”ด **error** | **Removed** in the RC โ€” breaking against a final-spec server | `Mcp-Session-Id`, the `initialize` handshake, `logging/setLevel`, `resources/subscribe`, `tasks/list`, error code `-32002`, server-initiated `sampling/createMessage` (and others โ€” run `mcp-deprecate --list-rules`) |
| ๐ŸŸก **warning** | **Deprecated** โ€” still works, removable no sooner than 12 months out (HTTP+SSE transport is shorter โ€” 3 months after the RC reaches Final) | Roots, Sampling, Logging, the HTTP+SSE transport, `includeContext: "thisServer"/"allServers"` |

It also prints a **manual-review checklist** for changes that have no reliable static signature (e.g. the new required `resultType` field, `server/discover`, `CacheableResult` fields). Every rule cites its originating SEP.

## Install

```bash
npm install -g mcp-deprecate
# or run without installing:
npx mcp-deprecate ./src
```

## 1. CLI

```bash
mcp-deprecate [path] [options]
```

```text
$ mcp-deprecate ./src   # line:column and migration text below are illustrative
...
  ERROR   12:3  initialize / notifications/initialized handshake  [mcp-2575-initialize ยท SEP-2575]
          MCP is now stateless: the initialize / notifications/initialized handshake is removed.
          โ†’ Carry protocol version, client identity, and capabilities in _meta on every request.

Summary: 1 error(s), 0 warning(s) across 1 file(s).
```

| Option | Default | Description |
|---|---|---|
| `-f, --format <fmt>` | `text` | `text`, `md`, or `json` |
| `--fail-on <lvl>` | `error` | Non-zero-exit threshold: `error` (default), `warning` (errors count too), or `none` (always exits 0) |
| `--no-advisories` | | Hide the manual-review checklist |
| `--list-rules` | | Print the full rule table and exit |
| `-v, --version` | | Print version and exit |
| `-h, --help` | | Print this help and exit |

Generate a migration document:

```bash
mcp-deprecate . --format md --fail-on none > MIGRATION.md   # --fail-on none = always exit 0
```

Exit codes: `0` clean ยท `1` findings at/above `--fail-on` ยท `2` usage/scan error.

## 2. GitHub Action

Gate pull requests so no one reintroduces a removed feature:

```yaml
# .github/workflows/mcp-compat.yml
name: MCP compat
on: [pull_request]
jobs:
  mcp-deprecate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shurugiken/mcp-deprecate@v0.1.0 # pin to a released tag
        with:
          path: "src"
          fail-on: "error"   # use "warning" for a strict gate
```

Inputs: `path` (default `.`), `fail-on` (`error`/`warning`/`none`, default `error`), `format` (`text`/`md`/`json`, default `text`), `version` (npm dist-tag or version, default `latest`), `advisories` (`true`/`false`, default `true`).

## 3. MCP server

> **Security:** the server reads any file path its client requests โ€” it has no path allow-list. Connect it only to trusted MCP clients.

Run `mcp-deprecate` itself as an MCP server so an agent can lint other MCP servers:

```json
{
  "mcpServers": {
    "mcp-deprecate": {
      "command": "npx",
      "args": ["-y", "--package", "mcp-deprecate", "mcp-deprecate-server"]
    }
  }
}
```

Tools: `scan_source(path, format?)` (`format` defaults to `md`), `check_spec_compat(path)`, `list_rules()`.

## Library

```ts
import { scanPath, render, summarize } from "mcp-deprecate";

const findings = await scanPath("./src");
console.log(render(findings, { format: "md" }));
console.log(summarize(findings)); // { errors, warnings, total, filesWithFindings }
```

## How it works & limitations

Detection is **signature-based**: distinctive protocol method strings (`logging/setLevel`), headers (`Mcp-Session-Id`), error codes (`-32002`), and official TypeScript SDK schema symbols (`InitializeRequestSchema`). This favors precision over recall โ€” **a clean scan is not a proof of compatibility**, only the absence of known high-signal markers. Scans `.ts/.tsx/.js/.jsx/.mjs/.cjs/.py/.json`.

Known limits: comments are stripped before matching, but only single-line ones โ€” Python triple-quoted docstrings and multi-line JS/TS template literals aren't tracked (tokens mentioned inside them are still matched); method values passed through a variable rather than a string literal, and values split across lines (`includeContext:` with the value on the next line), are not detected; rules keyed to TypeScript SDK symbols (e.g. `InitializeRequestSchema`) won't fire on Python servers or hand-built raw JSON-RPC strings; symlinks to files are followed but symlinked directories are not; an explicitly-passed file over 2 MB errors, and files over 2 MB are skipped during directory walks; the directory walk also skips `node_modules`, `dist`, `build`, `out`, `coverage`, `vendor`, `__pycache__`, and any hidden directory (names starting with `.`, e.g. `.next`, `.turbo`); the programmatic library entrypoint is ESM-only (`require()` works on Node 22.12+; on Node 20 import it as ESM or via dynamic `import()`) โ€” the CLI and GitHub Action are unaffected and run on Node โ‰ฅ20. The MCP server reads whatever path its client asks for, so grant it only to trusted clients.

**Roadmap:** AST-based call-site analysis (ts-morph), deeper Python SDK coverage, and a runtime prober that boots a server and checks advertised capabilities against the RC.

## Sources

- [MCP 2026-07-28 release candidate announcement](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/)
- [Draft specification changelog](https://modelcontextprotocol.io/specification/draft/changelog)
- [Deprecated features registry](https://modelcontextprotocol.io/specification/draft/deprecated)

## License

MIT ยฉ Kwashawn Warren