Overview
The PrivateDrive MCP server exposes our booking engine as Model Context Protocol tools. An assistant can resolve an address, compare vehicle classes, get an exact price for a date and time, tell a traveller where the driver will wait at CDG, and prepare a booking.
The agent prepares, the traveller confirms and pays
create_booking_draft returns a confirmation URL on privatedrive.co where the traveller reviews the ride and pays. That keeps a human in the loop on the only irreversible step, and it means you can wire this into a product without holding payment liability.Prices come from the production pricing engine, including seasonal, event and night surcharges. A quote returned by the MCP server for a given date is the same price the website shows for that date.
Quickstart
A shared read-only key is published here so you can try the server in under a minute. It covers the six read tools. To prepare bookings you need your own key, which the next section explains.
curl -sS -X POST https://api.privatedrive.co/mcp \
-H "Authorization: Bearer mcp_live_3154b596c57930d7413d6d20f68b35e10482da90ede0153ff9c575f2496c0c17" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-D - \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "my-agent", "version": "1.0.0" }
}
}'The response headers carry mcp-session-id. Send it back on every following request of that session.
curl -sS -X POST https://api.privatedrive.co/mcp \
-H "Authorization: Bearer mcp_live_3154b596c57930d7413d6d20f68b35e10482da90ede0153ff9c575f2496c0c17" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: <session-id-from-step-1>" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_ride_quote",
"arguments": {
"vehicleId": "<id from list_vehicles>",
"pickupAddress": "Paris-Charles de Gaulle International Airport (CDG)",
"dropoffAddress": "Opera, Paris, France",
"pickupDatetime": "2026-08-10T14:00:00",
"passengers": 2
}
}
}'{
"price": 120,
"currency": "EUR",
"vehicleCategory": "E_CLASS",
"vehicleCapacity": { "passengers": 3, "luggage": 3 },
"recommendedVehicles": 1,
"breakdown": {
"basePrice": 120,
"childSeatSurcharge": 0,
"isRoundTrip": false
},
"bookingType": "point-to-point"
}That ride is 105 euros in low season. The 120 returned here is the August high-season rate: pass a real pickupDatetime and you get the real price.
Client configuration
Claude Desktop, Claude Code, Cursor
Add the server to your MCP configuration file. Replace the key with your own once you have registered.
{
"mcpServers": {
"privatedrive": {
"type": "http",
"url": "https://api.privatedrive.co/mcp",
"headers": {
"Authorization": "Bearer YOUR_KEY"
}
}
}
}TypeScript SDK
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('https://api.privatedrive.co/mcp'),
{
requestInit: {
headers: { Authorization: `Bearer ${process.env.PRIVATEDRIVE_MCP_KEY}` },
},
},
);
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);
const { tools } = await client.listTools();
const quote = await client.callTool({
name: 'get_ride_quote',
arguments: {
vehicleId,
pickupAddress: 'Paris-Charles de Gaulle International Airport (CDG)',
dropoffAddress: 'Opera, Paris, France',
pickupDatetime: '2026-08-10T14:00:00',
passengers: 2,
},
});The SDK handles the session header for you. Tool results arrive as a single text content block containing JSON, so parse result.content[0].text.
Authentication and access tiers
Every request carries Authorization: Bearer <key>. A key only ever sees the tools of its tier: anything outside its scope is absent from tools/list and cannot be called.
| Tier | Tools | Rate limit | How to get it |
|---|---|---|---|
| Public | The six read tools: search_address, list_vehicles, get_ride_quote, check_availability, list_service_areas, get_meeting_point | 20 req/min per IP | Published above, no signup |
| Registered | The six read tools plus create_booking_draft and get_booking_status | 30 req/min per key | POST /mcp/register, instant |
| Partner | Everything above plus cancel_booking, which issues a real refund | Agreed per partner | Contact us |
Registering a key
curl -sS -X POST https://api.privatedrive.co/mcp/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"agentName": "Acme Travel Assistant",
"intendedUse": "Concierge assistant for business travellers in Paris"
}'{
"apiKey": "mcp_live_…",
"tools": ["search_address", "list_vehicles", "get_ride_quote",
"check_availability", "list_service_areas", "get_meeting_point",
"create_booking_draft", "get_booking_status"],
"rateLimitPerMinute": 30,
"expiresAt": "2027-01-23T20:50:32.728Z",
"endpoint": "https://api.privatedrive.co/mcp",
"docs": "https://privatedrive.co/en/mcp/docs"
}Keys last 180 days. Registering again with the same email rotates the key: the new one is returned and the previous one stops working immediately, which is also how you revoke a leaked key. Registration is limited to three per hour per IP.
Treat the key as a secret
Rate limits and sessions
Exceeding your limit returns HTTP 429 with the ceiling in the message. Back off and retry; the window is one minute.
Sessions are bound to the key that opened them. Reusing a session id with a different key is rejected with Invalid session ID, so one integration can never inherit another's permissions. Sessions expire after 30 minutes of inactivity; simply omit the header to start a new one. Closing a session with DELETE /mcp is polite but optional.
Tool reference
Every tool answers with one text block containing JSON. Failures set isError: true and return an object with an error field explaining what to do next, which is meant to be readable by the model, not only by your code.
search_address
Turns loose user phrasing into an address the pricing engine accepts. Call this before quoting whenever the traveller typed something informal such as "CDG" or "Gare du Nord".
| Parameter | Type | Notes |
|---|---|---|
| query | string, 2 to 200 chars | Required |
| type | 'all' | 'airport' | 'station' | Defaults to 'all'. Narrows the search |
{ "addresses": ["Paris-Charles de Gaulle International Airport (CDG)", "…"] }list_vehicles
Lists the vehicle classes with their capacity and reference pricing. You need the id from here for every quote. Takes no parameters.
{
"vehicles": [
{
"id": "69b43638d243f5560ad0d4c9",
"category": "E_CLASS",
"capacity": { "person": 3, "luggage": 3 },
"options": ["…"],
"pricing": { "perKm": 0, "perHour": 85, "cdgTransfer": 105, "orlyTransfer": 95 }
}
]
}E-Class seats 3, V-Class seats up to 7, S-Class seats 3. Child seats are free and do not need to be priced in.
get_ride_quote
The exact price for a specific ride. Always call this before preparing a booking, and always quote the number it returns.
| Parameter | Type | Notes |
|---|---|---|
| vehicleId | string | Required, from list_vehicles |
| pickupAddress | string | Required |
| dropoffAddress | string | Required unless hoursNumber is set |
| pickupDatetime | string, ISO 8601 | Required, Europe/Paris. Drives seasonal, event and night surcharges |
| passengers | integer, 1 to 50 | Required |
| hoursNumber | integer, 1 to 24 | Hourly hire only, minimum 3 |
| returnDatetime | string, ISO 8601 | Round trip only |
| numberOfVehicles | integer, 1 to 10 | Defaults to 1 |
| childSeats | integer | Free of charge |
| checkedLuggage, handLuggage | integer | Used for sizing |
Always pass a real pickupDatetime
check_availability
Tells you whether a slot can be booked online. Online booking needs at least 5 hours of notice, and hourly hire has a 3 hour minimum. Shorter notice is often still possible through the human concierge, and the response says so.
{
"available": false,
"reason": "Online booking requires at least 5 hours of notice",
"alternative": "Short-notice rides are often possible via the human concierge: https://wa.me/33670031818"
}list_service_areas
Where we operate: instant online booking across the eight Île-de-France departments and all Paris airports, fixed-rate day trips, and everything else on manual quote. Takes no parameters.
get_meeting_point
The exact spot where the driver waits, per airport and terminal. Useful to answer "where do I find my driver?" before the traveller lands.
| Parameter | Type | Notes |
|---|---|---|
| airport | 'cdg' | 'orly' | 'lbg' | 'bva' | Required. lbg is Le Bourget, bva is Beauvais |
| terminal | string | Optional. CDG: 1, 2, 3. Orly: 1-2-3 or 4. Omit for all |
Airport pickups include 60 minutes of free waiting after the actual landing, and the flight is tracked in real time.
create_booking_draft
Prepares the booking and returns a confirmation URL. Nothing is charged and no driver is assigned until the traveller opens that link and pays. Drafts expire after 30 minutes. Requires a registered key.
| Parameter | Type | Notes |
|---|---|---|
| All get_ride_quote parameters | Same meaning and same validation | |
| passengerName | string | Required, the main passenger |
| passengerEmail | string | Required, receives the receipt |
| passengerPhone | string, E.164 | Required, e.g. +33612345678 |
| flightNumber | string, max 20 | Airport pickups |
| notes | string, max 500 | Passed to the driver |
| idempotencyKey | string | Strongly recommended. Replaying the same key returns the same draft instead of creating another |
| locale | 'en' | 'fr' | Defaults to 'fr' |
{
"draftId": "7f8B65JE",
"confirmationUrl": "https://privatedrive.co/confirm/<token>",
"price": 120,
"currency": "EUR",
"expiresAt": "2026-08-01T09:30:00.000Z",
"summary": {
"pickup": "Paris-Charles de Gaulle International Airport (CDG)",
"dropoff": "Opera, Paris, France",
"datetime": "2026-08-10T14:00:00",
"vehicle": "E_CLASS",
"passengers": 2
}
}Give the traveller the confirmationUrl as a link. Do not paraphrase the price: quote the price field exactly.
get_booking_status
Looks up an existing booking. Both the booking id and the phone number used to book are required, and a mismatch returns the same { "found": false } as an unknown id, so the tool cannot be used to probe which ids exist.
cancel_booking
Cancels and refunds according to the published policy: full refund more than 48 hours before pickup, 50 percent between 24 and 48 hours, none under 24 hours. The exact amount is computed server-side and returned. This tool is restricted to partner keys because it moves real money. Confirm with the traveller before calling it.
Booking flow
1. search_address resolve pickup and dropoff
2. list_vehicles pick a class that seats the group
3. check_availability confirm the slot is bookable online
4. get_ride_quote get the exact price for that date
5. create_booking_draft returns confirmationUrl
6. traveller opens the link, reviews, pays by card
7. get_booking_status follow the booking afterwardsSteps 1 and 3 are skippable when you already hold a clean address and a date comfortably in the future, but step 4 before step 5 is not: quoting from anything other than get_ride_quote risks announcing a price we will not honour.
Rules the API enforces
These are refusals, not warnings. Designing for them upfront avoids dead ends in your conversation flow.
| Rule | What happens |
|---|---|
| Vehicle must seat the group | Quoting 4 passengers in a 3-seat sedan is refused, naming the class that fits and the number of vehicles that would work |
| At least 5 hours of notice | Both check_availability and create_booking_draft refuse, pointing to the WhatsApp concierge |
| Hourly hire minimum 3 hours | Refused below 3 hours |
| Pickup must be in the future | Refused, with an explicit message |
| Card payment only | Confirmation links always take a card. There is no pay-the-driver path |
| Price parity | The engine applies season, events, holidays and night rates from the date you pass. The quote equals the website price for that date |
Errors
| Status | Meaning | What to do |
|---|---|---|
| 401 | Missing, invalid, inactive or expired key | Check the header, or register again to rotate |
| 429 | Rate limit exceeded | Back off, the window is one minute |
| 400 Invalid session ID | Unknown session, or a session belonging to another key | Drop the header and open a new session |
| Tool not found | The tool is outside your key scope | Register a key, or contact us for partner access |
| isError with an error field | Business rule refusal, such as capacity or notice | Read the message, it states the correct next step |
Support
Questions, partner access, or a bug in a tool response: write to [email protected] with the tool name and the arguments you sent. For anything a traveller needs urgently, the concierge answers on WhatsApp.
PrivateDrive is a Paris chauffeur service operating a network of licensed private drivers, with Mercedes E-Class, V-Class and S-Class vehicles.