Skip to main content
Glama

otp-mcp

セルフホストした OpenTripPlanner (OTP) を MCP(Model Context Protocol)サーバー越しに使えるようにするツール。Claude Code や claude.ai から「AからBは電車で何分?」を、自分の手元のOTPが持つ正確な経路データで聞けるようにする。

作った背景

きっかけは、ある公開の経路検索API(MCP付き)を触ったこと。MCP越しに plan_journey を叩いて経路が返ってくる体験はとても便利だった一方、そのAPIは「力技で集めた時刻表のパッチワーク」で、JRの直通・乗継系統(上野東京ライン・京浜東北快速など)を取りこぼし、関東の所要時間を実態の約2倍に誤ることがあった(飲み会場所最適化アプリ arigatai-score の経路エンジン選定の中で実測)。

一方で、自分は arigatai-score 用に 関東全域のOTP(TokyoGTFS + OSM からビルドしたグラフ)を既にセルフホストしている。これは Yahoo!乗換案内とほぼ一致する精度(平均誤差 約3分)を持つ。

だったら「便利なMCPの体験」を「自前OTPの正確なデータ」で実現すればいい——というのがこのツール。

トレードオフはこうなる:

公開API(パッチワーク)

otp-mcp(自前OTP)

カバレッジ

全国だが穴が多い

関東のみ

精度

平均誤差 約17分

平均誤差 約3分

「狭いが正確な経路MCP」を狙ったツール。

Related MCP server: openroute-mcp

設計思想

  • 薄いラッパーに徹する: 経路検索のロジックはOTPに任せ、このサーバーはOTPのGraphQL(planConnection / stops)を叩いて結果を読みやすく整形するだけ。

  • stdio / HTTP 両対応: ローカルの Claude Code は stdio、claude.ai のリモートコネクタは HTTP(Streamable HTTP + 任意のBearer認証)。1つの実装で両方をカバーする。足場は自分がフォークして使っている scrapbox-cosense-mcp の構成を下敷きにした。

  • 経路の見せ方: leg(区間)ごとに「路線名・駅・所要分」を並べ、出発/到着時刻と乗換回数を添える。

提供ツール

  • plan_journey(from, to, numItineraries?) — 経路検索。from/to は駅名(例: 新宿)か "緯度,経度"。ランク付けされたルートを返す。

  • suggest_stations(q, limit?) — 駅名サジェスト。座標付きで返す。

出力例(plan_journey 新宿 渋谷):

新宿 → 渋谷

【ルート1】15:26 → 15:34  所要8分  乗換0回
  🚶 徒歩 4分 → 新宿
  🚃 JR湘南新宿ライン  新宿 → 渋谷  4分
  🚶 徒歩 1分 → 渋谷

前提

経路検索の本体である OTP が動いていて、このサーバーから到達できること。本リポジトリ自体はOTPを含まない。

  • 既定では arigatai-score の docker compose で動くOTP(サービス名 otphttp://otp:8080)を想定

  • 別構成のOTPに繋ぐ場合は OTP_BASE_URL を設定

使い方

Claude Code(ローカル / stdio)

ビルドして、.mcp.json に登録する:

npm install
npm run build
{
  "mcpServers": {
    "otp": {
      "command": "node",
      "args": ["/home/kouki/dev/otp-mcp/build/index.js"],
      "env": { "OTP_BASE_URL": "http://localhost:8080" }
    }
  }
}

OTP_BASE_URL はOTPに到達できるURLにする(OTPのポートをホスト公開している場合は http://localhost:8080 など)。

claude.ai / リモート(HTTP)

Docker Compose で HTTP サーバーとして起動し、Cloudflare Tunnel 等で公開して claude.ai のカスタムコネクタに登録する:

cp .env.example .env   # MCP_AUTH_TOKEN を設定推奨
docker compose up -d --build
  • エンドポイント: https://<公開ホスト>/mcp

  • MCP_AUTH_TOKEN を設定した場合は Authorization: Bearer <token> が必要

  • 既定の compose は arigatai-score の Docker ネットワーク(arigatai-score_internal)に相乗りして http://otp:8080 に到達する

CLI(動作確認用)

node build/index.js plan 新宿 渋谷
node build/index.js suggest 新宿

今後の展望

  • station_departures(発車標)の追加(OTPの stoptimes クエリ)

  • 出発/到着時刻の指定

  • 運賃・乗換回数のメタ情報付与

  • OTPのカバレッジを関東以外へ広げたら、そのまま全国対応に

関連

Available Tools

3 tools
plan_journeyA

Plan a public-transit (rail/subway) journey using a self-hosted OpenTripPlanner instance (self-hosted OTP (Kanto rail/subway)). 'from' and 'to' are each a station name (e.g. "新宿") or a "lat,lon" coordinate. Returns ranked itineraries with per-leg lines (line name, stations, minutes), departure/arrival times, and transfer count. Accurate within the covered area (Kanto); returns no route for places outside coverage.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesDestination: a station name or a "lat,lon" coordinate.
fromYesOrigin: a station name or a "lat,lon" coordinate.
numItinerariesNoNumber of itineraries to return (default 3).

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description adequately discloses that this is a read-only query to a self-hosted OTP instance, returns ranked itineraries with detailed per-leg information, and fails gracefully for out-of-coverage locations. It does not mention any side effects or rate limits, but given the read-only nature, the transparency is sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise (4 sentences) and front-loaded with the core purpose. While a more structured format (e.g., bullet points) could improve readability, the current paragraph is clear and efficient with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description covers the return format (ranked itineraries, per-leg details, times, transfer count) and a failure scenario. It does not address error handling for invalid station names, but for a simple tool with 3 parameters, it is largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains each parameter. The description reiterates that 'from' and 'to' can be station names or coordinates, and mentions the default for 'numItineraries', which is already in the schema. Thus, the description adds minimal value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool plans a public-transit journey using a specific self-hosted OTP instance for the Kanto area. It distinguishes from siblings by focusing on rail/subway journey planning, while 'plan_route_map' likely handles map-based routes and 'suggest_stations' provides station suggestions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for journey planning within Kanto but does not explicitly guide when to use this tool versus alternatives like 'plan_route_map' or 'suggest_stations'. It provides a limitation (covers only Kanto) but no direct comparison or exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

plan_route_mapA

Plan a rail/subway journey and render it as a Yahoo!乗換案内-style vertical timeline (an inline interactive view on claude.ai). The view shows stations, departure/arrival times, line names in their official colors, and transfer points stacked vertically; the same itinerary is also returned as text. 'from' and 'to' are each a station name (e.g. "新宿") or a "lat,lon" coordinate. By default shows the best (fastest) itinerary; use 'routeIndex' to pick another. Prefer this over plan_journey when a visual route is helpful.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesDestination: a station name or a "lat,lon" coordinate.
fromYesOrigin: a station name or a "lat,lon" coordinate.
routeIndexNoWhich itinerary to show, 0 = best/fastest (default 0).

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite no annotations, the description discloses key behaviors: returns both visual timeline and text, shows stations, times, line colors, transfer points, accepts station names or coordinates. It could mention potential limitations like API availability or language support.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and concise, with the main purpose in the first sentence. It avoids redundancy and every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, it adequately explains return format (visual timeline and text) and covers all parameters. Could briefly mention error handling or supported regions, but overall complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so baseline is 3. Description adds meaning by explaining 'from' and 'to' can be station names or 'lat,lon' coordinates, and routeIndex selects itinerary (0=best). This goes beyond the schema's short descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Plan a rail/subway journey and render it as a Yahoo!乗換案内-style vertical timeline' with specific verb-resource pairing and distinguishes from sibling 'plan_journey' by emphasizing the visual output.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises 'Prefer this over plan_journey when a visual route is helpful', providing clear when-to-use guidance. Also explains default best itinerary and routeIndex for alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

suggest_stationsA

Autocomplete station names against the self-hosted OpenTripPlanner instance (self-hosted OTP (Kanto rail/subway)). Returns matching stations with coordinates. Use to resolve or disambiguate a name before plan_journey.

ParametersJSON Schema
NameRequiredDescriptionDefault
qYesStation name prefix or substring.
limitNoMax results (default 10).

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must cover behavioral traits. It indicates the tool returns matching stations with coordinates and references a specific instance, but does not mention authentication, rate limits, or that it is a read-only operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences. The first sentence delivers the core purpose, and the second provides usage guidance. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple autocomplete tool with only two parameters and no output schema, the description covers the essential aspects: what it does, what it returns, and its intended use case. Minor missing details about error handling or behavior for exact matches.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the description adds context for the 'q' parameter by stating it expects a station name prefix or substring. However, it does not elaborate on the 'limit' parameter beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool autocompletes station names against a specific OTP instance, returns matching stations with coordinates, and is meant to resolve names before using plan_journey. It distinguishes itself from siblings by specifying its role as a preliminary step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises using this tool before plan_journey, providing clear context. However, it does not mention when not to use or alternative approaches for disambiguation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A4.2/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: plan_journey for text itineraries, plan_route_map for visual timelines, and suggest_stations for name resolution. There is no overlap in functionality.

Naming Consistency5/5

All tools follow a verb_noun pattern with consistent prefixes (plan_, suggest_). The naming is predictable and clear.

Tool Count4/5

Three tools is slightly minimal but covers the core workflow: suggest stations, plan text journey, plan visual journey. The scope is focused and each tool earns its place.

Completeness3/5

The core journey planning is covered, but there are notable gaps such as missing tools for station details, line information, or schedule data, which agents might need.

Maintenance

ActivityStale
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ojimpo/otp-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server