py-mcp-travelplanner 0.1.20
Minimal Azure Policy engine with file and sdk backends
License: MIT
Requires Python: <4.0,>=3.11.1

# MCP Travel Planner

**A unified MCP (Model Context Protocol) server providing a single entry point to comprehensive travel planning services.**

This project implements ONE unified MCP server that orchestrates multiple travel-related backend services (flights, hotels, weather, geocoding, events, finance). MCP clients like Claude Desktop connect to a single server interface and access all travel planning capabilities through it.

## Key Features

- **Single MCP Server Entry Point**: One unified server (`mcp_server.py`) for all travel services
- **Service Orchestration**: Manages multiple backend services through one interface  
- **MCP Tools**: Expose travel planning capabilities via Model Context Protocol
- **Claude Desktop Integration**: Ready-to-use configuration for Claude Desktop
- **Modular Backend**: Each service runs independently but is coordinated by the unified server
- **Runtime Configuration**: Multi-source config with env vars, .env, and YAML support

## Quick Start

**Ready-to-use MCP configuration examples** are provided in the `examples/` directory:

- **`claude_desktop_config_uv_testpypi.json`** - Run from Test PyPI with UV (no installation)
- **`claude_desktop_config_uv_pypi.json`** - Run from PyPI with UV (stable release)
- **`claude_desktop_config_template.json`** - Standard Python installation

See [`examples/QUICK_REFERENCE.md`](examples/QUICK_REFERENCE.md) for copy-paste configs and [`examples/MCP_CONFIG_README.md`](examples/MCP_CONFIG_README.md) for complete documentation.

## Configuration

The project uses a **multi-source runtime configuration system** with proper precedence:

1. **Environment variables** (highest priority)
2. **.env file**
3. **runtime_config.yaml**
4. **Default values** (lowest priority)

See [`docs/CONFIG_README.md`](docs/CONFIG_README.md) for complete configuration documentation.

## Architecture

```
MCP Client (Claude Desktop) 
        ↓ (stdio)
Unified MCP Server (single entry point)
        ↓ (orchestrates)
Backend Services (flight, hotel, weather, geocoder, finance, events)
```

## Status

- Prototype / Proof-of-Concept. Intended for local development, experimentation, and as a reference implementation for orchestration patterns.

## Key Concepts

- Modular microservice-style servers implemented as small Python scripts under `py_mcp_travelplanner/`.
- Each service lives in its own folder (for example `flight_server/`, `hotel_server/`, `weather_server/`) with a `main.py` or server entrypoint.
- A small CLI and control server are provided for orchestration and to demonstrate inter-service interactions.

## Contents

- `py_mcp_travelplanner/` — main package containing CLI, control server and per-service folders.
  - `flight_server/`, `hotel_server/`, `weather_server/`, `geocoder_server/`, `event_server/`, `finance_server/` — example service implementations.
- `requirements.txt` — pinned runtime/dev dependencies used by the project.
- `tests/` — pytest-based unit tests and lifecycle tests.
- `examples/` — MCP configuration examples for Claude Desktop and other clients.

## Quick Start (Local Development)

### Prerequisites

- Linux / macOS / Windows with WSL
- Python 3.12.1 or later is recommended for development

### Recommended: Create and use a virtual environment

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
```

### Install dependencies

**Option A — pip (quick)**

```bash
pip install -r requirements.txt
```

**Option B — poetry (if you prefer pyproject/poetry workflows)**

```bash
poetry install
```

### Running services

Each server folder contains a runnable entrypoint (usually `main.py`). From the repository root you can start any server directly with Python. For example:

```bash
# run the flight server
python py_mcp_travelplanner/flight_server/main.py

# run the weather server
python py_mcp_travelplanner/weather_server/main.py

# run the control server (if present)
python py_mcp_travelplanner/control_server.py
```

**Note:** Some servers may expect environment variables or API keys; check the server's README under the corresponding server folder for provider-specific setup.

## Unified MCP Server — Access All Services Through One Interface

The **unified MCP server** (`py_mcp_travelplanner/mcp_server.py`) provides a single entry point to all travel planning services. Instead of running and configuring multiple separate MCP servers, you can use ONE server that automatically discovers and integrates all available subservices.

### Key Benefits

- **Single Connection**: MCP clients connect to one server instead of six
- **Auto-Discovery**: Automatically finds and loads all available services
- **Namespaced Tools**: Clear tool organization (e.g., `event.search_events`, `flight.search_flights`)
- **Service Management**: Start, stop, and monitor subservices through MCP tools
- **Unified Interface**: Consistent access patterns across all travel services

### Running the Unified Server

```bash
# Run the unified MCP server
python -m py_mcp_travelplanner.mcp_server

# Or via CLI
py-mcp-travel unified
```

### Available Services & Tools

The unified server integrates:

| Service | Tools | Description |
|---------|-------|-------------|
| **event** | `search_events`, `get_event_details`, `list_events` | Event search and discovery |
| **flight** | `search_flights`, `get_flight_details`, `list_flights` | Flight search and booking |
| **hotel** | `search_hotels`, `get_hotel_details`, `list_hotels` | Hotel search and reservations |
| **weather** | `get_weather`, `get_forecast` | Weather forecasts |
| **geocoder** | `geocode`, `reverse_geocode` | Location geocoding |
| **finance** | `get_exchange_rates`, `convert_currency` | Currency exchange |

### Management Tools

- `list_services` - Show all integrated services and their tools
- `get_service_manifest` - Get detailed JSON manifest of all services
- `get_status` - Overall system status
- `start_server` / `stop_server` - Manage individual subservices
- `health_check` - Check service health

### Claude Desktop Configuration

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "travel_planner_local": {
      "command": "python",
      "args": ["-m", "py_mcp_travelplanner.mcp_server"],
      "env": {
        "SERPAPI_KEY": "your-api-key-here"
      }
    }
  }
}
```

### Example Usage

Once connected, use namespaced tool names:

```python
# Search for events in New York
event.search_events({
  "query": "concerts",
  "location": "New York",
  "date_filter": "week"
})

# Search for flights
flight.search_flights({
  "departure_id": "JFK",
  "arrival_id": "LAX",
  "outbound_date": "2025-06-15"
})

# Get weather forecast
weather.get_forecast({
  "location": "New York",
  "days": 7
})
```

### Documentation

For complete details about the unified server architecture, see **[docs/UNIFIED_SERVER.md](docs/UNIFIED_SERVER.md)**.

### CLI

# run the weather server
python py_mcp_travelplanner/weather_server/main.py

# run the control server (if present)
python py_mcp_travelplanner/control_server.py
```

**Note:** Some servers may expect environment variables or API keys; check the server's README under the corresponding server folder for provider-specific setup.

### CLI

A simple CLI is available under `py_mcp_travelplanner/cli.py` and `py_mcp_travelplanner/cli_handlers.py`. You can run the CLI script to access helper commands used in development:

```bash
python -m py_mcp_travelplanner.cli
```

(If the package isn't installed as a module, run the file directly: `python py_mcp_travelplanner/cli.py`.)

## Unified MCP Server — Single Entry Point Architecture

This project provides **ONE unified MCP server** that acts as a single entry point to all travel planner services. The server is located at `py_mcp_travelplanner/mcp_server.py` and orchestrates all backend services (flights, hotels, weather, geocoding, events, finance) through a single Model Context Protocol interface.

### Architecture Overview

- **Single MCP Server**: One unified server exposing all travel planning capabilities
- **Service Orchestration**: The MCP server manages and coordinates multiple backend services
- **Unified Interface**: MCP clients connect to one server and access all travel services through it

## MCP Server Configuration

### For Claude Desktop and MCP Clients

Ready-to-use configuration files are provided in the `examples/` directory:

**Option 1: UV with Test PyPI** (recommended for testing)
```json
{
  "mcpServers": {
    "py_mcp_travelplanner_testpypi": {
      "command": "uv",
      "args": [
        "run",
        "--index",
        "https://test.pypi.org/simple",
        "--with",
        "py_mcp_travelplanner",
        "--no-project",
        "--",
        "py_mcp_travelplanner_cli"
      ],
      "env": {
        "SERPAPI_KEY": "your_serpapi_key_here"
      }
    }
  }
}
```

**Option 2: UV with PyPI** (stable release)
```json
{
  "mcpServers": {
    "py_mcp_travelplanner": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "py_mcp_travelplanner",
        "--no-project",
        "--",
        "py_mcp_travelplanner_cli"
      ],
      "env": {
        "SERPAPI_KEY": "your_serpapi_key_here"
      }
    }
  }
}
```

**Option 3: Local Installation**
```json
{
  "mcpServers": {
    "py_mcp_travelplanner": {
      "command": "python",
      "args": ["-m", "py_mcp_travelplanner.mcp_server"],
      "env": {
        "SERPAPI_KEY": "your_serpapi_key_here"
      }
    }
  }
}
```

**Configuration locations by OS:**
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux**: `~/.config/Claude/claude_desktop_config.json`

See [`examples/MCP_CONFIG_README.md`](examples/MCP_CONFIG_README.md) for complete setup instructions.

### Environment Variables

Set these in the MCP config `env` section or in your shell:

**Required:**
- `SERPAPI_KEY` - Your SerpAPI key (get from https://serpapi.com/)

**Optional (with defaults):**
- `LOG_LEVEL` - `DEBUG`, `INFO`, `WARNING`, `ERROR` (default: `INFO`)
- `CONTROL_SERVER_PORT` - Server port (default: `8787`)
- `DEBUG_MODE` - Enable debug mode: `true`/`false` (default: `false`)
- `DRY_RUN` - Test mode without side effects: `true`/`false` (default: `false`)

See [`docs/CONFIG_README.md`](docs/CONFIG_README.md) for all configuration options.

### What the unified MCP server exposes

- **Tools**: `list_servers`, `start_server`, `start_all_servers`, `stop_server`, `health_check`, `get_status`, `list_pids`, `verify_serpapi_key`
- **Services**: event_server, finance_server, flight_server, geocoder_server, hotel_server, weather_server
- Each tool accepts a JSON-like arguments object and returns TextContent responses

## Running the MCP Server

### Method 1: With Claude Desktop (Recommended)

1. **Get a SERPAPI key** from https://serpapi.com/ (free tier: 100 searches/month)

2. **Choose a configuration** from `examples/`:
   - For testing: `claude_desktop_config_uv_testpypi.json`
   - For production: `claude_desktop_config_uv_pypi.json`
   - For local dev: `claude_desktop_config_template.json`

3. **Copy to Claude Desktop config location** (see paths above)

4. **Edit the config** and replace `your_serpapi_key_here` with your actual key

5. **Restart Claude Desktop**

The travel planner tools will now be available in your Claude conversations!

### Method 2: Direct Execution (for testing)

```bash
# Start the unified MCP server
python -m py_mcp_travelplanner.mcp_server

# Or use the CLI helper
python -m py_mcp_travelplanner.cli mcp
```

## Available MCP Tools

When connected to the unified MCP server, you'll have access to these tools:

- **list_servers**: List all available travel service backends
- **start_server**: Start a specific service (event, flight, hotel, weather, etc.)
- **start_all_servers**: Start all services at once
- **stop_server**: Stop a running service by name or PID
- **health_check**: Verify a service is healthy and ready
- **get_status**: Get overall system status and running services
- **list_pids**: List all running service process IDs
- **verify_serpapi_key**: Test if SERPAPI_KEY is configured correctly

### Tool call JSON examples (conceptual)

When calling a tool via an MCP client you will call the tool by name and pass the corresponding arguments object. The exact outer envelope depends on the MCP client library you use; below are the argument payloads for the most common operations:

- Start a server (dry run):
```json
{ "server": "flight_server", "dry_run": true }
```

- Start a server (actual start):
```json
{ "server": "flight_server", "dry_run": false }
```

- Start all servers (dry run):
```json
{ "dry_run": true }
```

- Stop a server (by name):
```json
{ "server": "flight_server", "timeout": 5.0 }
```

- Stop a server (by PID):
```json
{ "server": 12345, "timeout": 5.0 }
```

- Health check:
```json
{ "server": "flight_server" }
```

- Get overall status (no arguments):
```json
{}
```

### Expected responses

The server returns an array of TextContent objects (the `mcp` library encodes this). When using an MCP client, you should inspect the returned text field(s). For example a `get_status` call may return a single element whose `text` contains a human-readable status summary.

## HTTP Control Server (Concrete, Scriptable)

For convenience there is a small HTTP control server (`py_mcp_travelplanner/control_server.py`) that wraps a subset of the MCP server functionality and exposes simple HTTP endpoints. This is recommended for quick scripting and interactive use.

### Start the control server (background)

```bash
python py_mcp_travelplanner/control_server.py
# or, using the CLI helper
python -m py_mcp_travelplanner.cli serve --host 127.0.0.1 --port 8787
```

### Useful curl examples

- Get status (discovered servers + SERPAPI presence):
```bash
curl -s http://127.0.0.1:8787/status | jq
```

- Health check for a server:
```bash
curl -s "http://127.0.0.1:8787/health?server=flight_server" | jq
```

- Start a single server (dry run):
```bash
curl -X POST "http://127.0.0.1:8787/start?server=flight_server&dry=true" | jq
```

- Start all servers (actual start):
```bash
curl -X POST "http://127.0.0.1:8787/start_all?dry=false" | jq
```

- Stop a server by name:
```bash
curl -X POST "http://127.0.0.1:8787/stop?server=flight_server" | jq
```

- List registered PIDs:
```bash
curl -s http://127.0.0.1:8787/pids | jq
```

- Verify SERPAPI_KEY (performs a test request using the configured key):
```bash
curl -X POST http://127.0.0.1:8787/test_key | jq
```

### Python example

```python
import requests

BASE = "http://127.0.0.1:8787"

# get status
print(requests.get(f"{BASE}/status").json())

# start flight server (dry-run)
print(requests.post(f"{BASE}/start?server=flight_server&dry=true").json())

# start all
print(requests.post(f"{BASE}/start_all?dry=false").json())

# verify serpapi
print(requests.post(f"{BASE}/test_key").json())
```

## Advanced Usage: Multi-Server Orchestration & HTTP API

### Running Individual Servers (stdio or HTTP)

Each backend server (weather, event, hotel, flight, finance, geocoder) can be started with either stdio (default) or HTTP transport, and exposes a manifest for tool discovery:

```bash
# Start weather server with HTTP API
python -m py_mcp_travelplanner.weather_server.main --transport http --host 127.0.0.1 --port 8791

# Start event server with stdio (default)
python -m py_mcp_travelplanner.event_server.main

# Print tool manifest/schema for debugging
python -m py_mcp_travelplanner.weather_server.main --manifest
```

### Unified Launcher Script

You can launch all servers from a single config file (YAML or JSON) using the provided script:

```bash
python scripts/run_mcp_from_config.py --config runtime_config.yaml
```

Example config (runtime_config.yaml):
```yaml
servers:
  weather:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8791
  event:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8796
  hotel:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8795
  flight:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8793
  finance:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8792
  geocoder:
    enabled: true
    transport: http
    host: 127.0.0.1
    port: 8794
SERPAPI_KEY: "your_serpapi_key_here"
```

This will launch all enabled servers with the specified transport and ports. Press Ctrl+C to stop all servers.

### Integration Testing: HTTP Endpoints & Manifest

You can test HTTP endpoints and manifest output for any server:

```bash
# Test weather server HTTP endpoint
curl http://127.0.0.1:8791/manifest

# Or print manifest to stdout
python -m py_mcp_travelplanner.weather_server.main --manifest
```

You can also write integration tests in pytest to verify HTTP endpoints and manifest output. See the 'tests/' folder for examples.

## Tests

Run the test suite with pytest:

```bash
# Run all tests
pytest -q

# Run MCP server tests specifically
pytest tests/test_mcp_server.py -v

# Run with coverage
pytest --cov=py_mcp_travelplanner --cov-report=html
```

**Test Coverage**:
- **MCP Server Tests**: 25 tests covering all 8 tools, initialization, and workflows
- **Config Tests**: 28 tests covering runtime configuration system
- **Total**: 58 tests passing

## Development Notes (Important)

### 1) Consolidate pyproject files

The repository currently contains service-level metadata and possibly extra `pyproject.toml` files inside server folders. For a single-source-of-truth dependency management approach, consolidate those service-level `pyproject.toml` contents into the root `pyproject.toml` and remove or archive the per-server `pyproject.toml` files. This simplifies CI, local dependency installation, and version pinning.

### 2) Harmonize shared dependencies (requests example)

Several service folders may declare their own `requests` version. To avoid mismatched runtime behavior, pin `requests` at the root `pyproject.toml` (or `requirements.txt`) to a single compatible version range and update any server-specific files to rely on the root manifest.

### 3) Python compatibility and dependency constraints

Some dependencies in the ecosystem (for example `openapi-pydantic`) declare compatibility for Python versions `<4.0,>=3.8`. To remain compatible with such packages while still using modern Python, set the project Python requirement to a range that excludes Python 4.0. For example in `pyproject.toml` set:

```toml
python = ">=3.12.1,<4.0"
```

This avoids dependency resolution errors if someone installs or runs the project on Python 4.x while the dependencies do not declare support for it.

### 4) Harmonize dependency versions across the monorepo

When merging per-server manifests, ensure shared libraries (requests, aiohttp, pydantic, etc.) are pinned consistently. Run a dependency resolver (pip-tools, poetry) and test local execution after changes.

## Troubleshooting

- If a server fails to start due to missing environment variables or API keys, check the server folder README for provider-specific instructions.
- If you hit dependency resolution errors, run `pip check` or `poetry lock` to see conflicts and adjust the root manifest accordingly.

## Contributing

- Fork the repository, create a feature branch, and open a pull request against the main branch.
- Keep changes focused: if you're changing dependencies, update `pyproject.toml`/`requirements.txt` and add a short rationale in the PR summary.
- Run tests locally and ensure linting passes before opening a PR.

## License

See the `LICENSE` file in the repository root.

## Acknowledgements

This repository is a learning / POC project showcasing modular service layouts, simple orchestration, and packaging considerations for small multi-service Python projects.

## Contact

For questions or help, open an issue in this repository with details about your environment and the problem you're encountering.