鉄道駅LOD MCPサーバー
by uedayou
README.md
# 鉄道駅LOD MCPサーバー
[](https://github.com/uedayou/jrslod-mcp-server/actions/workflows/test.yml)
[](LICENSE)
日本の鉄道の**事業者・路線・駅**を検索し、位置情報(駅=ポイント / 路線=ポリライン、GeoJSON)・**営業キロ**・**乗降客数(1 日あたり、2011〜2024年度)**・乗換/隣接駅・簡易経路を取得できる、ローカル実行(stdio)の MCP サーバーです。データソースは [鉄道駅LOD](https://uedayou.net/jrslod/)(認証不要・オープンライセンス、CC BY-SA 4.0)。
Claude Desktop / Claude Code などの MCP 対応クライアントから、次のようなことができます:
- 駅・路線・事業者のラベル/別名検索(`JR東日本`⇔`東日本旅客鉄道`、`〜本線`⇔`〜線` を自動吸収)
- 駅のポイント / 路線のポリライン(分岐線を含む)を GeoJSON で取得(地図表示向け)
- 事業者 → 路線 → 駅 のドリルダウン、路線の駅一覧(データ上の順序)
- 緯度経度からの最寄り駅検索(逆ジオコーディング、駅の geohash を利用)
- 路線の**全長算出**(形状ポリラインからの実測長 + 公表営業キロ、乖離の理由注記つき)
- 駅の**乗降客数(1 日あたり)の年度推移**(2011〜2024)
- 静的な路線図(隣接駅・乗換駅)上の**簡易経路探索**(乗換/駅数最小。時刻表・所要時間・直通運転は非考慮)
## Tools
| Tool | 概要 |
|---|---|
| `search_railway` | 駅・路線・事業者をラベル/別名で検索(`kind` で種別絞り込み) |
| `get_railway_geometry` | 駅(ポイント)/ 路線(ポリライン)を GeoJSON Feature で取得。`simplify` で座標点数を間引ける |
| `get_railway_geometries` | 複数の駅・路線をまとめて 1 つの FeatureCollection で(最大 50 件、地図表示向け) |
| `save_railway_geometries_to_file` | 同上をローカルファイルへ直接書き出し(応答サイズ上限の回避。出典・ライセンスを注記) |
| `list_railway_children` | 事業者 → 路線 / 路線 → 駅 の一覧(`wdt:P527`) |
| `list_stations_on_line` | 路線の全駅をデータ上の順序で一覧(`dcterms:relation` グループ。分岐は区間を連結) |
| `find_nearest_stations` | 緯度経度から最寄り駅(駅の 7 桁 geohash プレフィックスで絞り、セル中心までの距離でランキング) |
| `list_railway_operators` | 鉄道事業者(約 176)の名称一覧 |
| `get_railway_line_lengths` | 路線の全長を算出(実測長 + 公表営業キロ `wdt:P2043`、乖離が大きい場合は `operator-segment` / `includes-branches` 注記) |
| `get_station_passengers` | 駅の乗降客数(1 日あたり)の年度推移(2011〜2024、最大 50 駅をまとめて取得。出典・集計注記つき。補正推定値があれば `estimate` に併記) |
| `find_rail_network_path` | 駅ネットワーク上の経路(乗換/駅数最小)。**時刻表・所要時間・最速・列車種別・直通運転は非考慮**。信頼性注記(`reliability`)と検証用の元データ URL(`evidence`)つき |
## 制約と注意点
- 駅はポイント、路線はポリラインとして持ちます(路線は分岐線を含む複数本になることがあります)。
- `get_railway_line_lengths` の実測長は国土数値情報 鉄道データの軌道中心線の幾何長です。鉄道各社の営業キロとは定義が異なり数%〜数十%ずれます(JR 各社が区間ごとに分けて持つ路線では担当区間のみ、支線・貨物短絡線を含む、球近似の積算のため)。
- `find_rail_network_path` は時刻表を持ちません。答えられるのは「どの路線でどこを経由するか(最小乗換 / 最小駅数)」までです。直通運転(副都心線⇔東急東横線 等)は辺として存在せず乗換回数を過大に数えます。運行系統(湘南新宿ライン・快速等)は路線として存在しません。
- 乗降客数は国土数値情報 駅別乗降客数データ(2011〜2024 年度)由来の **1 日あたりの値(人/日)** です。各鉄道事業者が独自に算出した値で、統一的な基準に基づくものではありません(事業者をまたいだ比較には注意)。
- 記載誤りの可能性がある値には、原本とは別に**補正推定値**(前後年度と同路線の他駅の増減から推定。国・鉄道事業者の公表値ではない)が付くことがあります。`get_station_passengers` は常に原本を `value` で返し、補正推定値は `estimate` に併記するだけです。推定値を使うかどうかはユーザーに確認します。
## 必要環境
- Node.js 18.17 以上
## セットアップ
```bash
npm install
npm run dev # tsx watch でホットリロード起動(stdio)
```
## Claude Code への登録
プロジェクト直下の `.mcp.json` に登録済みです。このリポジトリを Claude Code で開くと自動的に検出されます。
## Claude Desktop への登録
事前にビルドします:
```bash
npm run build
```
`claude_desktop_config.json` に以下を追加します(`args` のパスは実際にリポジトリを配置した絶対パスに):
```json
{
"mcpServers": {
"jrslod-mcp-server": {
"command": "node",
"args": ["/path/to/jrslod-mcp-server/dist/index.js"]
}
}
}
```
Windows はパス区切りを `\\` でエスケープします(例: `"C:\\path\\to\\jrslod-mcp-server\\dist\\index.js"`)。
> **Tips**: プロンプトに「**鉄道駅LOD MCPサーバーを使って**」のようにサーバー名を明示すると、確実にこのサーバーの Tool が呼ばれます。
## 使い方の例
エンティティの指定は **URI**(`https://uedayou.net/jrslod/東日本旅客鉄道/山手線`)でも **「会社名/路線名(/駅名)」**(`東日本旅客鉄道/山手線`)でも、多くの場合**名前だけ**でも通ります。`JR東日本`⇔`東日本旅客鉄道`、`東京メトロ`⇔`東京地下鉄`、`〜本線`⇔`〜線` の揺れは自動補完されます。各例の末尾に、利用が想定される Tool を示します(実際にどれを呼ぶかは LLM の判断によります)。
> **「鉄道事業者を全部挙げて」**
- `list_railway_operators()`(パラメータなし)→ 約 176 事業者の名称配列。手で列挙して漏らさないための一覧
- 想定される Tool: `list_railway_operators`
> **「"みなとみらい" を含む駅を探して」 / 「路線の中から "本線" を検索して」**
- `search_railway(query:"みなとみらい")` → ラベルと別名(略称・旧称等)の部分一致で `[{uri, label, kind}]`。`kind` は `station` / `line` / `operator`
- `search_railway(query:"本線", kind:"line")` のように `kind` で種別を絞れる(`limit` 既定 20、最大 100)。得られた `uri` を以降の Tool に渡す
- 想定される Tool: `search_railway`
> **「近鉄の路線を全部挙げて」 / 「鶴見線の所属駅は?」**
- `list_railway_children(parent:"近畿日本鉄道")` → 所属路線の `[{uri, label}]`
- `list_railway_children(parent:"東日本旅客鉄道/鶴見線")` → 所属駅の `[{uri, label}]`(順序は不定)。順番に並べたいときは次の例の `list_stations_on_line` を使う
- 想定される Tool: `list_railway_children`
> **「山手線の駅を順番に全部」 / 「鶴見線の駅を順番に」**
- `list_stations_on_line(line:"東日本旅客鉄道/山手線")` → 30 駅をデータ上の順序(`東京`→`有楽町`→`新橋`→…)で
- `list_stations_on_line(line:"東日本旅客鉄道/鶴見線")` → 13 駅。**分岐線(海芝浦支線・大川支線)は区間ごとの順序を連結**し、「3 区間(分岐)ぶんの順序を連結」と注記される
- 想定される Tool: `list_stations_on_line`
> **「渋谷駅の位置と、乗換路線・隣の駅・乗降客数を教えて」**
- `search_railway(query:"渋谷", kind:"station")` で `uri` を選ぶ → `get_railway_geometry(address:<uri>)`
- 返り値の GeoJSON Feature の `geometry` は駅の代表点(`Point`、座標は `[経度, 緯度]`)。`properties` に `operator`、`belongsToLine`、`lineColor`、`transferStations`(乗換駅)、`adjacentStations`(隣接駅、`left`/`right`)が入る
- 乗降客数は `get_station_passengers(stations:[<uri>])` で取得する(GeoJSON には含めない。補正推定値の注記を `get_station_passengers` 側で返すため)
- 想定される Tool: `search_railway` → `get_railway_geometry` → `get_station_passengers`
> **「新宿駅で乗り換えられる路線を全部教えて」**
- `get_railway_geometry(address:"東日本旅客鉄道/山手線/新宿")` → `properties.transferStations` に乗換先の駅 URI 配列(`wdt:P833`)。各 URI の 2 番目のセグメントが乗換路線名(中央線 / 小田急小田原線 / 京王線 / 都営地下鉄新宿線 / 東京メトロ丸ノ内線 / 都営地下鉄大江戸線 …)
- **他社線も、駅名の違う徒歩連絡も含む**(新宿 ⇔ `都営地下鉄大江戸線/新宿西口`、⇔ `西武新宿線/西武新宿`)
- 想定される Tool: `get_railway_geometry`
> **「渋谷駅の隣の駅は? / 山手線を渋谷から 1 駅ずつたどって」**
- `get_railway_geometry(address:"東日本旅客鉄道/山手線/渋谷")` → `properties.adjacentStations` に `[{direction:"left", station:".../原宿"}, {direction:"right", station:".../恵比寿"}]`(`wdt:P197`。同一路線の前後の駅、`left`/`right` は路線に沿った方向)
- 返ってきた駅 URI で再度 `get_railway_geometry` を呼べば 1 駅ずつ連鎖できる。路線の全駅を一気に順序どおり欲しいときは `list_stations_on_line` を使う
- 想定される Tool: `get_railway_geometry`(全駅なら `list_stations_on_line`)
> **「大阪環状線の形をそのまま地図に描きたい」**
- `get_railway_geometry(address:"西日本旅客鉄道/大阪環状線")` → `geometry` は複数パーツからなる `MultiLineString`。`properties` に `lineColor`(ラインカラー hex、大阪環状線なら `E80000`)・`publishedLengthKm`(営業キロ、`21.7`)
- 長大路線は `simplify:"low"|"medium"|"high"` で座標点数を間引ける(既定 `none`)。戻り値は標準 GeoJSON なので Leaflet の `L.geoJSON()` / MapLibre GL JS / deck.gl にそのまま渡せる
- 想定される Tool: `get_railway_geometry`

<sub>Claude Desktop で「大阪環状線の形をそのまま地図に描きたい」と入力して生成された作図例。本 MCP サーバー経由で `get_railway_geometry` が返した `MultiLineString`(路線)と駅ポイントを使用。線形・駅位置・ラインカラー・営業キロは鉄道駅LOD による。</sub>
> **「東京メトロの全路線を 1 枚の地図に」**
- `list_railway_children(parent:"東京地下鉄")` で路線 `uri` を取得 → `get_railway_geometries(addresses:[...], simplify:"medium")` で 1 つの GeoJSON `FeatureCollection`(最大 50 件)
- 一部が解決できなくても全体は失敗にせず、`features` から除外して `unresolved` として注記(全件失敗のときだけ `isError`)
- 想定される Tool: `list_railway_children` → `get_railway_geometries`

<sub>Claude Desktop で「東京メトロの全路線を 1 枚の地図に」と入力して生成された地図。`list_railway_children(parent:"東京地下鉄")` で路線一覧を取得し、`get_railway_geometries` が返した `FeatureCollection` を Leaflet で描画。線形・ラインカラーは鉄道駅LOD、ベースマップは OpenStreetMap。</sub>
> **「JR東日本の全在来線のポリラインを 1 つの GeoJSON ファイルにエクスポートして」**
- `list_railway_children(parent:"東日本旅客鉄道")` → `save_railway_geometries_to_file(addresses:[...], outputPath:"jre-lines.geojson")` → ローカルファイルへ直接書き出し、パス・概要・出典(CC BY-SA)だけを返す
- **中身は会話に返らない**ので、Claude 自身がその場で地図を描く依頼では使わず `get_railway_geometries` を使うこと
- 想定される Tool: `list_railway_children` → `save_railway_geometries_to_file`
> **「緯度 35.6812, 経度 139.7671 の最寄り駅は?」**
- `find_nearest_stations(lat:35.6812, long:139.7671, limit:5)` → 距離順に `[{uri, name, line, approxKm}]`
- `approxKm` は駅の 7 桁 geohash セル中心までの近似(±0.1km 程度)。厳密な位置が要るなら `uri` を `get_railway_geometry` に渡す。会社・路線ごとに別エンティティのため同一物理駅が複数返ることがある
- 想定される Tool: `find_nearest_stations`(必要なら → `get_railway_geometry`)
> **「大糸線は全体で何 km? JR東日本と JR西日本の担当区間は?」 / 「JR九州で営業キロが長い在来線トップ 5」**
- `get_railway_line_lengths(routes:["東日本旅客鉄道/大糸線", "西日本旅客鉄道/大糸線"])` → JR東 約 70.5km / JR西 約 35.5km(合計 ≈ 全線)、各行に `publishedLengthKm: 105.4`(全線の営業キロ)と `lengthNote:"operator-segment"`(= 実測は担当区間のみ)
- トップ 5 は `list_railway_children(parent:"九州旅客鉄道")` → `get_railway_line_lengths(routes:[...])`(最大 50 件)で比較
- **実測長は軌道中心線の幾何長**で営業キロと数%〜数十%ずれる。支線・貨物短絡線を含む路線は実測 > 営業キロで `lengthNote:"includes-branches"`。駅を渡すと「路線ではない」として除外
- 想定される Tool: `get_railway_line_lengths`(トップ 5 は + `list_railway_children`)
> **「渋谷駅の乗降客数はこの 10 年でどう変わった?」**
- `get_station_passengers(stations:["東日本旅客鉄道/山手線/渋谷"])` → `[{uri, name, line, series:[{year, value, note, estimate?}], latest}]`。`value` は 1 日あたりの乗降客数(人/日)。2011〜2024 年度(コロナ禍の落ち込みが見える)。`note` は集計対象の但し書き(他路線を含む 等)、出典も注記
- 複数の駅は 1 回にまとめて渡せる(最大 50 駅)。例: `list_stations_on_line(line:"西日本旅客鉄道/大阪環状線")` の結果を渡せば環状線の全駅を比較できる。出典・定義・補正推定値の注記は 1 回だけ返る
- 駅名が曖昧なときは会社名・路線名を含めて指定する
- 想定される Tool: `get_station_passengers`
> **「渋谷から浅草へ、乗り換えの少ない行き方」 / 「乗換が増えてもいいので駅数最小で」**
- `find_rail_network_path(from:"渋谷", to:"浅草")` → 東京メトロ銀座線で 1 本(`optimize` 既定 `fewest_transfers`)
- `find_rail_network_path(from:"渋谷", to:"浅草", optimize:"fewest_stops")` で駅数最小(乗換は駅 4 つ相当のペナルティ)。`fastest`(最速)は時刻表が無いため提供しない
- 返り値: `legs`(乗車/乗換の並び)、`totals`(`stops` / `transfers`)、`reliability`(`level` = high/medium/low、`signals`、`advisory`)、各区間の `evidence`(`wdt:P197` / `wdt:P833` の元データ URL)
- **時刻表・所要時間・最速・直通運転は非考慮**。直通運転区間(副都心線⇔東急東横線 等)を含むと `reliability` が下がり、実際は乗換不要の可能性がある旨が `advisory` に出る。運行系統(湘南新宿ライン・快速等)は路線として存在しない
- 想定される Tool: `find_rail_network_path`
> **「渋谷から浅草への乗換が少ない経路を、路線を色分けして地図に描いて」**(乗換なしの例)
- `find_rail_network_path(from:"渋谷", to:"浅草")` → `legs` は 1 本(東京メトロ銀座線・乗換なし・18 駅)。`totals` = 18 駅 / 0 乗換
- 路線名を `get_railway_geometry` に渡し `properties.lineColor`(銀座線 `FF9501`)でポリラインを 1 色描画。`legs` の `evidence` の駅 URI から出発・到着駅と途中駅をマーカーに
- 乗換が無いので色分けは 1 色。乗換があると次の例のように区間ごとに色が変わる
- 想定される Tool: `find_rail_network_path` → `get_railway_geometry`

<sub>`find_rail_network_path(from:"渋谷", to:"浅草")` が返した 1 区間(銀座線)を `get_railway_geometry` の `lineColor` で描画し、`evidence` の駅を Leaflet でマーカー表示。線形・ラインカラー・駅位置は鉄道駅LOD、ベースマップは OpenStreetMap。時刻表・所要時間・直通運転は非考慮。</sub>
> **「中野から押上へ、乗換の少ない経路を路線ごとに色分けして地図に描いて」**(乗換ありの例)
- `find_rail_network_path(from:"中野", to:"押上")` → `legs` = 東京メトロ東西線(中野→大手町・8 駅)/ **大手町で乗換** / 東京メトロ半蔵門線(大手町→押上・6 駅)。`totals` = 14 駅 / 1 乗換、`reliability.level` = high
- `legs` の各 `ride` の路線名を `get_railway_geometry` に渡し、`properties.lineColor`(東西線 `019BBF` / 半蔵門線 `8F75D6`)でポリラインを色分け
- 起点・乗換・到着の**駅**は `evidence` の駅 URI を `get_railway_geometry` に渡し、返る `Point` をマーカーに
- 経由路線は**全形**が返るので、実際に乗る区間(起点〜乗換〜到着)だけ濃い線で強調し、残りは薄く描くと分かりやすい。`reliability.advisory` と `totals` はキャプションへ
- 上の渋谷→浅草の例と違い `legs` が複数になり、区間ごとに `lineColor` が変わる。乗換駅を境に色が切り替わる図になる
- 想定される Tool: `find_rail_network_path` → `get_railway_geometry`(路線ごと・駅ごと)

<sub>`find_rail_network_path(from:"中野", to:"押上")` が返した 2 区間(東西線 → 大手町で乗換 → 半蔵門線)を、各路線の `get_railway_geometry` の `lineColor` で色分けし Leaflet で描画。濃い線が実際に乗る区間、薄い線が路線の全形。線形・ラインカラーは鉄道駅LOD、ベースマップは OpenStreetMap。時刻表・所要時間・直通運転は非考慮。</sub>
## 応用事例:住所LOD MCP サーバーと組み合わせる
鉄道駅LOD MCP サーバーは 1 データセット専用ですが、**[住所LOD MCP サーバー](https://github.com/uedayou/loa-mcp-server)**(日本の行政界・町丁目を扱う [住所LOD](https://uedayou.net/loa/) の MCP サーバー)を同じクライアントで同時に有効化すれば、Claude 側で両者の結果を突き合わせて 1 枚の地図にできます。
> **「住所LOD MCPサーバーと鉄道駅LOD MCPサーバーを利用して、大阪環状線の各駅の平均乗降客数と大阪市の行政区の人口を地図上にビジュアライズしてください。」**
大阪環状線の各駅の平均乗降客数(円の大きさ)と、大阪市の行政区の人口(色の濃さ)を 1 枚に重ねた地図です。鉄道側の路線形状・駅位置・乗降客数を鉄道駅LOD MCP サーバーから、行政区の境界と人口を住所LOD MCP サーバー(人口・世帯数の取得に対応)から取得しています。

<sub>Claude Desktop で上記プロンプトを入力して生成。プロンプトの解釈・データの結合方法・可視化の形式はいずれも Claude 側の判断による。区の人口は住所LOD の値(2020年国勢調査の基本単位区を合算した参考値で、公式統計値とは一致しない場合がある)。出典表記は画像内および各データソース(鉄道駅LOD / 住所LOD / 国土数値情報)に準拠。</sub>
## 開発
```bash
npm run typecheck # tsc --noEmit
npm test # vitest(オフライン、fixture ベース)
npm run build # dist/ へコンパイル
npm run inspector # MCP Inspector で対話的に確認
```
## 元データについて
このサーバーは [鉄道駅LOD](https://uedayou.net/jrslod/) が公開するデータを利用しています。
- **ライセンス**: CC BY-SA 4.0(出典表記 + 継承)
- **データ出典**: 国土数値情報 鉄道データ(N02-25 版)/ 国土数値情報 駅別乗降客数データ(2011〜2024 年度)/ Wikidata / DBpedia 日本語版
最新の状況は [鉄道駅LOD サイト](https://uedayou.net/jrslod/) を参照してください。
## 免責事項
- 本ソフトウェアは現状有姿(as-is)で提供され、開発者はその動作・正確性・可用性についていかなる保証も行いません。
- 本ソフトウェアが問い合わせる [鉄道駅LOD](https://uedayou.net/jrslod/) は無償で公開されている共有サービスです。多数のアクセスが集中した場合や特定利用者からの大量アクセスがあった場合、鉄道駅LOD 側の判断で利用が制限されることがあります。
- 鉄道駅LOD が提供するデータの正確性・完全性・最新性は保証されません。出力の利用にあたっては利用者自身の責任で妥当性を判断してください。
## ライセンス
本ソフトウェア(コード)は [MIT License](LICENSE) のもとで公開しています。利用しているデータ([鉄道駅LOD](https://uedayou.net/jrslod/))のライセンスは上記のとおり別途 CC BY-SA 4.0 です。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues