KeyFlight PNR Converter について
KeyFlight PNR Converterは、GDS予約を扱う旅行代理店、旅行会社、開発者向けのホスト型MCPサーバーとPNR APIです。Amadeus、Sabre、Galileo、Worldspanの記録を解析して旅程やJSONを生成し、PROチケットPDFも作成できます。
主な機能
- 014種類のGDS形式のPNRを解析
- 02読みやすい旅程と構造化JSONを出力
- 03旅程のレイアウトと日時形式を選択
- 04価格を指定可能なPROチケットPDFを生成
活用シーン
- 01GDS予約を旅客向けの旅程に変換
- 02解析した予約データを予約ツールやCRMに渡す
- 03PNRからPROチケットPDFを作成
MCP 対応
ホスト型MCPサーバー https://keyflight.io/mcp は、PNR解析とPROチケットPDF生成のツールを提供します。Streamable HTTPを使用し、Bearer APIキーが必要です。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://keyflight.io/mcpclaude mcp add --transport http io-keyflight-pnr https://keyflight.io/mcp{"mcpServers":{"io-keyflight-pnr":{"type":"http","url":"https://keyflight.io/mcp"}}}Cursor で開く{"servers":{"io-keyflight-pnr":{"type":"http","url":"https://keyflight.io/mcp"}}}VS Code で開く{"mcpServers":{"io-keyflight-pnr":{"type":"http","url":"https://keyflight.io/mcp"}}}{"mcpServers":{"io-keyflight-pnr":{"serverUrl":"https://keyflight.io/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
https://keyflight.io/mcp認証が必要ツール
詳細

KeyFlight PNR Converter:MCP サーバーと PNR API
GDS(Amadeus、Sabre、Galileo、Worldspan)の未加工の予約情報を Claude、Cursor、または別の AI アシスタントに貼り付けると、読みやすい旅程、JSON 形式の予約情報、または PRO チケットの PDF を取得できます。
KeyFlight は、ホスト型の Model Context Protocol サーバー(https://keyflight.io/mcp)と、HTTP API(https://keyflight.io/api/v1/pnr/decode)を提供しています。どちらも、keyflight.io にある無料の PNR converter と同じデコーダーを使用します。
このリポジトリには、ドキュメントとサンプルが含まれています。サーバー自体は KeyFlight がホストしているため、インストールや実行は不要です。リファレンスの全文は keyflight.io/pnr-api をご覧ください。
対象ユーザー: GDS の予約を扱う旅行代理店や旅行会社、および予約ツール、CRM、チャットボット、メールのワークフローに PNR デコード機能を追加する開発者です。
API キーを取得する
MCP サーバーと PNR API では、同じキーを使用します。キーは kfp_ の後に43文字の英字、数字、-、_ が続く形式です。
- KeyFlight サブスクリプション(旅行代理店向けのサブスクリプション)を取得します。
- 同じページで 「すでに登録済みですか?」 を選び、メールで届くリンクを開いて 「API キーを作成」 を押します。
- キーをコピーします。キーが表示されるのは一度だけです。サブスクリプションで同時に利用できるキーは2つです。キーは同じページで無効化できます。
サブスクリプションが有効でない間、キーは 403 subscription_inactive を返します。API と MCP サーバーに無料プランはありません。ウェブサイトの PNR converter は、キーなしで誰でも無料で利用できます。
AI アシスタントを接続する(MCP)
| サーバー URL | https://keyflight.io/mcp |
| トランスポート | Streamable HTTP、POST のみ。セッションおよびサーバー送信イベントストリームには対応していません |
| 認証 | ヘッダー Authorization: Bearer kfp_… |
| プロトコルのバージョン | 2025-06-18、2025-03-26、2024-11-05 |
Claude Code
claude mcp add --transport http keyflight https://keyflight.io/mcp --header "Authorization: Bearer kfp_…"
Cursor(.cursor/mcp.json)
{
"mcpServers": {
"keyflight": {
"url": "https://keyflight.io/mcp",
"headers": {
"Authorization": "Bearer kfp_…"
}
}
}
}
Claude Desktop(claude_desktop_config.json、Node.js が必要)
Claude Desktop は mcp-remote 経由で接続します。
{
"mcpServers": {
"keyflight": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://keyflight.io/mcp",
"--header",
"Authorization: Bearer kfp_…"
]
}
}
}
続いて、たとえば「この PNR をデコードして、価格を850 EURにした PRO チケットを作成して」と依頼し、予約情報を貼り付けます。
その他のクライアント:Streamable HTTP とカスタムヘッダーに対応する MCP クライアントなら、どれでも利用できます。他のサイトのウェブページから送信されたリクエスト(ブラウザーの Origin ヘッダーを含むリクエスト)は 403 origin_not_allowed で拒否されます。そのため、デスクトップアプリ、コマンドライン、または自分のサーバーから接続してください。クライアントを使わない場合は、examples/mcp/raw-jsonrpc.sh をご覧ください。POST ごとに1つの JSON-RPC メッセージを送信し、JSON が返されます。
MCP ツール
decode_pnr:PNR をデコードする
未加工の PNR を、読みやすい旅程(テキスト)と構造化 JSON(搭乗者、フライト、空港、ターミナル、現地時刻、フライト所要時間、航空会社の予約番号)に変換します。
| 引数 | 型 | デフォルト | 説明 |
|---|---|---|---|
text | string, required | GDS に表示される PNR。最大 20,000 文字です。形式はテキストから判別されます。 | |
view | table, lines2, lines3, whatsapp | table | 旅程テキストのレイアウトです。 |
time_format | "24", "12" | "24" | 24 時間表記または 12 時間表記です。 |
date_format | "short", "numeric" | "short" | short:2026年5月3日、numeric:03.05.2026。 |
返される内容は旅程テキスト、その後に続く JSON:、そして同じ JSON です。PNR API の応答をご覧ください。structuredContent を読み取るクライアントは、そこから JSON を取得できます。
フライトが見つかったデコードは、それぞれ API 呼び出しと同様に、サブスクリプションの月間デコード数にカウントされます。フライトを含まないテキストはエラーを返し、カウントされません。その月のデコード数を使い切ると、1 日(UTC)までツールはエラーを返します。
make_ticket:PRO チケット PDF を作成する
未加工の PNR から PRO チケット PDF(PNR、航空会社のロゴ、クラス、任意の料金)を作成し、PDF へのリンクを返します。KeyFlight サブスクリプションに含まれています。
このチケットは旅行者向けの書類です。航空券ではなく、PNR も航空会社のシステムで照合されません。
| 引数 | 型 | デフォルト | 説明 |
|---|---|---|---|
text | string, required | PNR。最大 20,000 文字です。すべてのフライトに日付と時刻が必要です。 | |
passengers | array of strings, up to 20 | PNR 内の名前 | チケットに記載する搭乗者名。例:"SMITH/JOHN MR"。 |
pnr | string | テキスト内のコード、またはランダムなコード | チケットに印字する予約コード。英字と数字を 5~8 文字で指定します。 |
booking_class | Economy, Premium Economy, Business, First Class | 最初のフライトの予約クラスの客室 | チケットに記載するクラスです。 |
price | string | チケットに料金を記載しない | チケットに印字する合計料金。例:"1200.50"。 |
currency | string, up to 10 characters | "$" | 料金の横に表示する通貨。例:"USD"、"€"。 |
logo | none, expedition | none | チケットのヘッダーに表示するロゴです。 |
time_format | "24", "12" | "24" | 24 時間表記または 12 時間表記です。 |
date_format | "short", "numeric" | short または numeric。 |
返される内容は、PNR、フライト数、搭乗者名を含む PRO ticket PDF: https://keyflight.io/tickets/….pdf の行と、structuredContent です。
{ "url": "https://keyflight.io/tickets/….pdf", "pnr": "PQ7XNR", "passengers": ["JOHNSON JOHN", "JOHNSON JANE"], "segments": 2 }
チケットは月間デコード数にカウントされません。1 つのキーで 1 時間に最大 30 枚のチケットを作成できます。
エラー(テキストにフライトがない、フライトに日付または時刻がない、搭乗者名がない、pnr またはオプションが誤っている、1 時間に 30 枚を超えるチケットを作成しようとした)は、isError: true を含むツール結果として返されるため、アシスタントは内容を読み取り、呼び出しを修正できます。
HTTP 経由の PNR API
Content-Type: application/json と Authorization: Bearer kfp_… を指定して POST https://keyflight.io/api/v1/pnr/decode を呼び出します。本文は { "text": "…", "options": { … } } です。HTTP API はデータと旅程をテキストおよび HTML で返します。PRO チケット PDF は MCP ツール make_ticket から取得できます。以下の例では、examples/pnr-amadeus.txt の Amadeus 予約を送信します。
curl
curl https://keyflight.io/api/v1/pnr/decode \
-H "Authorization: Bearer $KEYFLIGHT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "RP/LHRBA/LHRBA BA/BA 26APR26/1200Z PQ7XNR\nPQ7XNR/BA QLHR 03MAY\n1.JOHNSON JOHN\n2.JOHNSON JANE\n3 BA 178 Y 03MAY 7 LHRJFK HK2 0855 1205 03MAY E BA/PQ7XNR\n4 BA 117 Y 10MAY 7 JFKLHR HK2 1830 0640 11MAY E BA/PQ7XNR\n5 TKT/TIME LIMIT\n6 OPC LHRBA-10MAY:1900/1S2/Q TKT/T-BA\n7 FA PAX 125-2196837482/ETBA/GBP560.20/03MAY26/LHRBA2104/00390755/S3-4",
"options": {
"view": "table"
}
}'
Node.js 18+
// Node.js 18+ (fetch is built in), in an ES module or an async function
const text = `RP/LHRBA/LHRBA BA/BA 26APR26/1200Z PQ7XNR
PQ7XNR/BA QLHR 03MAY
1.JOHNSON JOHN
2.JOHNSON JANE
3 BA 178 Y 03MAY 7 LHRJFK HK2 0855 1205 03MAY E BA/PQ7XNR
4 BA 117 Y 10MAY 7 JFKLHR HK2 1830 0640 11MAY E BA/PQ7XNR
5 TKT/TIME LIMIT
6 OPC LHRBA-10MAY:1900/1S2/Q TKT/T-BA
7 FA PAX 125-2196837482/ETBA/GBP560.20/03MAY26/LHRBA2104/00390755/S3-4`;
const response = await fetch('https://keyflight.io/api/v1/pnr/decode', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KEYFLIGHT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text, options: { "view": "table" } }),
});
const data = await response.json();
if (response.ok) {
data.segments.forEach((s) => console.log(s.airlineCode, s.flightNumber, s.departure.date));
} else {
console.error(response.status, data.error, data.message);
}
Python
examples/api/decode.py(requests が必要です):
import os
import requests
text = """RP/LHRBA/LHRBA BA/BA 26APR26/1200Z PQ7XNR
PQ7XNR/BA QLHR 03MAY
1.JOHNSON JOHN
2.JOHNSON JANE
3 BA 178 Y 03MAY 7 LHRJFK HK2 0855 1205 03MAY E BA/PQ7XNR
4 BA 117 Y 10MAY 7 JFKLHR HK2 1830 0640 11MAY E BA/PQ7XNR
5 TKT/TIME LIMIT
6 OPC LHRBA-10MAY:1900/1S2/Q TKT/T-BA
7 FA PAX 125-2196837482/ETBA/GBP560.20/03MAY26/LHRBA2104/00390755/S3-4"""
response = requests.post(
"https://keyflight.io/api/v1/pnr/decode",
headers={"Authorization": f"Bearer {os.environ['KEYFLIGHT_API_KEY']}"},
json={"text": text, "options": { "view": "table" }},
timeout=30,
)
data = response.json()
if response.ok:
for s in data["segments"]:
print(s["airlineCode"], s["flightNumber"], s["departure"]["date"])
else:
print(response.status_code, data["error"], data["message"])
オプション
| フィールド | 値 | デフォルト |
|---|---|---|
text | 必須。GDSに表示される予約内容。最大20,000文字です。 | |
options.view | table、lines2、lines3、whatsapp:itinerary のレイアウトです。 | table |
options.timeFormat | "24"(18:30)、"12"(6:30 PM) | "24" |
options.dateFormat | "short"(3 May 2026)、"numeric"(03.05.2026) | "short" |
options.show.logo | true / false。航空会社のロゴです(HTMLのみ)。 | true |
options.show.airports | true / false。都市名の横に空港名とターミナルを表示します。 | true |
options.show.cabin | true / false。客室クラスと予約クラスです:エコノミー(Y)。 | false |
options.show.status | true / false。区間のステータスです:確定、空席待ち。 | false |
options.show.passengers | true / false。フライトの上に搭乗者名を表示します。 | false |
options.show.pnr | true / false。フライトの上に予約参照番号と航空会社の参照番号を表示します。 | false |
不明なオプションまたは無効な値を指定すると、フィールド名と許可される値を含む 400 invalid_option が返されます。
レスポンス
上記の例に対する完全な回答です:examples/api/response-example.json(itinerary.html は短縮されています)。主なフィールド:
| フィールド | 意味 |
|---|---|
pnrCode | テキスト内で見つかった予約参照番号、または null。 |
passengers[].name | PNRに記載されている搭乗者名。 |
segments[].airlineCode, airlineName, flightNumber | 航空会社と便名(UA0950の場合は "950")。 |
segments[].bookingClass, cabin | 予約クラスの文字と、それに対応する客室クラス:エコノミー、プレミアムエコノミー、ビジネスクラス、ファーストクラス。 |
segments[].status, statusText | PNRに記載されているステータスコード("HK2")と、確定、空席待ち、またはコードそのもの。 |
segments[].logoUrl | 航空会社のロゴ、64×64 PNG。 |
segments[].duration | 2空港のタイムゾーンを考慮したフライト時間(分)、または null。 |
segments[].distance | 2空港間の距離 { km, miles }、または null。 |
segments[].aircraftCode, aircraft | PNRに記載されている場合の機材の種類、または null。 |
segments[].operatedBy | PNRに記載されている運航航空会社(OPERATED BY …)、または null。 |
segments[].airlineLocator | { airlineCode, code }:航空会社独自の予約参照番号、または null。 |
segments[].departure, arrival | code、city、airport、terminal、現地の date(YYYY-MM-DD)と time(HH:MM)。 |
itinerary | view、text、html(テーブルとインラインスタイルを含むメール用HTML。whatsapp の場合は null)。 |
無料コンバーターで表示される、table 表示の例の itinerary.html(options.show.logo: false):
制限
| 制限 | 値 |
|---|---|
| PNRテキスト | 最大20,000文字。JSON本文は最大100kb |
| キーごとのリクエスト数 | APIとMCPサーバーでそれぞれ1分あたり60件。超過すると Retry-After を含む 429 too_many_requests が返されます |
| IPアドレスごとのリクエスト数 | 1分あたり120件 |
| サブスクリプションごとのデコード数 | 1暦月(UTC)あたり3,000件。2つのキーを合算し、APIと decode_pnr を合算します。フライトが見つかったデコードのみがカウントされます。 |
PROチケットPDF(make_ticket) | キーごとに1時間あたり30件 |
HTTP APIのレスポンスには、X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset、X-Monthly-Limit、X-Monthly-Remaining、X-Monthly-Reset が含まれます。
エラー
PNR API のエラーは JSON 形式です:{ "error": "<code>", "message": "…" }。
| ステータス | error | 発生条件 |
|---|---|---|
| 400 | invalid_json | 本文が JSON オブジェクトではありません。 |
| 400 | text_required | text がないか、空です。 |
| 400 | invalid_option | 不明なオプション、または誤った値です。field に項目名、allowed に許可される値が列挙されます。 |
| 401 | missing_api_key | Authorization: Bearer … ヘッダーがありません。 |
| 401 | invalid_api_key | キーが無効か、取り消されています。 |
| 403 | subscription_inactive | キーのサブスクリプションが有効ではありません。 |
| 404 | not_found | 該当するエンドポイントがありません。 |
| 405 | method_not_allowed | メソッドが POST ではありません。 |
| 413 | too_long | テキストが 20,000 文字を超えています(回答の max を参照)。 |
| 413 | payload_too_large | 本文が 100kb を超えています。 |
| 415 | unsupported_encoding | 本文が UTF-8 ではありません。 |
| 422 | no_flights | テキストにフライト情報がありません。月間上限にはカウントされません。 |
| 429 | too_many_requests | 1 分あたりの上限を超えています。Retry-After 秒待ってください。 |
| 429 | monthly_limit_reached | 今月のサブスクリプションのデコード回数を使い切りました。 |
| 500 | server_error | サーバー側で問題が発生しました。 |
| 503 | service_unavailable | 現在キーを確認できません。1 分後にもう一度お試しください。 |
ツールの実行前に、MCP サーバーは同じ JSON 形式で 401 missing_api_key/invalid_api_key、403 subscription_inactive、429 too_many_requests、503 service_unavailable を返します。また、他のサイトのウェブページからのリクエストには 403 origin_not_allowed を、POST 以外のリクエストには 405 method_not_allowed を返します。ツール実行中のエラー(月間上限も含む)は、isError: true を持つツール結果として返されます。
対応する GDS 形式
Amadeus(1A)、Sabre(1B/1S)、Galileo(1G)、Worldspan(1P)に対応しています。予約内容は GDS に表示されているとおりに送信してください。どのシステムのものかを指定する必要はありません。各システムの予約例:Amadeus、Sabre、Galileo、Worldspan。
リンク
- API と MCP のリファレンス:keyflight.io/pnr-api
- 無料の PNR コンバーター(キー不要):keyflight.io/tickets/pnr
- 旅行代理店向け KeyFlight サブスクリプション:keyflight.io/subscription
ライセンス
このリポジトリのサンプルとドキュメントは、MIT License の下で提供されています。KeyFlight サービスはオープンソースではありません。利用するには KeyFlight のサブスクリプションが必要です。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。