Skip to content
Developer reference

PrivateDrive MCP server

Give any AI assistant the ability to price and prepare a private chauffeur booking in Paris. Live prices from the same engine that powers privatedrive.co, real airport meeting points, and a confirmation link the traveller opens to pay.

Endpoint https://api.privatedrive.co/mcpTransport Streamable HTTPProtocol 2025-06-18

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

No tool can charge a card. 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.

1. open a 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" \
  -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.

2. price a ride
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
      }
    }
  }'
response
{
  "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.

mcp config
{
  "mcpServers": {
    "privatedrive": {
      "type": "http",
      "url": "https://api.privatedrive.co/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_KEY"
      }
    }
  }
}

TypeScript SDK

typescript
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.

TierToolsRate limitHow to get it
PublicThe six read tools: search_address, list_vehicles, get_ride_quote, check_availability, list_service_areas, get_meeting_point20 req/min per IPPublished above, no signup
RegisteredThe six read tools plus create_booking_draft and get_booking_status30 req/min per keyPOST /mcp/register, instant
PartnerEverything above plus cancel_booking, which issues a real refundAgreed per partnerContact us

Registering a key

register
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"
  }'
response
{
  "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

Keep it server-side. Never ship it in a browser bundle, a mobile app, or a public repository. The published public key is the only one meant to be visible, and it can only read.

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".

ParameterTypeNotes
querystring, 2 to 200 charsRequired
type'all' | 'airport' | 'station'Defaults to 'all'. Narrows the search
returns
{ "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.

returns
{
  "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.

ParameterTypeNotes
vehicleIdstringRequired, from list_vehicles
pickupAddressstringRequired
dropoffAddressstringRequired unless hoursNumber is set
pickupDatetimestring, ISO 8601Required, Europe/Paris. Drives seasonal, event and night surcharges
passengersinteger, 1 to 50Required
hoursNumberinteger, 1 to 24Hourly hire only, minimum 3
returnDatetimestring, ISO 8601Round trip only
numberOfVehiclesinteger, 1 to 10Defaults to 1
childSeatsintegerFree of charge
checkedLuggage, handLuggageintegerUsed for sizing

Always pass a real pickupDatetime

The date is what applies high season, event weeks such as Fashion Week, public holidays and night rates. A quote without a genuine date is a low estimate that the website will not honour on the day.

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.

returns (refused)
{
  "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.

ParameterTypeNotes
airport'cdg' | 'orly' | 'lbg' | 'bva'Required. lbg is Le Bourget, bva is Beauvais
terminalstringOptional. 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.

ParameterTypeNotes
All get_ride_quote parametersSame meaning and same validation
passengerNamestringRequired, the main passenger
passengerEmailstringRequired, receives the receipt
passengerPhonestring, E.164Required, e.g. +33612345678
flightNumberstring, max 20Airport pickups
notesstring, max 500Passed to the driver
idempotencyKeystringStrongly recommended. Replaying the same key returns the same draft instead of creating another
locale'en' | 'fr'Defaults to 'fr'
returns
{
  "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

sequence
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 afterwards

Steps 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.

RuleWhat happens
Vehicle must seat the groupQuoting 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 noticeBoth check_availability and create_booking_draft refuse, pointing to the WhatsApp concierge
Hourly hire minimum 3 hoursRefused below 3 hours
Pickup must be in the futureRefused, with an explicit message
Card payment onlyConfirmation links always take a card. There is no pay-the-driver path
Price parityThe engine applies season, events, holidays and night rates from the date you pass. The quote equals the website price for that date

Errors

StatusMeaningWhat to do
401Missing, invalid, inactive or expired keyCheck the header, or register again to rotate
429Rate limit exceededBack off, the window is one minute
400 Invalid session IDUnknown session, or a session belonging to another keyDrop the header and open a new session
Tool not foundThe tool is outside your key scopeRegister a key, or contact us for partner access
isError with an error fieldBusiness rule refusal, such as capacity or noticeRead 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.

MCP Server Documentation | Book a Paris Chauffeur from an AI Agent | PrivateDrive