Traintrackr について
Traintrackrは、ClaudeやChatGPTなどのMCPクライアントから英国のNational Railを調べるMCPサーバーです。リアルタイム情報と将来の時刻表を組み合わせ、駅の案内や経路計画に対応します。
主な機能
- 01発車時刻、番線、遅延、運休の確認
- 02到着情報と発車案内板の表示
- 03将来日の時刻表の検索
- 04乗り換えを含む経路計画
- 05停車駅と駅名の検索
活用シーン
- 01駅の次の列車を確認
- 02列車の遅延や運休を確認
- 03特定列車の番線を調べる
- 04駅間の経路を計画
MCP 対応
リアルタイムおよび予定列車の検索、経路計画、発車案内板のMCP AppをMCPクライアントに提供します。ホスト型エンドポイントは https://traintrackr.live/mcp です。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://traintrackr.live/mcpclaude mcp add --transport http live-traintrackr-traintracker https://traintrackr.live/mcp{"mcpServers":{"live-traintrackr-traintracker":{"type":"http","url":"https://traintrackr.live/mcp"}}}Cursor で開く{"servers":{"live-traintrackr-traintracker":{"type":"http","url":"https://traintrackr.live/mcp"}}}VS Code で開く{"mcpServers":{"live-traintrackr-traintracker":{"type":"http","url":"https://traintrackr.live/mcp"}}}{"mcpServers":{"live-traintrackr-traintracker":{"serverUrl":"https://traintrackr.live/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
Traintrackr
Claude と ChatGPT が GB(National Rail)の列車について、「Sudbury 行きの次の列車は何時ですか?」「Liverpool Street 発 13:00 の列車は定刻ですか?」「来週土曜日の朝に Cambridge から Sudbury へ行くにはどうすればよいですか?」といった質問に答えられるようにする MCP サーバーです。
公開サービスは traintrackr.live で稼働しています。無料で利用でき、メールアドレスでサインインします。パスワードは不要です。コネクターのアドレスは次のとおりです。
https://traintrackr.live/mcp
使い方
Claude。 Traintrackr は Claude のコネクターディレクトリに掲載されています。claude.ai/directory/traintrackr を開くか、claude.ai で カスタマイズ → コネクター を開き、コネクターの横にある + を選択して、ディレクトリから Traintrackr を見つけます。接続 を選択すると、Claude が Traintrackr のサインインページを開きます。そこでメールアドレスを入力し、送られてきたメールに記載されたリンクを開くか、6 桁のコードを入力します。claude.ai で追加したコネクターは、Claude Desktop とモバイルアプリでも利用できます。アドレスを指定して追加するには、カスタムコネクターを追加 を選択し、名前に Traintrackr と入力して、コネクターのアドレスを貼り付けます。
ChatGPT。 ChatGPT では、Web 上の Plus、Pro、Business、Enterprise、Edu プランで開発者モードを通じて追加します。ワークスペースでは、先に管理者が開発者モードを許可する必要がある場合があります。設定 → セキュリティとログイン → 開発者モード をオンにしてから、chatgpt.com/plugins で + を選択し、名前に Traintrackr と入力して、コネクターのアドレスを貼り付け、OAuth を選択します。上記と同じ方法でメールアドレスを使ってサインインします。新しいチャットで + → 開発者モード を選択し、Traintrackr を選びます。
その後、列車について質問できます。traintrackr.live/docs では、各回答に含まれる情報と利用制限を確認できます。プライバシーポリシー と 利用規約 もサイトに掲載されています。このサーバーは MCP Registry に live.traintrackr/traintracker として登録されています。
この README の残りの部分では、サーバーの仕組みと、自分用に複製して実行する方法について説明します。Claude のデスクトップアプリでは stdio 経由でローカル実行し、HTTP 経由でホストすることもできます(Render へのデプロイ を参照)。時刻表は Postgres に保存されます。
flowchart LR
Claude[Claude] <-->|stdio or HTTP| TT[traintracker]
subgraph Live["Live, next ~2 hours"]
D[Darwin<br/>Rail Data Marketplace]
end
subgraph Timetable["Timetable, any future date"]
NR[Network Rail<br/>SCHEDULE feed] -->|daily download| DB[(Postgres<br/>timetable schema)]
end
TT --> D
TT --> DB
ツール
| ツール | 回答する内容 | データ |
|---|---|---|
find_station | 「どのサドベリーですか?」駅名 ↔ CRS コード | 同梱の駅一覧 |
live_departures | 次の列車、予想時刻、ホーム、遅延、運休 | Darwin。2時間以内に運行する列車が rows より少ない場合は、予定時刻表の列車で補います。設定されていない場合は予定時刻を返し、オフラインの場合はその旨の注記とともに予定時刻を返します |
departure_platform | 「コルチェスター行き13:00発は何番ホームですか?」1本の列車のホーム。live または scheduled のフラグ付き | Darwin(ページ分割)。ライブのホームが発表されるまでは、時刻表の予定ホームを返します |
platform_departures | 「7番ホームから次に出発する列車を3本教えてください」 | departure_platform と同じ |
live_arrivals | 今後約2時間以内に到着する列車 | Darwin の到着列車。件数が少ない場合は予定列車で補います。設定されていない場合は予定時刻を返し、オフラインの場合はその旨の注記とともに予定時刻を返します |
show_board | 「リバプール・ストリートの発車案内を表示してください」ライブの発車または到着情報と同じ内容を、発車案内板として表示します | live_departures および live_arrivals と同じ |
timetable | 任意の日付における駅の予定発車・到着情報 | ローカル時刻表 |
service_details | 1本の列車の全停車駅 | ID を発行したソース |
plan_journey | A地点からB地点までの乗り換えを含む経路(max_changes まで。デフォルトは4回)。ロンドン市内の乗り継ぎも含みます | ローカル時刻表 + Darwin のライブ情報 |
data_status | 設定内容、時刻表の鮮度、不足しているもの。DJANGO_DEBUG=1(自分で実行しているサーバー)の場合は、時刻表のスキーマ、最後の更新エラー、使用した Darwin の利用枠も表示します | — |
privacy_policy | 「私について何を保存していますか?」プライバシーポリシーをテキストとページのアドレスで返します | /privacy ページ |
すべてのツールは駅名または CRS コードを受け付けます。「Sudbury」や「Harrow」など、名前が曖昧な場合は候補を返すため、Claude はどの駅を指しているのか確認できます。
発車案内板
show_board には MCP App が付属しています。MCP Apps に対応したクライアントは、結果を回答の横にパタパタ式の発車案内板として表示します。クライアントは、発車案内板を持つツールを呼び出すたびに案内板を表示するため、このツールは独立しており、案内板を見たいとユーザーが求めた場合にのみ使うよう、アシスタントに指示されています。live_departures と live_arrivals は同じ列車情報を返しますが、案内板は表示しません。MCP Apps に対応していないクライアントでは、show_board の結果も通常どおり表示されます。
案内板は1ページで、apps/rail/ui/board.html にあり、ui://traintracker/board.html というリソースとして提供されます。スタイルとスクリプトはインラインで、外部から読み込むものはありません。クライアントがツールの結果を渡すと、最大12本の列車、駅のお知らせ、データの出典が表示されます。更新を選ぶと、クライアントに同じ引数で show_board を再度呼び出すよう求めます。この呼び出しも他の呼び出しと同様にレート制限の対象になります。システムに動きを減らす設定をしているユーザーにはフラップが動かず、スクリーンリーダーでは列車情報が表として読み上げられます。
自分でコピーを実行する
ここからは、サーバーを自分で実行する方法について説明します。traintrackr.live の公開サービスは、このコードを Render へのデプロイの手順でデプロイしたものです。
アカウントなしで試す(デモモード)
TRAINTRACKER_DEMO=1 を設定すると、アカウントの承認前にすべてのツールを試せます。サーバーは生成されたサンプルデータを使用し、ネットワークリクエストを一切行いません。
- 時刻表: 今日から90日間の、イースト・アングリアとロンドンにある実在の25駅(リバプール・ストリート、ストラトフォード、チェルムズフォード、コルチェスター、イプスウィッチ、ノリッジ、マークス・テイ、サドベリー、ケンブリッジ、キングス・クロスなど)を対象とした、生成済みの SCHEDULE フィードです。日曜日は遅い時間から運行を開始します。実際の時刻表とは別の専用スキーマ(
timetable_demo)に保存され、毎日再構築されます。デモモードでもDATABASE_URLが必要です。 - リアルタイム発着案内: Darwin の出発、到着、列車詳細の応答は、その時刻表をもとにプロセス内で生成されます。約5本に1本の列車が遅延し、25本に1本が運休し、12本に1本で番線が変更されます。同じ日の同じ列車には、常に同じ結果が表示されます。大規模駅(リバプール・ストリート、キングス・クロス、ケンブリッジなど)では、出発の15分前に番線が案内されるため、予定番線へのフォールバックも試せます。
すべての発着案内と経路計画にはデータが生成されたものであることを示す注記が付き、data_status は demo_mode を報告します。デモネットワーク外の駅を指定すると、発着案内は空になります。
"env": { "TRAINTRACKER_DEMO": "1" }
これを Claude デスクトップ設定の traintracker エントリに追加する(Claude デスクトップアプリに追加するを参照)か、.env に TRAINTRACKER_DEMO=1 を設定してください。キーを設定したら、この設定を削除してください。試してみる例:「リバプール・ストリート発の次の列車」、「ケンブリッジからキングス・クロスへの次の列車は何番線ですか?」、「明日の9時にケンブリッジからサドベリーへ行くにはどうすればよいですか?」
必要なアカウント
| # | アカウント | 必要? | 費用 | 提供内容 | 用途 |
|---|---|---|---|---|---|
| 1 | Rail Data Marketplace — Live Departure Board 製品 | はい(リアルタイム時刻の取得に必要) | 無料 | Darwin:National Rail のリアルタイムフィード。次の2時間分の出発案内に、予想時刻、番線、遅延・運休の理由、停車駅、駅のアラートが含まれます。駅の案内表示と同じデータです。 | live_departures、plan_journey のリアルタイム情報 |
| 2 | Network Rail Open Data (NTROD) — SCHEDULE フィード | はい(時刻表と経路計画に必要) | 無料 | Network Rail の計画システムから提供される、GB 全土の旅客列車時刻表全体です。短期的な変更(工事、臨時列車、運休)も、公開後に含まれます。毎日更新されます。 | timetable、plan_journey、tt: ID の service_details、リアルタイムツールのオフライン時の代替 |
| 3 | Rail Data Marketplace — Service Details 製品 | 任意 | 無料 | Darwin の発着案内で確認した列車の、リアルタイムの全停車パターンです。 | darwin: ID の service_details |
| 4 | Rail Data Marketplace — Live Arrival Board 製品 | 任意 | 無料 | Darwin の到着案内です。これがない場合、到着時刻には予定時刻が表示されます。 | live_arrivals |
1. Rail Data Marketplace(Darwin)
- raildata.org.uk でアカウントを作成します。
- 製品カタログで "Live Departure Board"(LDBWS 製品。「Live Fastest Departure Boards」ではありません)を検索して登録します。無料プランの承認は、即時から数日後までかかる場合があります。
- 登録した製品を開き、Specification タブを選択します。Consumer key(シークレットではありません)をコピーして、
DARWIN_API_KEYに設定します。 - このタブに表示されるベース URL が
.env.exampleのDARWIN_DEPARTURES_URLと一致することを確認します。異なる場合は、DARWIN_DEPARTURES_URLに自分の値を設定します(/GetDepBoardWithDetailsより前の部分すべて)。 - (任意) 同じ方法で Service Details と Live Arrival Board にも登録します。各製品にはそれぞれ専用のキーと URL があります。
DARWIN_SERVICE_API_KEY/DARWIN_SERVICE_URLとDARWIN_ARRIVALS_API_KEY/DARWIN_ARRIVALS_URLを設定します。
2. Network Rail オープンデータ(SCHEDULE)
- Network Rail データフィードポータルに登録します。有効化には時間がかかる場合があります。
- サインインし、Static feeds の下に SCHEDULE が表示されていることを確認します。
- ポータルのユーザー名とパスワードを
NR_USERNAMEとNR_PASSWORDに設定します。 - ポータルから提供される full daily extract, all operators, JSON のダウンロードリンクが
.env.exampleのNR_SCHEDULE_URLと異なる場合は、NR_SCHEDULE_URLにそのリンクを設定します。
時刻表が存在しない場合、または26時間より古い場合、サーバーはバックグラウンドでフィードをダウンロードします。サーバー起動時とツール呼び出しごとにこれを確認するため、サーバーを何日も起動したままにしても最新の状態が保たれます。ダウンロードに失敗した場合は古い時刻表を提供し続け、data_status にエラーが表示されます。manage.py refresh_timetable --commit を手動で実行することもできます(コマンドを参照)。Render のように別のジョブで refresh_timetable を実行する場合は、TIMETABLE_AUTO_REFRESH=0 を設定します。
3. Postgres
時刻表は、DATABASE_URL のデータベース内にある1つのスキーマ(デフォルトでは timetable)に保存されます。このロールには、そのデータベースでスキーマを作成する権限が必要です。データベースの所有者にはその権限があります。共有サーバーでは、traintracker 専用のデータベースとロールを作成してください。
CREATE ROLE traintracker LOGIN PASSWORD '…';
CREATE DATABASE traintracker OWNER traintracker;
REVOKE CONNECT ON DATABASE traintracker FROM PUBLIC;
サーバー自体のユーザーではなく、このロールを DATABASE_URL に設定してください。サーバーのユーザーはサーバー上のすべてのデータベースを所有しているため、traintracker に障害が発生すると、ほかのアプリケーションのデータにも影響が及びます。一方、traintracker ロールがアクセスできるのは専用のデータベースだけです。
GB 全域の時刻表には約475 MB(430万件の停車)が必要で、更新中はその約2倍の容量が必要になります。更新には、ダウンロード時間に加えて約40秒かかります。新しい時刻表はステージングスキーマで作成してから名前を変更して切り替えるため、読み取り側が作成途中の時刻表を見ることはありません。また、アドバイザリロックによって、2つの更新が同時に実行されるのを防ぎます。
テーブルは UNLOGGED です。毎日フィードから再構築されるため、先行書き込みログへの記録を省略し、サーバーの WAL やポイントインタイムリカバリ用ストレージを消費しません。その代わり、クラッシュ後に Postgres がテーブルを空にします。次の更新まで、ツールは「No timetable yet」と報告します。
各ソースの使用方法
flowchart TD
Q{What's being asked?}
Q -->|next ~2 hours| L[live_departures / live_arrivals]
Q -->|a future date| T[timetable]
Q -->|A to B| P[plan_journey]
Q -->|one train| S[service_details]
L --> L1{Darwin key?}
L1 -->|yes| Darwin
Darwin -->|error or timeout:<br/>note says Darwin is offline| TT
L1 -->|no| TT[(Timetable<br/>scheduled times, flagged)]
T --> TT
P --> CSA[Connection Scan<br/>over the day's timetable]
CSA --> OV{Today, departing<br/>within 2 hours?}
OV -->|yes| Darwin2[Darwin expected times<br/>+ tight-connection flag]
Darwin2 -.->|offline| Note[Plan note: Darwin offline,<br/>times are scheduled]
S --> ID{ID prefix}
ID -->|darwin:| Darwin3[Darwin Service Details]
ID -->|tt:| TT
| ソース | 最新性 | 対象範囲 | キャッシュ期間 | 知っておくべき制限 |
|---|---|---|---|---|
| Darwin | リアルタイム | 現在 → 2時間後 | 20秒 | Darwin のサービス ID は、列車の運行後すぐに期限切れになります |
| 時刻表(Postgres) | 毎日(Network Rail の公開時刻は約06:00) | 2日前 → 公開済み時刻表の最終日(通常は数か月先) | 次回の再構築まで | 予定時刻のみです。直前の変更はここではなく Darwin に表示されます |
Trainline のリンク
時刻表から取得した列車(timetable、plan_journey、tt: ID を指定した service_details、および予定時刻にフォールバックするライブツール)には、trainline_url が含まれます。これは、停車駅と運行状況を確認できる、その列車の Trainline ページです。URL は <TRAINLINE_LIVE_URL>/departures/<station>/<token> で、token は /callingPattern/<train UID>/<run date> を base64 化したものです。station はページのタイトルにのみ使用されます。発着案内盤の駅、乗車する区間の駅、または列車の始発駅です。
- Darwin の列車にはリンクがありません。Darwin のサービス ID には列車の UID が含まれていないためです。
- Trainline は、独自の駅名をスラッグとして駅を識別します。多くは駅一覧の名前から判別できますが、異なるものは
trainline_slugs.jsonに記載されています。Trainline にライブ発着案内盤がない駅(主に2022年以降に開業した駅)はnullになっています。そのような駅にしか停車しない列車にはリンクがありません。 - Trainline は、これらの URL の仕様を公開していません。URL はライブ発着案内盤から確認し、スラッグは2026年9月にライブページのサイトマップで照合しました。Trainline が知らない列車の場合、駅の発着案内盤が表示されます。
- デモモードでは列車が架空のものなので、リンクはありません。
Darwin の利用枠
無料の Darwin アクセスでは、4 週間の Railway 期間あたり 500 万件のリクエストを利用でき、1 つのサーバーキーですべてのユーザーに対応します。サーバーは Darwin に送信したリクエスト数を集計し、manage.py rail_status と、DJANGO_DEBUG=1 の場合は data_status に合計を表示します(ホストされたサーバーでは、サインインしたユーザー全員に残りの利用枠は表示されません)。
Darwin usage: 412,906 requests in the last 28 days, 8.26% of 5,000,000
- カウント対象: Darwin に送信された各リクエストです。失敗したリクエストも含まれます。20 秒間のキャッシュからボードを返す場合、リクエストは送信されず、カウントもされません。デモモードではカウントされません。
- 期間: 直近 28 日間です。Railway の期間は単純には算出できません(年の初めと終わりでは長さが異なります)。また、ローリングウィンドウが重なる期間より厳しくなることはありません。
- 製品ごと: カウントは Rail Data Marketplace の各製品(
departures、arrivals、service)ごとに保持され、割合は合計を基準に算出されます。利用枠が製品ごとに設定されている場合、この割合は実際の使用量より高くなります。 - 1 日あたりの上限: サーバーが 1 日(英国時間)に Darwin へ送信するリクエストは最大
DARWIN_DAILY_LIMIT件です(デフォルトは 170,000 件。利用枠から算出すると、1 日あたり約 178,000 件です)。上限を超えると、午前 0 時までライブツールは予定時刻を返し、その理由を通知します。サーバーの再起動後も、その日のカウントは引き継がれます。0に設定すると上限は無効になります。 - 警告: 使用量が利用枠の 70% を超えるとログに警告が記録され、90% を超えるともう一度警告が記録されます。それぞれ 1 回ずつ通知され、使用量がしきい値を下回ってから再び超えた場合、またはサーバーがしきい値を超えた状態で再起動した場合にのみ、再度通知されます。
- 保存: 専用スキーマ(
USAGE_SCHEMA)内の小さなテーブルdarwin_requestsに保存されるため、カウントは再起動や時刻表の更新後も維持されます。カウントはメモリに蓄積され、50 件待ちになったとき、または 1 分が経過したとき、さらにシャットダウン時に書き込まれます。サーバーが強制終了された場合、失われるのは最大でその件数までです。書き込みに失敗した場合はログに記録して再試行され、ツール呼び出しが失敗することはありません。60 日より古い行は削除されます。
時刻表に保持されるデータ
SCHEDULE フィードは大規模です(貨物列車を含むすべての列車が含まれます)。インポート時に traintracker は、乗客に必要なデータのみを保持します。
- 乗客向けの種別のみ(列車、代行・時刻表掲載のバス、船舶)。ただし、特定の日に旅客列車の運行を止めることがある上書きレコードと運休レコードを除き、貨物列車と回送列車は除外されます。
- 公開時刻が設定された停車地点のみ。ジャンクションと通過地点は除外されます。
- 2 日以上前に運行期間が終了したスケジュールは除外されます。
そのため、時刻表は作成日の 2 日前から、いずれかのスケジュールが運行する最終日までを対象とします。この範囲外の日付を指定してツールを呼び出すと、その旨が通知されます。
各日付について、列車ごとに Network Rail の優先順位ルールが適用されます。運休(C)が新規(N)より優先され、新規(N)は上書き(O)より、上書き(O)は恒久(P)より優先されます。また、各スケジュールの運行曜日と日付範囲も適用されます。祝日の運行フラグはまだ適用されないため、祝日にはライブボードを確認してください。
旅程の計画
plan_journey は、その日のすべての列車の乗車区間をラウンド方式の Connection Scan で検索します。ラウンド n では、列車を最大 n 本使う場合の最も早い到着時刻を見つけます。これにより、最速の旅程と、乗り換え回数が少ない代わりに時間のかかる選択肢を、max_changes まで一度の検索で取得できます。各出発時刻の直後から検索を繰り返して次の候補を見つけた後、出発・到着・乗り換え回数のすべてで他の候補に劣る選択肢を除外するため、必要以上に早く出発するよう案内されることはありません。結果は到着時刻順に並び、乗り換え回数が最も少ない選択肢は必ず含まれます。
- 最小乗り換え時間: デフォルトでは列車間に 5 分(
MIN_INTERCHANGE_MINUTES)必要です。徒歩/地下鉄の区間には駅への出入り時間がすでに含まれているため、その後に乗り換え時間は追加されません。 - ロンドン横断: 地下鉄は鉄道の時刻表に含まれていないため、ロンドンのターミナル駅(Kings Cross、Liverpool Street、Waterloo など)間の乗り換えは概算されます。徒歩で 0.8 km 未満の場合は徒歩速度に 5 分を加算し、それ以外は地下鉄で約 12 分に 1 km あたり 3.5 分を加算します。「
tube (approx.)」と表示されます。 - リアルタイム情報の重ね合わせ: 今日の出発時刻が 2 時間以内の区間には、Darwin の予想時刻と番線が追加されます。遅延または運休によって乗り換え時間が削られる場合は、徒歩/地下鉄の区間を経由する乗り換えも含め、
connection_at_riskが設定されます。Darwin が停止している場合も、リアルタイム情報なしで旅程は返されます。 - 検索対象は運行日の全体です(早朝に運行する列車も含まれます)。翌朝まで検索は続きません。駅の発着案内には、午前 0 時を過ぎた直後に発車する列車も含まれます。
- 負荷: 旅程の検索では、その日の列車を複数回スキャンします。特定の日付のネットワーク構築には数秒かかり、保持には 100 メガバイトを超えるメモリを使用します。メモリには 2 日分を保持します。時刻表の読み込みと旅程検索はスレッドで実行され、同時実行数は 2 です。順番待ちが 10 秒を超えると、サーバーがビジーであることが通知されます。
インストール
uv、Python 3.14(uv が .python-version からインストールします)、および Postgres データベース(バージョン 13 以降)が必要です。ローカルでデータベースを用意するには、Docker(または OrbStack)を使うのが最も手早い方法です。
docker run -d --name traintracker-pg --restart unless-stopped \
-e POSTGRES_PASSWORD=postgres -p 127.0.0.1:55432:5432 postgres:17
git clone [email protected]:hugorodgerbrown/traintracker.git
cd traintracker
uv sync
cp .env.example .env # fill in your keys and DATABASE_URL (.env is git-ignored)
uv run python manage.py migrate
uv run python manage.py refresh_timetable --commit # first timetable download (a few minutes)
uv run python manage.py rail_status
uv run python manage.py runserver # the site, sign-in and /mcp at localhost:8000
Claude デスクトップアプリに追加する
~/Library/Application Support/Claude/claude_desktop_config.json を編集します。アプリはシェルの PATH を使用しないため、uv の絶対パスを指定します(which uv を実行してください)。
{
"mcpServers": {
"traintracker": {
"command": "/Users/hugo/.local/bin/uv",
"args": ["run", "--directory", "/Users/hugo/Projects/traintracker", "python", "manage.py", "serve_stdio"]
}
}
}
--directory を指定すると、プロジェクトフォルダーが作業ディレクトリになり、サーバーはそのフォルダー内の .env からキーを読み込みます。serve_stdio は起動したアプリにのみ応答するため、サインインもレート制限もありません。このファイルの "env" ブロックにキーを記述することもできます。実際の環境変数は .env より優先されます。
Claude アプリを再起動し、"traintracker のデータソースの状態は?" と尋ねて、すべて接続されていることを確認します。
設定
すべての設定は環境変数で行います。プロジェクトフォルダーに .env がある場合は、そこから読み込まれます。.env.example を参照してください。ローカル開発では Django の設定は不要です。Render では titan の環境変数グループで設定されます(Render へのデプロイを参照)。
config/settings.py にある Django の設定は次のとおりです。
| 変数 | デフォルト | 用途 |
|---|---|---|
DJANGO_DEBUG | 1 | 0 にすると、本番環境向けの強化設定として manage.py check --deploy が求める内容が有効になります。1 の場合、サインインメールはコンソールログに出力され、data_status に内部情報が表示されます |
DJANGO_SECRET_KEY | 開発用キー | DJANGO_DEBUG=0 の場合に必須です。各サインインコードのハッシュのキーとしても使用されます |
ACCOUNTS_EMAIL_KEY | 固定の開発用キー | DJANGO_DEBUG=0 の場合に必須です。各アカウントの検索に使う一方向ハッシュのキーとなるため、メールアドレスは保存されません。変更しないでください。すべてのアカウントが失われます |
DJANGO_ALLOWED_HOSTS | localhost,127.0.0.1 | サイトが応答するホスト名をカンマ区切りで指定します。Render の onrender.com 名は自動的に追加されます |
DJANGO_CSRF_TRUSTED_ORIGINS | — | フォーム送信で信頼するオリジンをカンマ区切りで指定します |
SITE_URL | http://localhost:8000(Render では onrender.com 名) | 公開アドレスです。メール内のリンク、パスキーのオリジン、サイトが表示するコネクターアドレス(<SITE_URL>/mcp)に使われます |
RATE_LIMIT_PROXY_COUNT | 0、または DJANGO_DEBUG=0 の場合は 1 | アプリの前段にあるプロキシの数です。制限の対象となるクライアントアドレスは、X-Forwarded-For の末尾からその数だけさかのぼった位置になります |
EMAIL_HOST / EMAIL_PORT | localhost / 587 | サインインメール用の SMTP リレーです。Resend の場合、ホストは smtp.resend.com です |
EMAIL_HOST_USER / EMAIL_HOST_PASSWORD | — | SMTP ログイン情報です。Resend の場合、ユーザー名は resend、パスワードは API キーです |
EMAIL_USE_TLS | 1 | リレーへの STARTTLS 接続を有効にします |
DEFAULT_FROM_EMAIL | Traintrackr <noreply@localhost> | サインインメールの送信元です。ドメインはリレーで検証済みである必要があります |
WEBAUTHN_RP_ID | SITE_URL のホスト名 | パスキーが使用できる場所です(docs/accounts.md を参照) |
FIVEBAR_DOMAIN | — | 指定したドメインで fivebar による Cookie を使わない訪問者数の計測を有効にします。空の場合は無効です |
FIVEBAR_TOKEN | — | FIVEBAR_DOMAIN を指定すると、各 MCP ツール呼び出しを fivebar で /mcp/<tool> として計測します。計測されるのはツール名、応答の有無、アプリ名、アカウントのキー付きハッシュであり、引数や応答内容は計測されません(この決定)。fivebar で Send events のみを有効にして作成したトークンを使用します。空の場合は無効です |
列車ツールの設定は、apps/rail/config.py で読み込まれます。
| 変数 | デフォルト | 用途 |
|---|---|---|
DARWIN_API_KEY | — | Live Departure Board のコンシューマーキー |
DARWIN_DEPARTURES_URL | RDM LDBWS URL | Specification タブの内容が異なる場合に上書きします |
DARWIN_SERVICE_API_KEY / DARWIN_SERVICE_URL | ボードキー / RDM URL | Service Details 製品 |
DARWIN_ARRIVALS_API_KEY / DARWIN_ARRIVALS_URL | — | Live Arrival Board 製品 |
NR_USERNAME / NR_PASSWORD | — | Network Rail データフィードのログイン情報 |
NR_SCHEDULE_URL | 日次の完全な JSON 抽出データ | ポータルに異なるリンクが表示される場合に上書きします |
DATABASE_URL | — | 時刻表用の Postgres データベース(必須)と、Django 独自のテーブル用 |
TIMETABLE_SCHEMA | timetable | 時刻表が格納されるスキーマ(デモモードでは末尾に _demo が追加されます) |
USAGE_SCHEMA | traintracker_usage | Darwin に送信したリクエスト数を記録するスキーマ(Darwin の利用枠を参照) |
DARWIN_DAILY_LIMIT | 170000 | 英国の1日あたりに Darwin へ送信できるリクエストの上限です。この上限を超えると、ライブツールは予定時刻を返します。0 にすると上限が無効になります |
TIMETABLE_AUTO_REFRESH | 1 | 0 にすると、サーバーによる時刻表のダウンロードを停止します(代わりに cron ジョブを使用してください) |
TIMETABLE_MAX_AGE_HOURS | 26 | この時間より古い場合に再ダウンロードします |
TRAINTRACKER_DATA_DIR | 設定されていれば $XDG_DATA_HOME/traintracker、それ以外は ~/.traintracker | インポート前にフィードをダウンロードする場所 |
RATE_LIMIT_PER_MINUTE | 30 | /mcp でアカウントごとに1分間に呼び出せるツールの回数です。0 にすると上限が無効になります |
RATE_LIMIT_BURST | 10 | 1分あたりのレート制限が適用される前に、アカウントが一度に呼び出せるツールの回数 |
OPENAI_APPS_CHALLENGE | — | OpenAI のプラグインポータルから取得したトークンです。設定すると、OpenAI がドメインの検証時に取得する /.well-known/openai-apps-challenge で返されます |
MIN_INTERCHANGE_MINUTES | 5 | 経路計画における最小乗り換え時間 |
TRAINLINE_LIVE_URL | https://www.thetrainline.com/live | 時刻表サービスの Trainline リンクのベース URL |
HTTP_TIMEOUT_SECONDS | 15 | 上流リクエストのタイムアウト |
TRAINTRACKER_DEMO | オフ | 1 にすると、アカウントを使わずに生成されたサンプルデータを使用します(デモモードを参照) |
TRAINTRACKER_NO_DOTENV | オフ | 1 にすると、鉄道ツールが .env を読み込まなくなります(プレビューサーバーではこれが設定されます) |
コマンド
すべてのコマンドは Django の管理コマンドで、uv run python manage.py <command> として実行します。データを変更するコマンドは、--commit を指定しない限り、実行予定の内容を表示するだけです。
| コマンド | 内容 |
|---|---|
runserver | サイト、サインイン、ローカルの /mcp を実行します(本番環境では gunicorn を実行します。Render へのデプロイを参照してください) |
serve_stdio | stdio で MCP サーバーを実行します(Claude デスクトップアプリと MCP Inspector が実行するものです)。サインインとレート制限はありません |
migrate | Django のテーブルを作成または更新します |
refresh_timetable [--commit] | SCHEDULE フィードをダウンロードし、時刻表を再構築します(デモモードでは、生成された時刻表を再構築します) |
import_timetable FILE [--commit] | 自分でダウンロードしたフィードファイル(JSON、gzip 圧縮の有無を問いません)から時刻表を作成します |
rail_status | 設定済みのソース、使用中の Darwin allowance、時刻表の詳細を表示します |
forget_account EMAIL [--commit] | メールアドレスに紐づくアカウントと、そのパスキー、保存済みのボード、接続済みアプリのトークン、サインインリクエスト(消去リクエスト)を削除します |
block_account EMAIL [--commit] | アドレスに紐づくアカウントを閉鎖するか、閉鎖済みのアカウントにします。これにより、サインインできなくなり、接続済みアプリも停止します |
purge_idle_accounts [--commit] | 180 日間サインインがなく、新しいトークンもないアカウントを削除します |
purge_sign_in_requests [--commit] | 有効期限を過ぎたサインインリクエストを削除します |
purge_idempotency_records [--commit] | 24 時間の保持期間を過ぎた冪等性レコード(Titan のもの)を削除します |
cleartokens | 期限切れの OAuth トークン(django-oauth-toolkit のもの)を削除します |
アカウント関連のコマンドについては、docs/accounts.mdで説明しています。serve_stdio では、ログは stderr に出力され、stdout には MCP プロトコルが出力されます。
Render へのデプロイ
render.yaml では、フランクフルトにある 3 つのサービスを定義しています。
| サービス | 種類 | 内容 | 環境 |
|---|---|---|---|
traintracker | Web サービス、512 MB、traintrackr.live | gunicorn、8 スレッドのワーカー 1 つ。ビルド時に collectstatic を実行し、デプロイを公開する前に毎回 migrate を実行します。ヘルスチェックは /livez です | 環境グループ titan と traintracker。サービスに DARWIN_API_KEY、OPENAI_APPS_CHALLENGE、TIMETABLE_AUTO_REFRESH=0 を設定 |
traintracker-refresh | Cron ジョブ、毎日 06:30 UTC | manage.py refresh_timetable --commit | 環境グループ titan と traintracker。サービスに NR_USERNAME、NR_PASSWORD を設定 |
traintracker-purge | Cron ジョブ、毎日 03:17 UTC | purge_idempotency_records、purge_sign_in_requests、cleartokens、purge_idle_accounts を実行します。プライバシーポリシーに記載されている削除対象です | 環境グループ titan と traintracker |
2 つの環境グループは、django-titan-template に付属するコマンドラインツール、titan によって作成されます。titan はすべての Titan アプリで共有されます(デバッグのオフ、Python のバージョン、ホストとオリジン、SMTP リレー)。traintracker はこのアプリ専用です(DATABASE_URL、DJANGO_SECRET_KEY、ACCOUNTS_EMAIL_KEY、メールキーと送信者、SITE_URL、FIVEBAR_DOMAIN、および手動で追加する FIVEBAR_TOKEN)。ACCOUNTS_EMAIL_KEY は各アカウントを特定するための一方向ハッシュを作成します。コピーを保管し、絶対に変更しないでください(ドキュメント)。Blueprint は環境グループを宣言せずに参照するため、同期によってそれらが上書きされることはありません。サービスに設定された値は、環境グループの値より優先されます。列車関連のツールは、プロセスごとに 1 つのイベントループ、1 つの Darwin の使用枠、1 つの経路ネットワークを共有するため(決定事項)、Web サービスのワーカーは 1 つです。plan_journey 用に 1 日分の経路ネットワークをメモリ上に保持するため(約 200 MB)、少なくとも 512 MB が必要です。
titan deploy traintrackerを実行します。最初のデプロイ前に、Blueprint が必要とする共有titanグループ、共有 Postgres インスタンス上のアプリのロールとデータベース、送信専用の Resend キー、traintrackerグループが作成されます。その後、Blueprint をデプロイし、サービスにドメインtraintracker.<parent domain>を追加して、onrender.comの名前で/healthzをチェックします。Render から求められたら、各サービスにDARWIN_API_KEY、OPENAI_APPS_CHALLENGE、NR_USERNAME、NR_PASSWORDを設定してください。traintracker-refreshcron ジョブを手動で 1 回実行(Trigger Run)し、最初の時刻表を読み込みます。- サービスを独自のドメインに設定します。titan 独自の
goliveは、アプリを<slug>.<parent domain>に設定します。このデプロイでは、ディレクトリーの掲載情報、MCP Registry、人々のコネクターで使用されているtraintrackr.liveを維持するため、手動で設定します。サービスにドメインを追加し、サービスのDJANGO_ALLOWED_HOSTSに(titanグループの値の後に)そのドメインを追加し、traintrackerグループにSITE_URL=https://traintrackr.liveとFIVEBAR_DOMAIN=traintrackr.liveを設定します。titan はすでに設定されている値を上書きしないため、DEFAULT_FROM_EMAILもここで変更できます。 - 以下の手順で、サーバーを claude.ai コネクターとして追加します。
claude.ai コネクターとして追加する
/mcp は mcp-auth を介した Titan の MCP ビューです。テンプレートの OAuth サーバーであり、django-oauth-toolkit を使用しているため、claude.ai に一度追加すれば、claude.ai、Claude Desktop、モバイルアプリから利用できます。ChatGPT も同じ方法で接続します。
- claude.ai で、設定 → コネクター → カスタムコネクターを追加を選択し、名前に
traintracker、URL にhttps://<your-service-host>/mcpを入力します。OAuth クライアントの各欄は空のままにします。Claude が自身を登録します。 - Claude がサーバーのサインインページを開きます。サインインします(サインインを参照)。
サインインすると、Claude に有効期間 1 時間のアクセストークンと、有効期間 30 日のリフレッシュトークンが渡されます。リフレッシュのたびにトークンはローテーションされます。ChatGPT がアクセストークンの期限切れ後も接続を維持するために必要な offline_access スコープが設定されています。コールバック先として受け付けられるのは、Claude、ChatGPT、ループバックアドレス(Claude Code などのデスクトップクライアント)のみです(config/settings.py の MCP_AUTH)。アクティブなアカウントを持つユーザーなら誰でも接続できます。/oauth/connected/ には、サインイン中のアカウントに接続されているアプリが表示されます。traintracker-purge cron ジョブが毎晩、期限切れのトークンを削除します。
サインイン
Titan のサインインでは、メールアドレスを入力し、届いたメールに記載されたリンクをクリックするか、6 桁のコードを入力します。または、アカウントページからパスキーを追加して使用できます。パスワードはありません。docs/accounts.md に、リンクとコードの有効期間、メール送信とコード入力の試行回数の上限、アカウントに保持される情報、アカウントの閉鎖または削除の方法など、詳細を記載しています。DJANGO_DEBUG=1 の場合、サインインメールは送信されず、コンソールログに書き込まれます。他人がログを読めるホストでは、この設定を使用しないでください。
レート制限。 /mcp のツール呼び出しには、アカウントごとに制限があります。一度に RATE_LIMIT_BURST 回まで呼び出せ、RATE_LIMIT_PER_MINUTE の割合で補充されます。すべてのユーザーが 1 つの Darwin キーを共有するため、この制限によって 1 つのアカウントが利用枠を使い切るのを防ぎます。呼び出し 1 回につき Darwin へのリクエスト 1 回分を消費します。追加のリクエストが発生する呼び出し(ページごとに取得する長い時刻表の読み込みや、複数区間を含む旅程など)では、追加リクエスト 1 回ごとに消費されるため、そのアカウントの次の呼び出しまでの待ち時間が長くなります。旅程の計画は 3 回の呼び出しとして数えられます。制限を超えた呼び出しは、ツールエラー Too many requests. Try again in N seconds. を返します。モデルはこれを読み取り、ユーザーに伝えることができます。回数はメモリ上に保持されるため、再起動するとリセットされます。serve_stdio は制限されません。
サイト
Django アプリは小規模な公開サイトも提供するため、デプロイは1つ、ドメインも1つです。
| パス | ページ |
|---|---|
/ | サーバーの機能、コネクターアドレスとコピー用ボタン、Claude と ChatGPT への追加方法、プロンプトの例3つ |
/docs | 各ツールの平易な説明、回答に含まれる内容を示す例3つ、制限事項、データソース、サポート |
/privacy | プライバシーポリシー(英国 GDPR):処理される情報、その理由、保存期間、処理者 |
/terms | 利用規約:現状有姿でのサービス提供、正確性、責任、公正利用、データライセンス、準拠法 |
/board | ライブボード用の駅と、必要であればホームを選択します(共有可能なボードを参照) |
サイトはapps/public/にあります。ページはDjangoテンプレートです。各ページのコンテンツはtemplates/public/pages/(index.html、docs.html、privacy.html、terms.html)内のフラグメントで、templates/public/layout.htmlに配置され、views.pyによってレンダリングされます。pages.pyにはページの一覧があり、フッターのリンクを作成し、プライバシーページをprivacy_policyツールが返すテキストに変換します。共有可能なボード(ボードページ、選択画面、埋め込み表示、TV 表示、JSON フィード、駅の候補)は、リクエストごとにboards.pyでレンダリングされます。frame.htmlはボードのみを表示し、埋め込みやTV向けに使います。静的ファイルはstatic/にあります。スタイルシートはcss/site.cssの1つ、スクリプトは2つで、js/site.jsはコピーボタン、発車案内板、駅選択画面用、js/saved_boards.jsは直前のボードとお気に入り用です。ボードはアプリの外観を担い、index.html内の列車のサンプルデータ表からsite.jsが描画します。apps/rail/ui/board.htmlではスタイルとスクリプトがインラインになっていますが、サイトのコンテンツセキュリティポリシーで拒否されるため、フラップはsite.cssとsite.jsに再度記述されています。アプリでフラップの描画方法を変更した場合は、両方を変更してください。アイコンはstatic/icons/icon.svgで、そこから32、180、512ピクセルのPNGを生成します。ディレクトリ一覧にアップロードするのはicon-512.pngで、/favicon.icoは32ピクセルのPNGにリダイレクトされます。アイコンを変更するには、SVGを編集して、たとえばmagick -background none -density 1200 icon.svg -resize 512x512 PNG32:icon-512.pngを実行し、PNGを再生成してください。リンクプレビューカードはstatic/img/share.png(1200×630)で、static/img/share.svgから作成されます。発車案内アプリの横に表示する、トップページの紹介文を載せたカードです。レンダリングにはブラウザーが必要です。このカードではシステムのサンセリフフォントと太字の等幅フォントを使用しており、ImageMagick 独自の SVG レンダラーでは選択できないためです。ブラウザーでshare.svgを1200×630のキャンバスに描画してPNGとして保存するか、デバイスピクセル比を1にしてそのサイズでスクリーンショットを撮ります。その後、magick saved.png -strip PNG24:share.pngを実行するとアルファチャンネルが削除されます。アルファチャンネルがあるとテストに失敗します。share.svgでは各フラップを<rect>で、各文字を個別の<text>で表現しているため、列車を変更する場合は文字を1つずつ変更します。ビルド手順はありません。ページにはサーバー自身の値(SITE_URLのコネクターアドレス、RATE_LIMIT_PER_MINUTEとRATE_LIMIT_BURSTの公正利用に関する記述)が使われるため、別の場所にデプロイした場合も、その環境について説明します。プライバシーポリシーと利用規約には、このリポジトリのデプロイ環境とその運営者が記載されています。独自にデプロイする場合は、privacy.html、terms.html、サポート用アドレスを変更してください。
スタイルシートとスクリプトは、ファイルのハッシュを含む名前でWhiteNoiseから配信されます(collectstatic)。そのため、ブラウザーは変更されたファイルをすぐに取得し、変更されていないファイルはキャッシュできます。ページはCookieを設定せず、別のオリジンから何も読み込みません。ただし、FIVEBAR_DOMAINが設定されている場合のfivebarのカウンターは例外です。Content-Security-Policyヘッダーでは、サイト自身のスタイルシート、スクリプト、フェッチのみを許可しています。ページは閲覧者のライトまたはダークの設定に従い、スマートフォンの画面幅でも動作します。
共有可能なボード
/board/LST は駅のリアルタイム発車案内を独立したページとして表示し、/board/LST/9 は1番線の発車案内、/board/LST/COL はコルチェスターに停車する列車(または、次の2時間に直通列車がない駅(/board/LST/SUY など)の場合は、乗り換える駅での接続列車)を表示します。ホームページのソラリー式発車案内板に、運行中の列車と駅の時計を表示するので、画面に開いたままにしたり、リンクとして共有したり、別のサイトに埋め込んだりできます。サインインは不要です。/board は駅と、目的地または番線を選ぶフォームです。駅の入力欄では、入力中に候補が表示されます。
| アドレス | 内容 |
|---|---|
/board/LST | ロンドン・リバプール・ストリート発の次の10本の列車:次の2時間はリアルタイム情報を表示し、表示する列車が少ない場合は、その後に時刻表の列車を表示します(下記参照) |
/board/LST/9 | 9番線のみの発車案内。リアルタイムの番線がまだ発表されていない列車は、時刻表上の番線で照合します |
/board/LST/COL | 終着駅にかかわらず、コルチェスターに停車する列車を表示します。ノリッジ行きの列車も含まれます |
/board/LST/COL?tv=1 | テレビ画面いっぱいに表示する発車案内のみのページ。下記参照 |
/board/LST/9?embed=1 | サイトのヘッダーやフッターを表示しない、<iframe> 用の発車案内のみのページ。他のサイトでフレーム表示できるのはこのページだけです |
/api/board/LST/9 | 発車案内のJSON。ページが表示されている間、1分ごとにページから取得します |
/api/boards | サインイン後に利用できる、保存済みの発車案内。下記参照 |
Darwin の情報提供時間は2時間なので、運行本数の少ない路線や、夜間の駅では発車案内がほとんど空になってしまいます。表示する列車が10本に満たない発車案内には、Darwin の2時間分の情報が終わる時点から、最大1日先までの時刻表上の列車が追加されるため、同じ列車が重複して表示されることはありません。これらの列車は Expected 欄に薄い文字で Scheduled と表示されます(琥珀色の表示はリアルタイムかつ定刻です)。2時間以内になると、リアルタイムの時刻に切り替わります。後の日付の列車には、その日の名前(MONDAY 19 OCTOBER)が付けられ、クレジットには両方の情報源が記載されます。ツールでは、これらの列車に source: "timetable" と、運行日の date が設定されます。
駅の後に続く3文字のコードは目的地、それ以外は番線です。発車案内で指定できるのは目的地か番線のどちらか一方で、両方は指定できません。発車案内ごとにアドレスは1つです。小文字のコード、駅名(/board/cambridge、/board/LST/colchester)、または p9 や platform-9 と表記した番線でアクセスすると、そのアドレスにリダイレクトされるため、発車案内を共有するリンクは常に同じになります。複数の駅に一致する名前の場合は、どの駅かを選ぶ画面が表示されます。発車案内ページには、リンクと <iframe> コードがそれぞれコピー用ボタン付きで表示され、各番線の発車案内へのリンクもあります。
ページには列車がテーブルとして描画されるため、JavaScript がなくても機能します。site.js がフラップを描画し、更新のたびに古い文字から新しい文字へ切り替えます。誰でも発車案内を開け、アクセス数の多いページに埋め込まれた発車案内はそのページの訪問者全員に表示されるため、Darwin へのリクエストは閲覧者ごとではなく、発車案内ごとに1分間に1回です。応答(またはエラー)は60秒間保持され、同じ発車案内へのすべてのリクエストで共有されます(board.py の SharedBoards)。取得中に届いたリクエストは、同じ応答を待ちます。各クライアントアドレスは一度に30件、1分間に60件まで発車案内を開けます(apps/public/board.py の BOARD_LIMIT)。上限を超えると、応答は429となり、Retry-After が返されます。発車案内も、他のリクエストと同様に DARWIN_DAILY_LIMIT の対象です。
ボード。 フロントページには、最後に開いたボードがサンプルボードの代わりにリアルタイムで表示され、その下にはお気に入りがリンクとして表示されます。ボードページでは お気に入りに追加 を選べます(最大12件で、13件目を追加すると最も古いものが削除されます)。サインアウト中はブラウザーに保存され(localStorage)、サーバーには何も送信されません。サインイン中はアカウント(apps/public/saved.py の SavedBoard、/api/boards)に保存され、ブラウザーには何も保存されないため、どのデバイスでも同じ内容が表示されます。サインインすると、そのブラウザーに保存されていた内容がアカウントに移されます。埋め込み表示とテレビ表示は保存されません。フロントページの HTML は全員に同じなので、キャッシュされたままになります。ボードの表示は static/js/saved_boards.js と site.js が行います。理由については、docs/decisions/saved-boards-live-in-the-browser-or-the-account.md をご覧ください。
テレビでの表示。 ?tv=1 を指定するとボードだけが表示され、すべての列車が画面に収まるようにフラップのサイズが調整されます。横長の画面では列車が1行に、縦長の画面では2行に表示されます。このサイズで画面に余る列の幅が目的地の列に加えられるため、ボードが画面幅いっぱいに広がり、長い名前も収まります。ボードページで テレビに表示 を選ぶと、その場で同じ表示に切り替わって全画面になります。テレビに接続した拡張ディスプレイへ移動したウィンドウや、キャストしたタブで使えます。全画面を終了すると元の表示に戻ります。テレビでは画面をスリープさせないようにし(ブラウザーが対応している場合は Screen Wake Lock を使用)、3秒間カーソルを動かさないとカーソルが非表示になります。また、サイトの変更が反映されるよう、数週間つけたままのボードも毎晩、英国時間の03:10から03:50の間に一度、自動でページを再読み込みします。この表示は同じボードの他のすべての表示とデータ取得を共有するため、Darwin への負荷は増えません。すべてのライブボードでは「更新済み」の横に次回更新までのカウントダウンが表示されます。5分間更新されていない場合は表示が暗くなり、最後に更新された時刻が示されます。
MCP Registry
server.json には、公式 MCP Registry 向けのサーバー情報が記載されています。サーバー名 live.traintrackr/traintracker、バージョン、そして https://traintrackr.live/mcp のリモートのストリーミング可能な HTTP エンドポイントが含まれます。Registry の 2025-12-11 スキーマに準拠しています。バージョンが pyproject.toml と一致していることをテストで確認します。
バージョン 0.1.0 は公開済みです。CI では公開しません。新しいバージョンは、mcp-publisher login dns の後に mcp-publisher publish を実行して手動で公開します。live.traintrackr/ という名前を使うには、ドメインを所有していることを証明する必要があります。これは traintrackr.live のルートドメインに、署名キーの公開鍵部分を含む TXT レコードを設定することで行います。独自にデプロイする場合は、名前と URL をご自身のドメインに変更してください。
制限事項
- 過去の運行時刻(「昨日の08:00発は遅れましたか?」など)は利用できません。Darwin が提供するのは現在から2時間先までの情報で、時刻表に掲載されるのは予定時刻です。
- Darwin の停止中:Darwin がオフラインの場合、ライブツールには予定時刻が表示され、Darwin がオフラインであることが示されます。復旧するまで、遅延、運休、リアルタイムのホーム情報は表示されません。
- 運賃は含まれません。
- 地下鉄/バス/路面電車は、ロンドンのターミナル間のおおよその接続情報を除き、時刻表には含まれません。
- 工事情報は、Network Rail が公表すると時刻表に反映され(通常はかなり前に公表されます)、Darwin には当日に反映されます。
開発
Traintrackr は、兄弟アプリの構築元となるプロジェクトテンプレート Titan 上の Django プロジェクトです。独自の Starlette アプリから Titan への移行は、4 つの段階を経て行われました(その決定)。copier update --trust で問題なくマージできるよう、新しい作業はテンプレートにできるだけ沿わせてください。HTTP は gunicorn の下で Django が処理し、列車関連ツールはプロセスごとに 1 つのイベントループで動作します(その決定)。
Titan と同様に、tox は uv.lock に基づき(tox-uv プラグイン経由)、Python 3.14 ですべてのチェックを実行します。docs/testing.md に、各テストの実行場所が記載されています。鉄道関連のテスト(tests/rail/)には、スキーマを作成できる Postgres が TEST_DATABASE_URL で必要です(デフォルトは postgresql://postgres:[email protected]:55432/postgres で、インストールの下にある docker run で起動できます)。各テストは専用のスキーマで実行され、終了後にそのスキーマを削除します(tests/rail/conftest.py)。CI では Postgres 17 をサービスとして実行します。
uvx --with tox-uv tox # fmt, lint, types, checks, test, audit
uvx --with tox-uv tox -e test # one environment
uvx --with tox-uv tox -e test -- -k platform # arguments after -- go to the tool
uvx --with tox-uv tox -e sast # semgrep (downloads its rule packs)
CI(.github/workflows/ci.yml)では、各環境を個別のジョブとして実行し、さらに sast と gitleaks のスキャンも行います。ワークフローに記載されたバージョンの uv、tox、tox-uv を使用し、Actions はコミットに固定しています。Dependabot(.github/dependabot.yml)は毎週、uv.lock、package-lock.json、Actions の更新を提案します。uv と tox のバージョンは手動で更新し、uv は render.yaml でも更新します。uv run pre-commit install を実行すると、各コミットの前に ruff、gitleaks、mypy が実行されます。
| 環境 | 実行内容 |
|---|---|
fmt | ruff format --check |
lint | ruff check:Titan のルール、docstring、bandit を含め、全体をチェックします。apps/rail/ の SQL(およびそのテスト)はスキーマ名を f-string で組み立てるため、S608 の対象外です |
types | django-stubs を使った mypy。apps/rail/ は厳格な設定を維持します |
checks | 本番設定で manage.py check --deploy を実行し、未適用のマイグレーションがないことも確認します |
test | カバレッジ(最低 90%)付きの pytest:インポーター、STP ルール、プランナー、ダウンロード、クライアント、デモモード、ツール、コマンド、レート制限、Darwin の使用状況は tests/rail/、サイトとボードは tests/public/、/mcp エンドポイントとそのツールは tests/mcp/、サインイン、パスキー、アカウント関連コマンドは tests/accounts/、Titan の共有コンポーネントは tests/core/ |
js | tests/js/ を対象にした Vitest(jsdom):ページ内での static/js の動作をテストします。Node はテストにのみ使用します(package.json) |
audit | 本番依存関係に対する pip-audit と、テスト用ツールに対する npm audit |
sast | semgrep(ルールパックをダウンロードするため、デフォルトのリストには含まれていません) |
テストでは、Network Rail の JSON 形式の合成 SCHEDULE フィード(tests/rail/feedgen.py)と、公開されている Darwin スキーマに基づく API フィクスチャを使用します。実際の稼働記録ではないため、実サービスに対して初めて実行することが最終確認となります。
プレビューサーバー
.claude/launch.json には、Claude Code のプレビューペインから起動できるサーバーが 2 つあります。どちらも上記の開発用 Postgres に対してデモモードで動作し、.env を無視し、127.0.0.1 のみで待ち受けます。別のデータベースを使用するには、PREVIEW_DATABASE_URL を設定してください。
| 名前 | 実行内容 | 用途 |
|---|---|---|
web | manage.py migrate を実行し、その後 DJANGO_DEBUG=1 で manage.py runserver をポート 8000 で実行します。ポートが使用中の場合は、空いているポートを使用します | 公開サイト、サインインページ、/mcp。サインインメールはサーバーのコンソールログに出力されます |
mcp-inspector | MCP Inspector(バージョン 2。npx 経由)をポート 6274 で実行し、manage.py serve_stdio を標準入出力の接続先にします | ツールを手動で呼び出す用途です。Inspector の「Apps」タブには、ツールに MCP アプリがある場合、そのアプリが表示されます |
Inspector には Node 22.19 以降が必要です。コマンドを実行できるローカルサーバーを起動します。このサーバーは起動ごとにトークンを生成し、配信するページに埋め込みます。この設定では、その機能を有効にしたままにしています。
manage.py
config/ Settings (one module, from the environment), URLs, WSGI/ASGI
apps/
core/ Titan's shared pieces: BaseModel, idempotency, rate limits, /livez, /healthz and /.well-known/security.txt
accounts/ Sign-in by email link or code, passkeys, the account commands
mcp/ /mcp: Titan's MCP view (mcp-auth), the tool list, ui:// resources
public/ The site: pages (views.py, pages.py), boards (boards.py, board.py), saved boards (saved.py), templates
pwa/ The app's name and identity, as Titan's templates use it
rail/ The train tools and the data behind them
server.py MCP tools, source fallback, live overlay
runtime.py The tools' event loop, one per process
timetable.py SCHEDULE importer and Postgres queries (STP resolution)
planner.py Connection Scan journey planner, London links
darwin.py Rail Data Marketplace LDBWS client
usage.py Count of requests sent to Darwin, against the allowance
ratelimit.py Per-account limit on tool calls
stations.py Station search and name resolution
trainline.py Links to a train's page on Trainline
schemas.py Output models shared by all sources
demo.py Demo mode: generated timetable and in-process Darwin
config.py The train tools' settings, from the environment
ui/ MCP App: the departure board (ui://traintracker/board.html)
data/ stations.json, trainline_slugs.json
management/ serve_stdio, refresh_timetable, import_timetable, rail_status
templates/ Traintrackr's sign-in, account and connect pages
static/ site.css, site.js, the sign-in scripts, the icons and the share card
tests/ core, accounts, mcp, public, rail
docs/ accounts.md, testing.md, decisions/
データとライセンス
Darwin のデータは Rail Data Marketplace 経由で、Network Rail のデータフィードは、それらを購読する際に同意する条件に基づいて使用しています。出力を再配布する前に、その条件を確認してください。どちらも出典のクレジット表記を求めています。
| データ | クレジット表記 | 表記の根拠 |
|---|---|---|
| Darwin(リアルタイム時刻) | 「Powered by National Rail Enquiries」、nationalrail.co.uk へのリンク、および NRE ブランドガイドラインのロゴ | NRE Developer Guidelines v06-01、第 4 節。フィードを他のデータと組み合わせる場合、クレジット表記は出典表示ページに記載できます |
| Network Rail SCHEDULE(時刻表) | 「Contains public sector information licensed under the Open Government Licence v3.0.」 | Network Rail のデータフィードライセンスに基づき、フィードは Open Government Licence v3.0 で公開されており、独自の表記は指定されていないため、ライセンスの標準規定が適用されます |
| 駅一覧 | davwheat/uk-railway-stations、Open Database License(ODbL) | リポジトリのライセンス |
クレジット表記は /docs の「データの出典」に記載されています。サイトの各ページのフッターには National Rail Enquiries のクレジット表記と、この節への「データソース」リンクがあります。サーバーの指示には出典を示す 1 行が記載されており、アシスタントは回答の出典を説明する際にクレジットを表記できます。ツールの応答にはこの表記を付け加えていません。フッターには文言とリンクがありますが、NRE のロゴはありません。Darwin データフィードのページにあるブランドパックでは、ロゴの使用に National Rail の許可が必要とされており、2026-09-30 に許可を申請しました(layout.html 内の TODO(hugo))。
コード:MIT。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。