Duffel MCP Server
# Duffel MCP Server
A Model Context Protocol (MCP) server that enables LLMs to interact with the [Duffel API](https://duffel.com) for searching and booking flights, accommodations, and managing travel bookings.
## Features
### ✈️ Flight Operations
- **Search Flights** - Find available flights with pricing, schedules, and airline information
- **Get Offer Details** - Retrieve up-to-date pricing and availability for specific offers
- **Create Orders** - Book flights with passenger details and payment
- **Manage Orders** - View and manage existing bookings
### 🌍 Supporting Resources
- **Search Airports** - Find airports by name, city, or IATA code
- **List Airports** - Browse airports with country filtering
### 🎯 Key Capabilities
- **300+ Airlines** - Access to major airlines via NDC, GDS, and LCC
- **Real-time Data** - Live pricing, availability, and seat selection
- **Flexible Search** - One-way, round-trip, multi-city support
- **Smart Responses** - JSON or Markdown formatted output
- **Error Handling** - Clear, actionable error messages
## Installation
### Prerequisites
- Python 3.12 or higher
- Duffel API account ([sign up here](https://app.duffel.com/join))
- Duffel API access token
- [uv](https://docs.astral.sh/uv/) (fast Python package manager)
### Install uv
On macOS with Homebrew:
```bash
brew install uv
```
Or via the official installer (macOS/Linux):
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
# then restart your shell or source the profile output by the installer
```
### Project setup
1. Clone or download the server file/repo
2. Create the virtual environment and install dependencies with uv:
```bash
uv sync
```
This uses `pyproject.toml` to create `.venv` and install exact versions.
3. Set up environment variable:
```bash
export DUFFEL_ACCESS_TOKEN="your_duffel_token_here"
```
Get your token from the [Duffel Dashboard](https://app.duffel.com):
- Navigate to: More → Developers → Access Tokens
- Create a test token for testing (free, unlimited balance)
- Create a live token for production bookings
## Usage
### Running the Server
Run with uv (uses the synced virtualenv automatically):
```bash
uv run python duffel_mcp.py
```
### Configuration for Claude Desktop
Add to your Claude Desktop config file (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"duffel": {
"command": "uv",
"args": ["run", "python", "/path/to/duffel_mcp.py"],
"env": {
"DUFFEL_ACCESS_TOKEN": "your_token_here"
}
}
}
}
```
### Configuration for Other MCP Clients
For other MCP clients, follow their specific configuration format, ensuring:
- The server is launched with Python 3.12+
- `DUFFEL_ACCESS_TOKEN` environment variable is set
- Server communicates via stdio
## Available Tools
### 1. `duffel_search_flights`
Search for available flights based on journey requirements.
**Parameters**:
- `slices` - Journey legs (origin, destination, date)
- `passengers` - List of travelers (use `age` for best accuracy)
- `cabin_class` - Optional: economy, premium_economy, business, first
- `max_connections` - Optional: limit stops (0 = direct flights)
- `response_format` - json or markdown
**Example**:
```python
{
"slices": [
{
"origin": "JFK",
"destination": "LAX",
"departure_date": "2025-12-15"
},
{
"origin": "LAX",
"destination": "JFK",
"departure_date": "2025-12-22"
}
],
"passengers": [
{"age": 35},
{"age": 32},
{"age": 8}
],
"cabin_class": "economy",
"max_connections": 1
}
```
### 2. `duffel_get_offer`
Retrieve current pricing and details for a specific offer.
**Parameters**:
- `offer_id` - Offer ID from search results
- `response_format` - json or markdown
**Important**: Always call this before booking to ensure offer is still valid and get current pricing.
### 3. `duffel_create_order`
Create a flight booking with passenger details and payment.
**Parameters**:
- `offer_id` - Offer ID to book
- `passengers` - Complete passenger details (name, DOB, contact)
- `payments` - Payment information
- `response_format` - json or markdown
**⚠️ Warning**: This creates real bookings! Use test tokens for development.
**Example**:
```python
{
"offer_id": "off_00009htYpSCXrwaB9DnUm0",
"passengers": [
{
"id": "pas_00009hj8USM7Ncg31cBCL",
"given_name": "John",
"family_name": "Smith",
"born_on": "1985-03-15",
"email": "john.smith@example.com",
"phone_number": "+14155551234",
"gender": "m",
"title": "mr"
}
],
"payments": [
{
"type": "balance",
"amount": "520.00",
"currency": "USD"
}
]
}
```
### 4. `duffel_get_order`
Retrieve details for an existing order.
**Parameters**:
- `order_id` - Order ID from booking
- `response_format` - json or markdown
### 5. `duffel_search_airports`
Search for airports by name, city, or code.
**Parameters**:
- `query` - Search term (e.g., "London", "Heathrow", "LHR")
- `limit` - Max results (1-100, default: 20)
- `response_format` - json or markdown
### 6. `duffel_list_airports`
List airports with optional country filter.
**Parameters**:
- `country_code` - Optional: ISO country code (e.g., "US", "GB")
- `limit` - Results per page (1-200, default: 50)
- `response_format` - json or markdown
## Typical Workflows
### Booking a Flight
1. **Search for flights**:
```
Search for round-trip flights from New York to London, departing Dec 15, returning Dec 22,
2 adult passengers, economy class, direct flights only
```
2. **Get offer details**:
```
Get the latest pricing for offer off_00009htYpSCXrwaB9DnUm0
```
3. **Create booking**:
```
Book this offer with passengers: John Smith (john@example.com, +14155551234, DOB 1985-03-15)
and Jane Smith (jane@example.com, +14155551235, DOB 1987-07-20). Use balance payment for $1,450.00 USD.
```
### Finding Airports
```
What airports are in the London area?
```
```
What's the airport code for San Francisco International?
```
## Best Practices
### ✅ Do's
1. **Use `age` over `type`** - Provides better accuracy across airlines
2. **Check offer expiry** - Offers expire in 15-30 minutes
3. **Verify before booking** - Always retrieve offer for current price
4. **Test mode first** - Use test tokens during development
5. **Handle async responses** - Some bookings return 200/202 with webhook notifications
### ❌ Don'ts
1. **Don't retry failed bookings** - If order creation fails, don't retry the same request
2. **Don't cache offers** - Always fetch fresh data before booking
3. **Don't ignore validation errors** - They guide toward correct usage
4. **Don't use expired offers** - Check `expires_at` timestamp
## Error Handling
The server provides clear, actionable error messages:
- **offer_expired** - Perform new search
- **offer_no_longer_available** - Select different offer
- **price_changed** - Retrieve offer again for updated price
- **validation_error** - Check parameter formats and requirements
- **payment_declined** - Verify payment details
## Testing
### Test Mode
Duffel provides unlimited test balance:
1. Create a **test** access token in dashboard
2. Use `"type": "balance"` for payments
3. Search and book without actual charges
4. Use test airline: "Duffel Airways"
### Manual Testing
```bash
# Set test token
export DUFFEL_ACCESS_TOKEN="duffel_test_xxx"
# Run server with uv
uv run python duffel_mcp.py
```
Then interact through your MCP client to test various workflows.
## API Reference
For complete Duffel API documentation:
- [Getting Started Guide](https://duffel.com/docs/guides/getting-started-with-flights)
- [API Reference](https://duffel.com/docs/api/overview/welcome)
- [Response Handling](https://duffel.com/docs/api/overview/response-handling)
## Troubleshooting
### "DUFFEL_ACCESS_TOKEN environment variable not set"
Set the environment variable with your Duffel API token.
### "offer_expired" errors
Offers have short expiry times (15-30 min). Perform a new search.
### "validation_error" on booking
- Check passenger names match government ID exactly
- Verify date format is YYYY-MM-DD
- Ensure payment amount matches offer total
- Confirm all required fields are provided
### "No flights found"
- Verify airport codes are valid IATA codes (use `duffel_search_airports`)
- Check dates are in future
- Try broader search criteria (more connections, different cabin class)
### Webhooks not received
- Configure webhook URLs in Duffel Dashboard
- Check your email for booking confirmations
- Use `duffel_get_order` to manually check order status
## License
This MCP server is provided as-is for integration with Duffel API. See Duffel's terms of service for API usage terms.
## Support
- **Duffel Documentation**: https://duffel.com/docs
- **Duffel Support**: https://support.duffel.com
- **MCP Documentation**: https://modelcontextprotocol.io
## Contributing
Contributions welcome! Potential enhancements:
- Stays API integration (hotel bookings)
- Order modifications and cancellations
- Seat selection tools
- Baggage management
- Loyalty program integration
- Advanced filtering options
## Version History
- **v0.1.0** - Initial release
- Flight search and booking
- Order management
- Airport search
- Markdown and JSON output formats
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose with no overlap. The tools cover specific actions like creating orders, retrieving offers/orders, listing/searching airports, and searching flights, all with well-defined boundaries. An agent can easily distinguish between them based on their unique functions.
All tool names follow a consistent 'duffel_verb_noun' pattern (e.g., duffel_create_order, duffel_get_offer, duffel_search_flights). This uniformity makes the tool set predictable and easy to navigate, with no deviations in naming style.
With 6 tools, the server is well-scoped for flight booking and search functionality. Each tool serves a distinct and necessary role in the workflow, from searching flights and airports to managing orders, without being overly sparse or bloated.
The tool set covers core flight booking operations comprehensively, including search, retrieval, and creation. However, there are minor gaps such as the absence of tools for updating or canceling orders, which could limit full lifecycle management, though agents might work around this by using existing tools for status checks.