Bing Flights MCP Server
# Bing Flights MCP Server
[](https://pypi.org/project/bing-flights-mcp/)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
A Model Context Protocol (MCP) server that scrapes flight information from Bing Flights using Playwright. This project provides both a standalone Python scraper module and an MCP server wrapper for integration with MCP-compatible applications.
**š¦ [View on PyPI](https://pypi.org/project/bing-flights-mcp/)**
## Features
- š Search for one-way and round-trip flights
- āļø Support for multiple passengers (adults, children, infants)
- šŗ All cabin classes (Economy, Premium Economy, Business, First)
- š¤ Headless or headed browser modes
- š Structured JSON responses
- š§ Easy integration via MCP protocol
## Project Structure
```
bing-flights-mcp/
āāā pyproject.toml # Package configuration
āāā requirements.txt # Python dependencies
āāā README.md # This file
āāā bing_flights_scraper/ # Standalone scraper module
ā āāā __init__.py
ā āāā scraper.py
āāā mcp_server.py # MCP server implementation
āāā tests/ # Test suite
āāā __init__.py
āāā test_mcp.py
āāā test_e2e.py
```
## Installation
### Quick Start (Recommended)
The easiest way to use this MCP server is with `uvx`:
```bash
uvx bing-flights-mcp
```
This will automatically install the package and its dependencies in an isolated environment.
### Installation via pip
You can also install from PyPI:
```bash
pip install bing-flights-mcp
```
After installation, install the Playwright browser:
```bash
playwright install chromium
```
### Development Installation
For development or if you want to modify the code:
1. **Clone or download this repository**
2. **Create and activate a virtual environment**
On Windows:
```bash
python -m venv venv
venv\Scripts\activate
```
On macOS/Linux:
```bash
python -m venv venv
source venv/bin/activate
```
3. **Install dependencies**
```bash
pip install -r requirements.txt
```
4. **Install Playwright browsers**
```bash
playwright install chromium
```
## Usage
### As an MCP Server
#### Using uvx (Recommended)
If you installed via PyPI, run:
```bash
uvx bing-flights-mcp
```
Or add to your MCP settings configuration:
```json
{
"mcpServers": {
"bing-flights": {
"command": "uvx",
"args": ["bing-flights-mcp"]
}
}
}
```
#### Running from Source
If you're developing or running from source:
```bash
python mcp_server.py
```
#### Available Tools
The MCP server exposes two tools:
**1. `search_flights`**
Search for flight options from Bing Flights.
**Parameters:**
- `origin` (string, required): Origin airport code (e.g., "SEA")
- `destination` (string, required): Destination airport code (e.g., "ICN")
- `departure_date` (string, required): Departure date in YYYY-MM-DD format
- `return_date` (string, optional): Return date for round-trip searches
- `adults` (integer, optional, default=1): Number of adult passengers
- `children` (integer, optional, default=0): Number of child passengers
- `infants` (integer, optional, default=0): Number of infant passengers
- `cabin_class` (integer, optional, default=0): 0=Economy, 1=Premium Economy, 2=Business, 3=First
- `max_results` (integer, optional, default=10): Maximum number of results
- `headless` (boolean, optional, default=true): Run browser in headless mode
**Example MCP Tool Call:**
```json
{
"origin": "SEA",
"destination": "ICN",
"departure_date": "2025-11-30",
"return_date": "2025-12-02",
"adults": 1,
"cabin_class": 0,
"max_results": 10,
"headless": true
}
```
**2. `get_scraper_status`**
Check scraper health and configuration.
**Example Response:**
```json
{
"status": "healthy",
"version": "1.0.1",
"capabilities": {
"one_way_search": true,
"round_trip_search": true,
"cabin_classes": ["economy", "premium_economy", "business", "first"],
"max_results": 50,
"headless_mode": true
}
}
```
### As a Standalone Python Module
You can also use the scraper directly in your Python code:
```python
from bing_flights_scraper import BingFlightsScraper
# Create scraper instance
scraper = BingFlightsScraper(headless=True)
try:
# Search for flights
results = scraper.search_flights(
origin="SEA",
destination="ICN",
departure_date="2025-11-30",
return_date="2025-12-02",
adults=1,
cabin_class=0,
max_results=10
)
# Process results
print(f"Found {results['results_count']} flights")
for flight in results['flights']:
print(f"Price: ${flight['price']['total']}")
print(f"Airlines: {', '.join(flight['airlines'])}")
print(f"Departure: {flight['outbound']['departure_time']}")
print(f"Arrival: {flight['outbound']['arrival_time']}")
print(f"Duration: {flight['outbound']['duration']}")
print("---")
finally:
scraper.close()
```
## Response Format
The scraper returns results in the following JSON structure:
```json
{
"search_params": {
"origin": "SEA",
"destination": "ICN",
"departure_date": "2025-11-30",
"return_date": "2025-12-02",
"trip_type": "round-trip",
"passengers": {
"adults": 1,
"children": 0,
"infants": 0
},
"cabin_class": "economy"
},
"results_count": 10,
"flights": [
{
"price": {
"total": 1200.00,
"currency": "USD",
"per_person": 1200.00
},
"airlines": ["Korean Air", "Delta"],
"outbound": {
"departure_time": "10:30",
"arrival_time": "14:45",
"duration": "13h 15m",
"stops": 1,
"layovers": [],
"flight_numbers": []
},
"booking_link": "https://www.bing.com/...",
"result_index": 1
}
],
"timestamp": "2025-10-23T02:19:00Z"
}
```
## Configuration Options
### Cabin Classes
- `0` - Economy
- `1` - Premium Economy
- `2` - Business
- `3` - First Class
### Browser Modes
- `headless=True` - Browser runs in the background (faster, no UI)
- `headless=False` - Browser window visible (useful for debugging)
## Troubleshooting
### Common Issues
**Issue: Playwright browser not found**
```
Solution: Run `playwright install chromium`
```
**Issue: Timeout waiting for flight results**
```
Solution:
- Check your internet connection
- Try with headless=False to see what's happening
- Verify the airport codes are valid
- Ensure the dates are in the future
```
**Issue: No results returned**
```
Solution:
- Verify airport codes are correct (use IATA codes like "SEA", "ICN")
- Check that dates are in YYYY-MM-DD format
- Try different date ranges
- Some routes may not have available flights
```
**Issue: Import errors**
```
Solution:
- Ensure virtual environment is activated
- Run `pip install -r requirements.txt` again
- Verify Python version is 3.10 or higher
```
### Debugging
To debug scraping issues, run with `headless=False`:
```python
scraper = BingFlightsScraper(headless=False)
```
This will show the browser window so you can see what's being loaded.
## Running Tests
### Basic Tests
Run the basic unit tests that verify module imports and URL construction:
```bash
python tests/test_mcp.py
```
### End-to-End Tests
Run comprehensive end-to-end tests that perform actual flight searches:
```bash
python tests/test_e2e.py
```
**Note:** E2E tests make real web requests to Bing Flights and may take several minutes to complete. They include:
1. **Invalid Parameters Test** - Verifies error handling
2. **One-Way Search Test** - Real search from SEA to ICN
3. **Round-Trip Search Test** - Real search from LAX to JFK
4. **Multiple Passengers Test** - Search with 2 adults and 1 child
The tests use headless browser mode and future dates to ensure valid searches.
## Technical Details
### Web Scraping Approach
- Uses Playwright for browser automation
- Waits for dynamic content to load
- Extracts data from Bing Flights result cards
- Handles multiple selector patterns for robustness
### Error Handling
The scraper uses minimal error handling and allows exceptions to propagate:
- Network errors ā Raises exception
- Timeout errors ā Raises `PlaywrightTimeoutError`
- Invalid parameters ā Raises `ValueError`
- Parsing errors ā Returns partial results or empty list
This design allows the MCP client to implement appropriate retry logic and error recovery.
## Limitations
- Only returns outbound flight details (return flight info not available on Bing results page)
- Maximum results limited by what's visible on the initial page load
- No pagination support (first page results only)
- Scraping depends on Bing's page structure (may break if they change their HTML)
## Dependencies
- `fastmcp>=0.1.0` - MCP server framework
- `playwright>=1.40.0` - Browser automation
- `python-dateutil>=2.8.2` - Date parsing utilities
## Contributing
When contributing, please:
1. Test changes with both headless and headed modes
2. Verify compatibility with the MCP protocol
3. Update documentation for new features
4. Follow existing code style and patterns
## License
MIT License - See LICENSE file for details
## Disclaimer
This tool scrapes publicly available data from Bing Flights. Please:
- Use responsibly and respect rate limits
- Review Bing's Terms of Service
- Do not use for commercial purposes without proper authorization
- Be aware that web scraping may break if the website changes
## Support
For issues, questions, or contributions, please open an issue on the project repository.TDQS
Scored across 2 tools
The two tools have completely distinct purposes: get_scraper_status is for health/configuration monitoring, while search_flights is for flight search operations. There is no overlap or ambiguity between these functions.
Both tools follow a consistent verb_noun naming pattern (get_scraper_status, search_flights) with clear, descriptive names. The naming convention is uniform throughout the tool set.
With only 2 tools, this server feels severely under-scoped for a flight search domain. A typical flight search service would need tools for booking, fare details, filtering, or itinerary management, making this set incomplete for practical use.
The tool surface is highly incomplete for flight search functionality. While search_flights covers basic search, there are no tools for booking, retrieving booking details, managing itineraries, or handling cancellations, leaving significant gaps in the domain coverage.