tsugime
tsugime is an MCP server that declares expected correspondences between tools (like index files and actual files) and checks them. It reports any mismatches, never modifying anything.
README
tsugime(継ぎ目)
道具どうしの継ぎ目に、成り立っているべき対応関係を宣言しておく。ずれたら教えてもらう。
MCP サーバです。English
規則 5 件 — 一致 4 / ずれ 1 / 読めず 0 ずれた項目 1 件
[skills-no-ghosts] INDEX.md の skill に実体がある
実体 41 件 / 実体 40 件 — 左のすべてが右に現れる
✗ 実体 に無い 1 件:
blender-web-pipeline (C:\Users\USER\.agents\skills\INDEX.md:362 にはある)
» 実体の無い項目は、消した skill の残骸
何のためのものか
道具が増えると、同じことを 2 箇所に書く状態が必ずできます。
- 記憶ファイルの実体と、それを読み込むための索引
- リポジトリと、README に並べたリポジトリ一覧
- 出荷した商品と、商品ページ
- タスクと、それを指しているノート
そして片方だけが更新されます。壊れないので気づきません。 索引に載っていない ファイルは、消えたわけではなく、ただ読まれなくなるだけです。
tsugime は、その対応関係を先に宣言しておき、今ずれているものを答えます。
既にあるものとの違い
MCP サーバは 2,000 本以上あります。そのほとんどは 実行する側 です。 Zapier も n8n もゲートウェイの類も「A が起きたら B をやれ」という命令形です。
tsugime は実行しません。一致しているかを見るだけです。
この考え方自体は新しくありません。インフラの世界では確立しています——
Terraform の plan、ArgoCD や Flux の drift detection。宣言した状態と実際の状態を
比べ続けて、ずれを出す。それを「手元の道具どうしの継ぎ目」に持ってきたものが
無かったので、作りました。
AI に何をさせるか
読み出しと差分は 決定的 です。ここに推測は入りません。同じ入力なら同じ出力で、 出どころ(パスと行番号)が必ず付きます。報告を鵜呑みにせず、その場で確かめられます。
曖昧な部分——「このノートとこの issue は同じものを指しているか」——だけを、 ずれを受け取った側(AI)が判断します。
そして tsugime は何も直しません。 索引に無いファイルを消すのか索引に足すのかは、 中身を見ないと決められないからです。自動修復を持たないのは機能不足ではなく、 境界の置き方 です。
使ってみる
1. 入れる
git clone https://github.com/watasisaikou/tsugime.git
cd tsugime
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
2. 継ぎ目を宣言する
tsugime.toml に書きます。1 つの規則が言うのは 3 つだけです——左、右、
どちらがどちらを含むべきか。
[[rule]]
name = "memory-indexed"
title = "すべての記憶ファイルが MEMORY.md から辿れる"
direction = "left_subset_right" # 左のすべてが右に現れるべき
note = "索引に無い記憶は毎セッション読み込まれない。書いた意味が消える"
[rule.left]
kind = "dir" # ディレクトリの中身
path = "~/.claude/projects/xxx/memory"
glob = "*.md"
only = "files"
exclude = ["MEMORY.md"]
[rule.right]
kind = "markdown_links" # Markdown の [題](先) の *先*
path = "~/.claude/projects/xxx/memory/MEMORY.md"
3. 走らせる
MCP を使わずに、そのまま確かめられます。hook や CI から呼ぶのはこちら。
usage: tsugime [-h] [-c CONFIG] [-r RULE] [--strict] [--json] [--limit LIMIT]
宣言した対応関係と実際を突き合わせ、ずれを出す(直さない)
options:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
規則ファイル
-r RULE, --rule RULE この名前の規則だけを見る
--strict ずれ、または読めない規則があれば exit 1
--json 機械が読む形で出す
--limit LIMIT 1 規則あたり表示するずれの上限(既定 20)
.venv\Scripts\python cli.py # 全部の規則を見る
.venv\Scripts\python cli.py --rule memory-indexed # 1 つだけ
.venv\Scripts\python cli.py --strict # ずれがあれば exit 1
-c を省略すると、TSUGIME_CONFIG 環境変数 → ~/.nagi/tsugime.toml →
カレントディレクトリの tsugime.toml → cli.py と同じディレクトリの tsugime.toml、
の順で探します。
終了コードで判断できます:
| exit code | 意味 |
|---|---|
| 0 | ずれなし。--strict を付けていなければ、ずれがあってもここに落ちます |
| 1 | --strict 指定時、ずれ、または読めなかった規則があった |
| 2 | 規則ファイル(tsugime.toml)が無い・壊れている |
CI から使う例(GitHub Actions):
- run: python cli.py --strict
4. Claude Code に繋ぐ
{
"mcpServers": {
"tsugime": {
"command": "C:\\Dev\\tsugime\\.venv\\Scripts\\python.exe",
"args": ["C:\\Dev\\tsugime\\server.py"],
"env": { "TSUGIME_CONFIG": "C:\\Dev\\tsugime\\tsugime.toml" }
}
}
}
読める側(アダプタ)
| 種類 | 何を鍵にするか | 主な指定 |
|---|---|---|
dir |
ディレクトリの中身(ファイル名 / ディレクトリ名) | glob only |
git |
リポジトリ名一覧、または 1 つのリポジトリのリモート URL / タグ名 / ブランチ名(what で選ぶ: repos remotes tags branches) |
what glob |
markdown_links |
[題](先) の 先 |
— |
wikilinks |
[[...]] の中身。ファイルでもディレクトリでも可 |
glob |
headings |
見出し。深さと正規表現で絞れる | level pattern after until |
frontmatter |
各ファイルの frontmatter の 1 項目 | field glob |
json |
JSON の配列 / オブジェクト | pointer field |
http_json |
HTTP GET した JSON の配列 / オブジェクト | url pointer field token_env headers timeout |
sqlite |
SELECT の 1 列目(読み取り専用で開きます) | query |
regex |
行を正規表現で走査した鍵(値も持てる) | pattern key |
git は外部の git コマンドを呼ばず、.git の中を直接読みます
(走る環境によって結果が変わらないように)。
どの側にも正規化を掛けられます: strip_suffix / basename / lower / exclude。
regex の 2 通りの使い方
(a) 鍵は固定、値は捕獲グループ 1:
[rule.left]
kind = "regex"
path = "pyproject.toml"
pattern = 'version\s*=\s*"([^"]+)"'
key = "version"
(b) 名前付きグループ (?P<key>) (?P<value>) で、1 ファイルから複数件:
[rule.right]
kind = "regex"
path = "deployed.env"
pattern = '(?P<key>[A-Z_]+)=(?P<value>.+)'
方向は 4 つです。それぞれ 1 つの問いに答えます。
left_subset_right— 左のすべてが右に現れるかright_subset_left— 右のすべてが左に現れるかequal— 左と右が完全に一致するかvalues_agree— 両側にある鍵について、値が一致するか
値も見る(values_agree)
3 つの方向は「鍵の集合」しか見ません。同じ鍵が両側にあっても、 その値まで一致しているかは見ていませんでした。 バージョン番号が典型例です—— 索引には載っているのに、書いてある値そのものが食い違っている。
values_agree はこの問いに答えます: 両側にある鍵について、値が一致するか。
[[rule]]
name = "version-matches-deploy"
title = "pyproject.toml のバージョンと、デプロイ済みの記録が一致する"
direction = "values_agree"
left_label = "pyproject.toml"
right_label = "デプロイ記録"
note = "デモ: 手元と本番でバージョンがずれている例"
[rule.left]
kind = "regex"
path = "pyproject.toml"
pattern = 'version\s*=\s*"([^"]+)"'
key = "version"
[rule.right]
kind = "regex"
path = "deployed.env"
pattern = "(?P<key>[A-Z_]+)=(?P<value>.+)"
lower = true
規則 1 件 — 一致 0 / ずれ 1 / 読めず 0 ずれた項目 1 件
[version-matches-deploy] pyproject.toml のバージョンと、デプロイ済みの記録が一致する
pyproject.toml 1 件 / デプロイ記録 1 件 — 共通鍵 1 件 — 両側にある鍵について、値が一致する
✗ 値が食い違う 1 件:
version pyproject.toml='1.2.0' (pyproject.toml:3) / デプロイ記録='1.1.0' (deployed.env:1)
» デモ: 手元と本番でバージョンがずれている例
設計上、意図して決めていることが 4 つあります。
- 片側にしか無い鍵は報告しません。 1 つの規則は 1 つの問いに答えます。存在まで見たいなら、
left_subset_rightなどの規則を別に書いてください - どちらが正しいかは tsugime には決められません。 だから両側の値と両側の出どころを そのまま出します。判断は人(か AI)に渡します
- 値を持てない源を
values_agreeに使うとエラーになります。 黙って「全部一致」と 言わせないためです。使えるのはfrontmatter/http_json/json/regex/sqliteだけです - 共通鍵が 0 件でも「一致」とは出ません。 「何も見ていない」ことが件数として必ず出ます (上の出力の「共通鍵 N 件」)
既存のアダプタにも、値を返せるようになったものがあります:
sqlite:queryが 2 列返すと、1 列目が鍵・2 列目が値になります(3 列以上は失敗)json/http_json:pointerの先がオブジェクトなら、キーが鍵・値がそのまま値になります (配列のままなら今どおり値は持ちません)frontmatter:value_fieldを指定すると、fieldの値を鍵にしつつ、value_fieldの値を 値として添えます
秘密の扱い(http_json)
http_json は外部サービスに繋ぐ唯一の入口なので、秘密の扱いだけ切り出して書いておきます。
- 設定ファイルにトークンを直接書かせません。 書くのは環境変数名(
token_env)だけです - その環境変数が無ければ、黙って未認証で投げず、失敗します(401 を「読めなかった」と誤認しないため)
- 失敗メッセージには URL のクエリ文字列以降とトークンの値を含めません
- GET しか送りません。 実装で固定してあり、設定から変える手段はありません
[rule.right]
kind = "http_json"
url = "https://api.github.com/repos/OWNER/REPO/releases"
field = "tag_name"
token_env = "GITHUB_TOKEN" # 値ではなく環境変数名を書く
headers = { Accept = "application/vnd.github+json" }
timeout = 10
MCP のツール
| ツール | 何をするか |
|---|---|
tsugime_rules |
宣言されている対応関係を並べる。まだ読み出さない |
tsugime_check |
突き合わせて、ずれた項目を出どころ付きで返す |
tsugime_explain |
1 つの規則について、左右の鍵を全部並べる |
3 つとも読み取り専用です。書き込むツールはありません。
tsugime_explain は、ずれが腑に落ちないときに使います。たいていは
「鍵の作り方が意図と違う」(拡張子が付いている、大文字小文字、パスかファイル名か)で、
それは左右を並べれば分かります。
作った日に見つかったもの
自分の環境に当てて、最初の実行で 3 件出ました。
記憶ファイルが 2 件、索引に載っていませんでした。
feedback_verify_before_asserting.md と project_idfu_unwired_aws_publisher.md。
どちらも書かれてから一度も読み込まれていませんでした。索引が毎セッション読み込まれる
仕組みなので、索引に無いものは書いた瞬間から存在しないのと同じです。
しかも片方は「確かめずに断言するな」という規律を書き留めたものでした。 それを守るための仕組みが、それ自身を落としていたわけです。
3 件目は、自分の宣言の誤りでした。 INDEX.md:362 の blender-web-pipeline に
実体が無い、と報告されました。消した skill の残骸だと思いました。違いました。
同じ文書の 3 行上にこう書いてありました——「以下は project local
(stg/.agents/skills/) のみ、global には配置しない」。実体は別の場所にあり、
無いのが正しかったのです。書いた規則が、文書の節の違いを見ていなかった。
もし tsugime が自動で直す作りだったら、この行は消えていました。 正しい記載が、 規則の書き手の不注意で失われるところでした。自動修復を持たないのは、 そういう理由です。
規則を直しました——headings に after / until を足して節ごとに見るようにし、
project local 節は別の場所と突き合わせる規則を新しく書きました。
その過程で、宣言を 3 回間違えました(節を分けていない、突き合わせ先のパスが違う、
equal が強すぎる)。そのたびに tsugime が教えてくれました。
規則は一度で正しく書けるものではなく、ずれの報告を読みながら削っていくものです。
分かっている限界
- 鍵の一致は文字列の一致です。 表記ゆれは拾えません。それは受け取った側(AI)の仕事です
values_agreeの値の比較も、文字列化してから行います(str(左) != str(右))。 型が違っても文字列表現が同じなら一致とみなします(例: JSON の数値1と文字列"1")- frontmatter は YAML を解析しません。
名前: 値の行を拾うだけで、入れ子や配列は読めません - 読めなかったものは黙って落とします。 frontmatter が無いファイル、届かない
pointerなどは例外になりますが、「対象が 0 件だった」ことは異常として扱いません。 規則が何も見ていない状態でも「ずれなし」と出ます。件数(left_count/right_count)を 必ず見てください - 直しません。 自動修復はありません
http_jsonの認証はAuthorization: Bearer一形式だけです。 Basic 認証や署名付きヘッダなど、他の認証方式には対応していませんhttp_jsonはページングを追いません。 応答 1 回分だけを見ます。ページ分割された API では、その分だけ鍵が欠けますhttp_jsonは応答をキャッシュしません。 その URL を使う規則の数だけ、毎回リクエストします
ライセンス
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.