Skip to main content
Glama
README.md
# spec-drift-mcp

[English version / 英語版はこちら](README.en.md)

AIコーディングエージェントが、コードを書く**前**・コミットする**前**に、自分の仕事を仕様書と突き合わせて自己チェックできるようにする [MCP](https://modelcontextprotocol.io) サーバーです。

データ構造の「正」を小さなYAML仕様書(SSOT: 唯一の正)として持っておくと、エージェントは Model Context Protocol 経由でこう聞けるようになります:

- 「`Invoice` ってどういう形であるべき?」 → `explain_spec`
- 「今のコード、仕様とズレてない?」 → `check_drift`

返ってくるのは推測ではなく、機械的に検証された答えです — 足りないフィールド、仕様にない余計なフィールド、型の不一致。

## なぜ作ったか

私は業務管理SaaS(約53,000行)を本番運用しています。開発体制はほぼ1人+AIコーディングエージェント。そこで一番痛かった失敗は、下手なコードではなく**静かなズレ(silent drift)**でした。仕様書はAと言っているのに、コードはいつの間にかBというフィールドを生やしていて、誰も気づかないまま本番でデータが欠ける — そういう事故です。

効いた対策は、仕様書を「エージェントが自分で参照でき、採点もされる存在」に変えること。pre-commitフックに組み込んで、ズレたままのコミットを機械的に止める。本リポジトリは、その仕組みからプロジェクト固有のコードを取り除き、単体のMCPサーバーとして切り出したものです。

## インストール

```bash
npm install -g spec-drift-mcp
# またはインストールせずに実行:
npx spec-drift-mcp
```

Node.js 18以上が必要です。

## Claude Code で使う

```bash
claude mcp add spec-drift -- npx -y spec-drift-mcp
```

…または任意のMCPクライアント(Claude Desktop等)に設定で追加:

```json
{
  "mcpServers": {
    "spec-drift": {
      "command": "npx",
      "args": ["-y", "spec-drift-mcp"],
      "env": {
        "SPEC_DRIFT_ROOT": "/absolute/path/to/your/project",
        "SPEC_DRIFT_SPECS": "specs"
      }
    }
  }
}
```

- `SPEC_DRIFT_ROOT` — 各仕様書の `source` パスの基準になるプロジェクトルート(デフォルト: カレントディレクトリ)
- `SPEC_DRIFT_SPECS` — 仕様書の置き場所。ルートからの相対パス(デフォルト: `specs`)

## ツール一覧

| ツール | 何をするか |
| --- | --- |
| `list_specs` | 全エンティティの仕様書と、それが管理するソースシンボルを一覧する |
| `explain_spec` | 1エンティティのフィールドレベルの仕様全文を返す |
| `check_drift` | 仕様書と実際のTypeScriptソースを比較し、すべてのズレを報告する |

## 仕様書のフォーマット

仕様書ディレクトリに、1エンティティ = 1 YAMLファイル:

```yaml
entity: Invoice          # 論理名。explain_spec / check_drift が使う
symbol: Invoice          # 検査対象のTSインターフェース or 型エイリアス(省略時はentityと同じ)
source: src/models/invoice.ts   # ソースファイルへのパス(ルートからの相対)
fields:
  - name: id
    type: string
  - name: amount
    type: number
  - name: issuedAt
    type: string
  - name: paid
    type: boolean
```

「コード側」は [ts-morph](https://ts-morph.com) でTypeScriptソースから直接読み取ります — `symbol` で指名された `interface` またはオブジェクトリテラルの `type` エイリアスが対象です。

## ズレの検出例

リポジトリ同梱の `examples/` では、`Customer` がわざと仕様からズレています。`check_drift` は3種類すべてを検出します:

```jsonc
{
  "ok": false,
  "checked": 2,
  "totalFindings": 3,
  "reports": [
    {
      "entity": "Customer",
      "findings": [
        { "kind": "MISSING_IN_CODE", "field": "email",        "expected": "string" },
        { "kind": "TYPE_MISMATCH",   "field": "creditLimit",  "expected": "number", "actual": "string" },
        { "kind": "EXTRA_IN_CODE",   "field": "emailAddress", "actual": "string" }
      ]
    },
    { "entity": "Invoice", "ok": true, "findings": [] }
  ]
}
```

- `MISSING_IN_CODE` — 仕様書にあるフィールドがコードに無い
- `EXTRA_IN_CODE` — コードにあるフィールドが仕様書に無い
- `TYPE_MISMATCH` — フィールドはあるが型が違う

## CLIとしても使える(pre-commit / CI用)

同じチェックがエージェント無しでも走ります。ズレがあれば非ゼロで終了するので、コミットのゲートにできます:

```bash
spec-drift-mcp check --root . --specs examples/specs
```

```
x Customer (Customer) - 3 drift
    [MISSING_IN_CODE] field 'email' is declared in the spec but missing in Customer
    [TYPE_MISMATCH] field 'creditLimit' should be 'number' but Customer has 'string'
    [EXTRA_IN_CODE] field 'emailAddress' exists in Customer but is not declared in the spec
ok Invoice (Invoice) - in sync

spec-drift: 3 problem(s) across 2 spec(s)
```

`.git/hooks/pre-commit` に入れるなら:

```bash
#!/usr/bin/env sh
npx spec-drift-mcp check || {
  echo "仕様とコードにズレがあります — コードを仕様に合わせてからコミットしてください"
  exit 1
}
```

## 仕組み

```
 YAML仕様書 (SSOT) ─┐
                    ├─►  比較  ─►  検出結果(欠落 / 余剰 / 型不一致)
 TSソース (現実)   ─┘
   ts-morphで読み取り
```

1. `spec.ts` がYAML仕様書を読み込み、検証する(zod)
2. `extract.ts` がts-morphでTypeScriptソースから実際のフィールド構成を読み取る
3. `drift.ts` が両者を突き合わせ、ズレを検出する
4. `server.ts` がそれをMCPとして公開。`cli.ts` が同じものをフック/CI向けに公開

## 開発

```bash
npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest
npm run build       # tsup -> dist/index.js
npm run smoke       # ビルド済みサーバーを実MCPプロトコルで叩いて検証
```

## ライセンス

MIT © 3ii-factory

TDQS

A3.9/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: listing specs, explaining a spec, and checking drift. No overlap or ambiguity.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern with underscores: list_specs, explain_spec, check_drift.

Tool Count4/5

Three tools is minimal but appropriate for the focused domain of spec drift detection. Each tool is essential and well-scoped.

Completeness5/5

The set covers the full workflow: list available specs, get detailed spec, and check for drift. No obvious missing operations for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues