cyah.ai › Developers
cyah MCP · developers
Bouw met de cyah MCP-server
Live hotels, vluchten en treinen voor je AI-assistent of app, via één open standaard. Probeer de tools direct in de sandbox, zonder account.
Overzicht
De cyah MCP-server geeft AI-assistenten en apps toegang tot dezelfde reisdata als de assistent op cyah.ai: live beschikbaarheid en prijzen van hotels, vluchten en treinen, en boekingslinks waarmee een reiziger op cyah.ai betaalt. De server spreekt het open Model Context Protocol (MCP), dus elke MCP-client kan ermee werken: Claude, ChatGPT, de OpenAI Responses API, LangChain, n8n of je eigen code.
search_destinations · search_hotels · get_hotel_offer · find_hotel · prepare_bookingVluchten
Vluchten van honderden luchtvaartmaatschappijen, stoelen en extra’s, boeken.
search_flights · prepare_flight_bookingTreinen
Treinen in heel Europa, stoelvoorkeur, boeken.
search_train_stations · search_trains · prepare_train_booking| Omgeving | URL | Toegang | Boekingen |
|---|---|---|---|
| Sandbox | https://staging.mcp.cyah.ai/sandbox/mcp | Open, geen sleutel nodig. Zonder prijzen | Testmodus: Stripe-testkaarten, niets wordt echt geboekt |
| Productie | https://mcp.cyah.ai/mcp | API-sleutel of OAuth 2.0 (op aanvraag) | Echt: de reiziger betaalt en boekt op cyah.ai |
Transport: Streamable HTTP, stateless. Elke aanvraag is een POST met een JSON-RPC-bericht; het antwoord is gewoon JSON (geen sessie, geen SSE-stream nodig). Ondersteunde methoden: initialize, tools/list en tools/call.
Zo werkt een boeking
- Zoeken
search_destinations→search_hotels/search_flights/search_trains - Kiezen
get_hotel_offervoor kamers en tarieven - Boekingslink
prepare_booking/prepare_flight_booking/prepare_train_booking→booking_url - Betalen op cyah.aiDe reiziger vult gegevens in en betaalt veilig via Stripe
Quickstart
De sandbox heeft geen sleutel nodig. Plak dit in een terminal:
curl -s https://staging.mcp.cyah.ai/sandbox/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search_destinations","arguments":{"query":"Lisbon"}}}'Het resultaat staat in result.structuredContent (als object) en in result.content[0].text (dezelfde JSON als tekst, voor LLM-clients).
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"query\":\"Lisbon\",\"hotel_places\":[…]}" }],
"structuredContent": { "query": "Lisbon", "hotel_places": [ … ], "airports": [ … ] },
"isError": false
}
}Een volledige zoektocht in Python, zonder SDK:
import requests # pip install requests
URL = "https://staging.mcp.cyah.ai/sandbox/mcp" # production: https://mcp.cyah.ai/mcp
HEADERS = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
# "Authorization": "Bearer ymcp_prd_...", # production only
}
def call_tool(name, arguments):
body = {"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": name, "arguments": arguments}}
result = requests.post(URL, json=body, headers=HEADERS, timeout=90).json()["result"]
if result["isError"]:
raise RuntimeError(result["structuredContent"]["error"])
return result["structuredContent"]
place = call_tool("search_destinations", {"query": "Lisbon", "types": "hotel"})["hotel_places"][0]
hotels = call_tool("search_hotels", {"place_id": place["place_id"], "check_in": "2026-12-11",
"check_out": "2026-12-13", "adults": 2, "sort": "price"})
for h in hotels["hotels"][:3]:
print(h["hotel_id"], h["name"], h["stars"], h.get("total_price", "(no prices in the sandbox)"))Let op de Accept-header: de server eist application/json, text/event-stream (MCP-specificatie), anders volgt 406 Not Acceptable.
Een client koppelen
Officiële MCP SDK (Python)
import asyncio
from mcp import Client # pip install mcp (official MCP Python SDK)
async def main():
async with Client("https://staging.mcp.cyah.ai/sandbox/mcp") as client:
tools = await client.list_tools()
print([t.name for t in tools.tools])
res = await client.call_tool("search_destinations", {"query": "Lisbon"})
print(res.structured_content["hotel_places"][0])
asyncio.run(main())Officiële MCP SDK (TypeScript / Node.js)
// npm install @modelcontextprotocol/sdk
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(new URL('https://staging.mcp.cyah.ai/sandbox/mcp'));
// production: new StreamableHTTPClientTransport(new URL('https://mcp.cyah.ai/mcp'),
// { requestInit: { headers: { Authorization: `Bearer ${process.env.CYAH_MCP_KEY}` } } });
const client = new Client({ name: 'my-travel-app', version: '1.0.0' });
await client.connect(transport);
const { tools } = await client.listTools();
console.log(tools.map((t) => t.name));
const res = await client.callTool({ name: 'search_train_stations', arguments: { query: 'Paris', limit: 3 } });
console.log(res.structuredContent.results);
await client.close();OpenAI Responses API
OpenAI roept de MCP-server zelf aan; het model kiest de tools.
from openai import OpenAI # pip install openai
client = OpenAI()
resp = client.responses.create(
model="gpt-4.1-mini",
tools=[{
"type": "mcp",
"server_label": "cyah",
"server_url": "https://staging.mcp.cyah.ai/sandbox/mcp",
# production: "server_url": "https://mcp.cyah.ai/mcp", "headers": {"Authorization": "Bearer ymcp_prd_..."}
"require_approval": "never",
}],
input="Find a 3-star hotel in Lisbon from 11 to 13 December for 2 adults and give me a booking link.",
)
print(resp.output_text)Claude Desktop
Via de brug mcp-remote in claude_desktop_config.json:
{
"mcpServers": {
"cyah-sandbox": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://staging.mcp.cyah.ai/sandbox/mcp"]
},
"cyah": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.cyah.ai/mcp",
"--header", "Authorization:Bearer ${CYAH_MCP_KEY}"],
"env": { "CYAH_MCP_KEY": "ymcp_prd_..." }
}
}
}MCP Inspector
Handig om tools met de hand te testen: npx @modelcontextprotocol/inspector, kies transport Streamable HTTP en vul de sandbox-URL in. Of gebruik meteen de playground.
cyah in ChatGPT. Voor eindgebruikers komt cyah als app in ChatGPT. Deze pagina gaat over koppelen vanuit je eigen product.
Authenticatie
De sandbox is open. Voor productie krijg je na aanvraag een eigen toegang met eigen limieten. Er zijn twee vormen:
| API-sleutel | OAuth 2.0 client credentials | |
|---|---|---|
| Voor | Eenvoudige server-naar-server-koppelingen | Partners (aanbevolen) |
| Header | Authorization: Bearer ymcp_prd_… | Authorization: Bearer <access_token> |
| Geldigheid | Tot intrekking of de afgesproken einddatum | Token 60 minuten; vraag daarna een nieuw token aan |
Scopes bepalen welke tools je ziet: search geeft de 7 zoektools, booking ook de 3 prepare_*-tools. tools/list toont alleen wat jouw toegang mag aanroepen.
# 1. Get an access token (valid 60 minutes) with your client id and secret
curl -s -X POST https://youmalou-mcp-prd-448759861986.auth.eu-west-1.amazoncognito.com/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&scope=youmalou-mcp/search youmalou-mcp/booking'
# 2. Use it as a Bearer token
curl -s https://mcp.cyah.ai/mcp \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Zonder of met een ongeldig token antwoordt de server 401 met een WWW-Authenticate-header die verwijst naar /.well-known/oauth-protected-resource (RFC 9728).
Bewaar sleutels en secrets alleen server-side, nooit in een browser of app.
Limieten
| Sandbox | Productie | |
|---|---|---|
| Tool-aanroepen per dag | 200 per IP-adres, 3.000 voor alle ontwikkelaars samen | Per toegang afgesproken |
| Verzoeken per 5 minuten | 1.000 per IP-adres | 600 per sleutel/token, 1.000 per IP-adres |
| Looptijd | Meestal 1 tot 10 seconden; een hotelzoekopdracht kan tot ongeveer 20 seconden duren. Gebruik een time-out van minstens 60 seconden. | |
Boven de 5-minutenlimiet volgt HTTP 429. Is het daglimiet op, dan geeft de tool een fout met de reden (zie hieronder). Zoekresultaten van hotels worden 15 minuten bewaard; get_hotel_offer en de prepare_*-tools werken altijd met live prijzen.
Fouten
Er zijn twee soorten fouten. Protocol- en toegangsfouten krijgen een HTTP-statuscode:
| HTTP | Betekenis |
|---|---|
401 | Geen of ongeldige sleutel/token (productie) |
403 | Toegang ingetrokken of verlopen |
405 | Alleen POST: de server is stateless, er is geen GET-stream |
406 | Accept-header mist application/json, text/event-stream |
429 | Te veel verzoeken in 5 minuten |
Toolfouten (ongeldige invoer, geen beschikbaarheid, leverancier onbereikbaar, daglimiet) komen terug als normaal resultaat met isError: true en een leesbare error. Een LLM kan die tekst direct gebruiken om zijn aanroep te verbeteren.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"error\":\"check_out must be after check_in\"}" }],
"structuredContent": { "error": "check_out must be after check_in" },
"isError": true
}
}Boeken en betalen
- Je product handelt nooit betaal-, paspoort- of persoonsgegevens af. De
prepare_*-tools geven eenbooking_urlnaar de beveiligde boekingspagina op cyah.ai; daar vult de reiziger gegevens in en betaalt via Stripe. - Prijs en beschikbaarheid worden bij
prepare_*en nogmaals op de boekingspagina gecontroleerd. Pas na betaling is de boeking definitief; zeg dus nooit dat iets geboekt is als alleen de link is gemaakt. - Hotel, vlucht en trein kunnen samen in één winkelmandje en in één keer worden betaald.
- Na de boeking regelt de reiziger wijzigen en annuleren zelf via Mijn boeking op cyah.ai.
- Geef
languagemee (nlofen): teksten en de boekingspagina volgen die taal.
Productietoegang aanvragen
Werkt je integratie in de sandbox? Mail naar hello@cyah.ai met je bedrijfsnaam, een korte beschrijving van je toepassing, de verwachte aantallen aanroepen per dag en of je ook wilt boeken (scope booking). Je krijgt een API-sleutel of OAuth-client via een beveiligd kanaal.
Wijzigingen aan tools zijn achterwaarts compatibel: nieuwe velden en optionele parameters kunnen erbij komen, bestaande verdwijnen niet zonder aankondiging. Lees velden die je niet kent dus niet als fout.