vdiff
Breaking-change diffs for npm packages, served over REST and MCP, so coding agents stop writing code against outdated API knowledge.
README
vdiff
A breaking-change diff API for npm packages. Given a package and two versions, it returns a structured, machine-readable list of what actually broke: removed exports, changed function signatures, and removed or changed class and interface members. Each entry includes the before and after signatures plus a short migration note.
Live at https://vdiff-api.onrender.com. Most easily consumed through the MCP server, vdiff-mcp:
claude mcp add vdiff -- npx -y vdiff-mcp
Or call the REST API directly:
curl "https://vdiff-api.onrender.com/v1/diff?ecosystem=npm&package=zod&from=3.24.0&to=4.0.0"
Why this exists
LLMs learn a package's API surface during training, then the package moves on. When a coding agent writes code against zod or express, it writes for the version it remembers, which is often not the version in your lockfile. The result is confident code that calls functions that were renamed or removed two majors ago.
Existing tools only solve part of this. Version lookup tools tell the agent what the current version is. Documentation tools tell it what the docs say today. Neither answers the question the agent actually has mid-edit: "what changed between the version I know and the version installed here?"
vdiff answers exactly that. Diffs are computed from the package's own type declarations rather than changelogs, so the output reflects the real exported surface, and every response carries a confidence score so the consumer knows how much to trust it.
Endpoint reference: docs/api.md.
How it works
- Resolve. Fetch package metadata, versions and dist-tags from the npm registry.
- Extract. For each of the two versions, download the tarball, keep only the
.d.tsfiles, and build a table of public exports (functions, classes, members, normalized call signatures) using the TypeScript compiler API. Bundled declarations are preferred; packages that ship none fall back to the matching DefinitelyTyped@types/*package, version-matched bymajor.minor. - Compare. Diff the two export tables into typed change entries (
export_removed,signature_changed,member_removedand so on), each with before/after signatures and a migration note. - Cache and meter. Results are stored in Postgres keyed on (package, from, to), so each version pair is computed once, ever. Every request is logged with cache-hit status and user agent.
- Guard. Per-IP rate limits, a cap on simultaneous diff computations, size limits on tarballs and extracted declarations, and fetch timeouts keep the service safe to expose publicly.
Diffs are type-level: a runtime behavior change that leaves the types untouched is invisible. Responses using bundled types carry confidence 0.9; responses using community-maintained @types/* declarations carry 0.8.
API overview
| Endpoint | Purpose |
|---|---|
GET /v1/diff |
Breaking-change diff between two versions (from required, to defaults to latest) |
GET /v1/resolve |
Latest version and dist-tags for a package |
GET /healthz |
Liveness check |
See docs/api.md for parameters, response shapes, change types, error codes and rate limits.
Stack
| Layer | Choice | Why |
|---|---|---|
| Runtime | Node 20+, TypeScript | npm-only .d.ts diffing needs the TS compiler API, so one language |
| API | Fastify 5 | Fast, minimal, good TypeScript support |
| Diffing | typescript compiler API |
Structured symbol tables from .d.ts files, the core of the product |
| Database | Postgres 18 (Docker local, Neon prod) | JSONB for variable-shape diff payloads, SQL for billing and analytics |
| Registry | npm registry HTTP API + tar |
Packuments and tarball extraction, declarations only |
| Tests | Vitest | Unit tests for compare logic and @types version matching |
The code is cloud-agnostic: a plain container plus a DATABASE_URL. It currently runs on Render with Neon Postgres.
Running it yourself
docker compose up -d # Postgres 18 on :5432
npm install
npm run db:migrate # apply src/db/schema.sql
npm run dev # API on :3000
Or containerized, the way a PaaS runs it (applies the schema on boot, then serves):
docker build -t vdiff-api .
docker run -p 3000:3000 -e DATABASE_URL="postgres://user:pass@host:5432/db" vdiff-api
Configuration
All configuration is via environment variables:
| Env var | Default | Purpose |
|---|---|---|
PORT |
3000 |
Listen port |
DATABASE_URL |
local Docker Postgres | Postgres connection string |
RATE_LIMIT_DIFF_MAX |
30 |
Per-IP /v1/diff requests per minute |
RATE_LIMIT_RESOLVE_MAX |
120 |
Per-IP /v1/resolve requests per minute |
COMPUTE_CONCURRENCY |
2 |
Max simultaneous diff computations |
TRUST_PROXY |
unset | Set true behind a PaaS proxy so the rate limiter sees real client IPs |
Hardening notes
- Rate limiting: per-IP, in-memory (fine while single-instance).
/healthzis exempt for platform health checks. - Compute cap: at most
COMPUTE_CONCURRENCYuncached diffs compile at once; excess requests get a503withretry-after. Cached diffs are always served. - Size guards: tarball downloads are capped at 50 MB (checked via content-length and counted bytes), extracted declarations at 15 MB per version. Oversized packages fail with a clear
422. - Fetch budgets: 10 s for packuments, 30 s for tarballs. Tarballs are only fetched from
registry.npmjs.orgover HTTPS.
Project layout
src/
index.ts Fastify bootstrap, /healthz
routes.ts /v1/resolve, /v1/diff: validation, cache, dedup, metering
registry/npm.ts packument fetch, tarball download, .d.ts extraction
diff/
symbols.ts .d.ts to symbol table (TS compiler API)
compare.ts symbol table diff to breaking changes
engine.ts orchestration, @types/* fallback, confidence
db/
schema.sql packages, versions, diffs, diff_requests_log
migrate.ts applies schema
mcp/ vdiff-mcp, the MCP server wrapping this API (published to npm)
docs/
api.md endpoint reference, kept current with the code
Tests
npm test # unit tests (Vitest)
npx tsc --noEmit # typecheck
License
The API and diff engine are licensed under the Functional Source License, v1.1, MIT Future License (FSL-1.1-MIT): free to use, read and modify for anything except offering a competing service, and each release automatically becomes MIT two years after publication.
The MCP server wrapper in mcp/ is MIT licensed.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。