Crossref MCP コネクタ v0.1.0
STEP 2068 rei-aios-85 tab 2026-09-16
Crossref REST API を 測定器 として扱う read-only MCP コネクタ。 STEP 2067 の ranking-disagreement viewer で 装置がページ として完成したものを、呼べる道具 へ格上げした land。
系譜 (2 STEP arc)
| STEP | tab | 成果 |
|---|---|---|
| 2067 | rei-aios-6e | cowork Claude session 制作の public/tools/ranking-disagreement/ viewer land + scripts/fetch-journal-metrics.py で Crossref 実データ 11 誌 2,954 本を取得。装置が ページ として完成 |
| 2068 | rei-aios-85 | 装置を 呼べる道具 へ格上げ: 4 tool を露出する MCP コネクタ、MODULE_INFO DRAFT → STEP 1676 8-key 契約準拠、tests 33 → 39 assertion |
4 tool
| tool | 返すもの |
|---|---|
crossref_module_info | 自己記述 (STEP 1676 8-key 契約準拠) と reject 語彙 |
crossref_journal_info | 題名・出版社・分野・ISSN Portal URL |
crossref_journal_metrics | 1 誌の被引用中央値 / 著者中央値 / 最大著者数 / 著者按分被引用 |
crossref_disagreement | 複数誌を 2 指標で別々に順位付けし、ずれだけを返す |
crossref_disagreement は 合計も総合スコアも返さない。
2 指標の合成には重みが要り、その重みを決める根拠が無いため。読みは
moved / max_shift / top3_overlap。
reject 語彙 (7 種、閉じている)
ISSN_NOT_FOUND / WINDOW_EMPTY / NO_AUTHOR_DATA /
SAMPLE_TOO_SMALL / UPSTREAM_UNAVAILABLE /
RATE_LIMITED / BAD_REQUEST
未定義の code で Reject を作ろうとすると ValueError。
「取れなかった」ではなく 「どの ISSN の・どの期間で・何件しか取れず・最低何件必要だったか」 を返す。
MODULE_INFO 契約 (STEP 1676 8-key)
MODULE_INFO は src/aios/self-description-contract/ の
SelfDescriptionContract 8 key に voluntary 準拠:
name— kebab-case identifier:"rei-crossref"version— semver x.y.z:"0.1.0"step— 生誕 STEP:2068purpose— 1 sentence 目的 (≥20 chars)publicApi— 4 tool 名keyConcepts— 4 concept (polite pool / reject 閉語彙 / 2 層 self-test / ずれだけ返す)relatedModules— 4 関連 module (sougou-external-connectors / self-description-contract / ranking-disagreement / fetch-journal-metrics)honestScope— 5 制約 (Crossref citations は少ない / 無作為でない / 単ページ完結条件 / 品質評価でない / read-only)
enumerate.ts は sougou-external-connectors を
evolutionKind: 'function-add' = out-of-scope に分類している。
本 connector が 8-key shape を採用するのは契約からの逸脱ではなく、voluntary conformance
(良い自己記述 discipline なので採用)。verify_module_info() は TypeScript
verifyModuleInfo() の Python 港として core.py に同梱、test 側で
issues == [] = CONFORM を assertion する。
self-test (2 層、装置設計の原則 ②)
| 層 | 種別 | 件数 | 失敗時の意味 |
|---|---|---|---|
| 層 1 | offline fixture (HTTP 注入式) | 39 assertion (33 元 + 6 MODULE_INFO 契約) | コネクタのバグ |
| 層 2 | live (Crossref 実疎通) | 1 assertion (Ann. Math.) | Crossref 側の問題として SKIP (FAIL でない) |
異常系だけでなく 正常系の fixture を必ず含めている (異常系だけだと、常に reject を返す実装が満点を取るため)。
python tests/test_core.py # 39 PASS / 0 FAIL, live PASS
REI_SKIP_LIVE=1 python tests/test_core.py # ネット遮断時も exit 0
land 位置
tools/sougou-external-connectors/
├── external_core.py # 既存 共通コア (v0.2.0)
├── sat_connector.py # SAT 大蔵経
├── philosophy_connector.py # PhilPapers + SEP
├── jp_academic_connector.py # CiNii + J-STAGE
└── rei-crossref-mcp/ # ★ NEW (STEP 2068)
├── README.md
├── rei_crossref/
│ ├── __init__.py
│ ├── core.py # 純粋層 (MCP 依存なし、offline test 可能)
│ └── server.py # 薄い MCP 露出層 (fastmcp 4.x)
└── tests/
└── test_core.py # 2 層 self-test
MCP server 起動 verify (STEP 2068 実測)
MCP SDK 2.0 で FastMCP は別 package (fastmcp) に split された。server.py は from fastmcp import FastMCP を使用。
pip install "mcp[cli]" fastmcp
python -m rei_crossref.server # stdio
実測 environment (rei-aios-85 tab): mcp 2.0.0 + fastmcp 4.0.4 + Python 3.13。
4 tool 全登録確認 + crossref_module_info end-to-end invoke で JSON {ok:true, module:{...}, rejects:{...}} 返却確認。
既知の限界 (honest scope)
- Crossref の被引用数は Scopus / Web of Science より 少なく出る (参照登録が出版社任せ)
- 標本は Crossref が返す先頭
max_papers件で 無作為抽出ではない (戻り値のsamplingに明記) max_papers ≤ 100のとき 1 ページで完結 (rows = min(100, max_papers))- 雑誌の品質ランキングではない。合計・総合スコアは意図的に返さない
- read-only。書き込み・状態保持なし
装置設計の 3 原則 (embed)
- Reject は座標付き — 7 種の閉じた語彙 +
wheredict で「どこで・なぜ」を返す - Self-test を被診断対象から切り離す — HTTP を fetch 関数として注入、偽 fetch で offline test 可能
- 正常系の fixture を必ず含める — 異常系だけだと「常に reject を返す実装」が満点を取る
関連 STEP
- STEP 2067 (rei-aios-6e、 2026-09-16): ranking-disagreement viewer — Crossref 実データを収集した先行 STEP
- STEP 1676 (2026-09-02): SelfDescriptionContract v0.1 pilot — 8-key 契約の起源
- STEP 1662 (2026-09-02): sougou-external-connectors
source_metadata追加 — 出典透明化の起源 - STEP 1657 (2026-09-02): sougou-connectors 446 tools +
learn_path追加