Up and running in under 5 minutes.
RunRelay Flights is currently in private beta. Reach out to get your API key and access credentials.
info@runrelay.ioAdd RunRelay to your MCP configuration file:
{
"mcpServers": {
"runrelay-flights": {
"url": "https://api.runrelay.io/sse",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
Ask your AI agent in natural language — RunRelay handles the rest:
"Find me a flight from Barcelona to Lisbon on March 20"
"Book the first result, business class, window seat"
"Add my passport details and use my saved profile"
RunRelay uses SSE transport over standard HTTP. No WebSockets required.
sessionId.
Send your API key as a Bearer token in all requests (except /health):
Authorization: Bearer YOUR_API_KEY
/health is public — no key needed
9 tools available via MCP. Relay Credits (RC) are consumed per call.
Search for available flights between airports
Get full fare details, baggage rules, and segments for an offer
Get cabin layout with seat availability and pricing
Get available add-ons: extra baggage, meals, priority boarding
Book a flight — with automatic human operator escalation on failure
4 tools for managing user profiles and saved travelers. No RC cost.
Create a user profile with seat preferences, cabin class defaults, and confirmation style.
userId, preferences (seatPreference, defaultCabin, confirmationStyle)Retrieve a user profile including preferences and full booking history.
userIdUpdate specific preferences without overwriting the full profile.
userId, updates (partial)Save a traveler with passport details and frequent flyer numbers. Once added, book_flight auto-fills passenger data.
userId, traveler (name, passport, FFP)add_traveler once to store passport and frequent flyer details. All future book_flight calls will automatically populate passenger data — no need to re-enter details.
From natural language to boarding pass — powered by real GDS/NDC inventory.
Your Claude, GPT, or custom agent connects to https://api.runrelay.io/sse using the MCP SSE transport.
Natural language query triggers search_flights. RunRelay parses IATA codes, dates, and passenger counts automatically.
Live pricing from global distribution systems. No cached fares, no bait-and-switch prices.
Agent can call get_flight_details, get_seat_map, and get_services to give the user full context before booking.
book_flight places the reservation, charges payment, and returns the PNR (booking reference).
If anything fails — airline API error, seat conflict, payment issue — a RunRelay human operator takes over and completes the booking manually. You're notified when done.
RunRelay's reliability guarantee
Airline APIs fail. Inventory disappears. Edge cases happen. When automated booking hits a wall, RunRelay's human operators receive an escalation ticket, complete the booking manually through airline portals, and notify your agent when complete — all transparently.
Pay per operation. Credits are consumed only on successful tool calls.
We offer custom plans for high-volume integrations and enterprise clients.
Complete end-to-end examples from connection to booking confirmation.
# Connect to SSE and capture session ID
# Run in background; the server will emit sessionId in the first event
curl -N \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: text/event-stream" \
https://api.runrelay.io/sse
# Example SSE response:
# data: {"type":"session","sessionId":"sess_abc123def456"}
SESSION_ID="sess_abc123def456"
curl -X POST \
"https://api.runrelay.io/messages?sessionId=$SESSION_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "my-agent",
"version": "1.0.0"
}
}
}'
curl -X POST \
"https://api.runrelay.io/messages?sessionId=$SESSION_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_flights",
"arguments": {
"origin": "BCN",
"destination": "LIS",
"departureDate": "2025-03-20",
"passengers": { "adults": 1, "children": 0, "infants": 0 },
"cabinClass": "economy",
"maxResults": 5
}
}
}'
# Result arrives on your SSE stream:
# data: {"type":"result","id":2,"result":{"offers":[...]}}
OFFER_ID="offer_abc123xyz" # from search results
curl -X POST \
"https://api.runrelay.io/messages?sessionId=$SESSION_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"jsonrpc\": \"2.0\",
\"id\": 3,
\"method\": \"tools/call\",
\"params\": {
\"name\": \"get_flight_details\",
\"arguments\": { \"offerId\": \"$OFFER_ID\" }
}
}"
curl -X POST \
"https://api.runrelay.io/messages?sessionId=$SESSION_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"jsonrpc\": \"2.0\",
\"id\": 4,
\"method\": \"tools/call\",
\"params\": {
\"name\": \"book_flight\",
\"arguments\": {
\"offerId\": \"$OFFER_ID\",
\"passengers\": [{
\"type\": \"adult\",
\"firstName\": \"Jane\",
\"lastName\": \"Smith\",
\"dateOfBirth\": \"1985-06-15\",
\"passport\": {
\"number\": \"AB123456\",
\"expiryDate\": \"2030-01-01\",
\"issuingCountry\": \"GB\"
},
\"email\": \"jane@example.com\",
\"phone\": \"+44 7700 900000\"
}],
\"paymentMethod\": {
\"type\": \"card\",
\"savedMethodId\": \"pm_saved_123\"
}
}
}
}"
# Success response:
# { "bookingReference": "RR-BCN-LIS-20250320-XK7" }
#
# Or if escalated to human operator:
# { "escalationTicketId": "esc_789abc", "status": "pending_human" }
@modelcontextprotocol/sdk — the official TypeScript SDK for MCP clients.
Install with: npm install @modelcontextprotocol/sdk
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const API_KEY = process.env.RUNRELAY_API_KEY!;
const BASE_URL = "https://api.runrelay.io";
async function bookFlight() {
// ── 1. Create transport with auth ──────────────────────────────────
const transport = new SSEClientTransport(new URL(`${BASE_URL}/sse`), {
requestInit: {
headers: {
Authorization: `Bearer ${API_KEY}`,
},
},
});
// ── 2. Connect MCP client ──────────────────────────────────────────
const client = new Client(
{ name: "my-flight-agent", version: "1.0.0" },
{ capabilities: {} }
);
await client.connect(transport);
console.log("✅ Connected to RunRelay MCP");
// ── 3. Search for flights ──────────────────────────────────────────
const searchResult = await client.callTool({
name: "search_flights",
arguments: {
origin: "BCN",
destination: "LIS",
departureDate: "2025-03-20",
passengers: { adults: 1, children: 0, infants: 0 },
cabinClass: "economy",
maxResults: 5,
},
});
const { offers } = searchResult.content[0] as { offers: any[] };
console.log(`✈️ Found ${offers.length} flights`);
if (offers.length === 0) {
console.log("No flights found");
return;
}
const bestOffer = offers[0];
console.log(` Best: ${bestOffer.airline} — €${bestOffer.totalPrice}`);
// ── 4. Get full details for the selected offer ─────────────────────
const details = await client.callTool({
name: "get_flight_details",
arguments: { offerId: bestOffer.offerId },
});
console.log("📋 Fare conditions:", details.content[0]);
// ── 5. Check seat map (optional) ──────────────────────────────────
try {
const seatMap = await client.callTool({
name: "get_seat_map",
arguments: { offerId: bestOffer.offerId },
});
console.log("💺 Seat map available:", seatMap.content[0]);
} catch {
console.log("💺 Seat map not available for this airline");
}
// ── 6. Book the flight ─────────────────────────────────────────────
const booking = await client.callTool({
name: "book_flight",
arguments: {
offerId: bestOffer.offerId,
passengers: [
{
type: "adult",
firstName: "Jane",
lastName: "Smith",
dateOfBirth: "1985-06-15",
passport: {
number: "AB123456",
expiryDate: "2030-01-01",
issuingCountry: "GB",
},
email: "jane@example.com",
phone: "+44 7700 900000",
},
],
paymentMethod: {
type: "card",
savedMethodId: "pm_saved_123",
},
},
});
const result = booking.content[0] as any;
if (result.bookingReference) {
console.log(`🎉 Booked! Reference: ${result.bookingReference}`);
} else if (result.escalationTicketId) {
// HITLaaS: human operator will complete the booking
console.log(`🤝 Escalated to human operator: ${result.escalationTicketId}`);
console.log(" You'll be notified when the booking is confirmed.");
}
await client.close();
}
bookFlight().catch(console.error);
// One-time setup: create user profile & add traveler
// After this, book_flight auto-fills passenger data!
// Create user profile
await client.callTool({
name: "setup_user",
arguments: {
userId: "user_jane_smith",
preferences: {
seatPreference: "window",
defaultCabin: "economy",
confirmationStyle: "always_confirm", // ask before booking
mealPreference: "vegetarian",
},
},
});
// Add a saved traveler (done once, reused forever)
await client.callTool({
name: "add_traveler",
arguments: {
userId: "user_jane_smith",
traveler: {
firstName: "Jane",
lastName: "Smith",
dateOfBirth: "1985-06-15",
passport: {
number: "AB123456",
expiryDate: "2030-01-01",
issuingCountry: "GB",
nationality: "GB",
},
frequentFlyer: [
{ airline: "IB", number: "IBE123456" }, // Iberia Plus
{ airline: "TP", number: "TP789012" }, // TAP Miles&Go
],
},
},
});
// Now book_flight will auto-fill Jane's details:
await client.callTool({
name: "book_flight",
arguments: {
offerId: "offer_xyz",
userId: "user_jane_smith", // passengers auto-populated!
paymentMethod: { type: "card", savedMethodId: "pm_saved_123" },
},
});