Skip to content

Repository files navigation

SNCF MCP Server ๐Ÿš„

A Model Context Protocol (MCP) server for querying SNCF (French national railway) train schedules using the official Navitia API. Integrates seamlessly with Claude Desktop and other MCP-compatible clients.

Python 3.12+ FastMCP License: MIT

โœจ Features

  • ๐Ÿ” Search trains between any two French cities with real-time data
  • ๐Ÿš‰ Find stations in any city across France
  • ๐Ÿ“… Flexible date parsing - accepts ISO, European, and written date formats
  • โšก Real-time data - uses official SNCF Navitia API with live timetables
  • ๐ŸŽฏ Smart journey planning - shows transfers, duration, and route details
  • ๐ŸŒ International routes - supports cross-border journeys (e.g., Paris-Munich)
  • ๐Ÿ› ๏ธ Claude Desktop ready - works out of the box with MCP clients

๐Ÿš€ Quick Start

Prerequisites

  • Python 3.12 or higher
  • uv (recommended) or pip
  • SNCF API key (free registration)

Installation

  1. Clone the repository

    git clone https://github.com/belgrano9/sncf_mcp_server.git
    cd sncf_mcp_server
  2. Install dependencies

    uv sync
  3. Get your SNCF API key

  4. Configure environment variables

    Create a .env file in the project root:

    SNCF_API=your-api-key-here

    โš ๏ธ IMPORTANT: Never commit your .env file! It's already in .gitignore.

  5. Test the server

    uv run server.py

๐Ÿ“– Usage

Standalone Testing

Test the search functionality directly in Python:

from server import search_trains, find_station

# Search for trains
result = search_trains("Paris", "Lyon", "2025-11-20 14:00")
print(result)

# Find a station
stations = find_station("Paris")
print(stations)

Or use the included Jupyter notebook (test_notebook.ipynb) for interactive testing.

Claude Desktop Integration

Add to your Claude Desktop config file:

Windows (%APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "sncf": {
      "command": "uv",
      "args": [
        "--directory",
        "C:\\Users\\YourName\\path\\to\\sncf_mcp_server",
        "run",
        "server.py"
      ]
    }
  }
}

macOS (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "sncf": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/sncf_mcp_server",
        "run",
        "server.py"
      ]
    }
  }
}

Linux (~/.config/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "sncf": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/sncf_mcp_server",
        "run",
        "server.py"
      ]
    }
  }
}

Restart Claude Desktop, and you can ask:

  • "Show me trains from Paris to Lyon tomorrow at 2pm"
  • "What's the earliest train from Paris Gare de l'Est to Munich tomorrow?"
  • "Find all train stations in Paris"
  • "How long does it take to get from Bordeaux to Marseille?"

๐Ÿ› ๏ธ MCP Tools

1. search_trains

Find trains between two stations with real-time data.

Parameters:

  • origin (string): Origin station/city name (e.g., "Paris", "Lyon", "Paris Gare de l'Est")
  • destination (string): Destination station/city name (e.g., "Mรผnchen Hbf", "Barcelona")
  • departure_datetime (string, optional): Travel date/time in flexible formats:
    • ISO: "2025-11-28 08:00" (recommended)
    • European: "28/11/2025 08:00"
    • Written: "November 28, 2025 8:00am"
    • Default: current time

Example Output:

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    SNCF JOURNEY SEARCH
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

๐Ÿ” Searched for 'Paris Est':
  โœ“ Paris Gare de l'Est (ID: stop_area:SNCF:...)
    Paris - Bercy (ID: stop_area:SNCF:...)
    Paris Montparnasse (ID: stop_area:SNCF:...)

โ†’ Selected: Paris Gare de l'Est

๐Ÿ” Searched for 'Mรผnchen Hbf':
  โœ“ Mรผnchen Hauptbahnhof (ID: stop_area:OCE:...)

โ†’ Selected: Mรผnchen Hauptbahnhof

๐Ÿ“… Searching for trains departing after: 2025-11-28 08:00
๐Ÿ”„ API datetime format: 20251128T080000

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
๐Ÿš„ AVAILABLE TRAINS
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

Found 5 journey option(s):

  1. Depart: 2025-11-28 08:55 โ†’ Arrive: 2025-11-28 14:54
     Duration: 5h 59min | Direct

  2. Depart: 2025-11-28 10:55 โ†’ Arrive: 2025-11-28 16:54
     Duration: 5h 59min | Direct

  3. Depart: 2025-11-28 12:55 โ†’ Arrive: 2025-11-28 19:18
     Duration: 6h 23min | 1 change(s)
     Route: Paris Gare de l'Est โ†’ Stuttgart Hbf | Stuttgart Hbf โ†’ Mรผnchen Hbf

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

2. find_station

Search for train stations in a city or by name.

Parameters:

  • station_name (string): Station/city name to search (e.g., "Paris", "Lyon Part-Dieu")

Example Output:

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    STATION SEARCH
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

๐Ÿ” Searched for 'Paris':
  โœ“ Paris Gare de Lyon (ID: stop_area:SNCF:87686006)
    Paris Montparnasse (ID: stop_area:SNCF:87391003)
    Paris Gare du Nord (ID: stop_area:SNCF:87271007)

โ†’ Selected: Paris Gare de Lyon

โœ… Best match: Paris Gare de Lyon
   ID: stop_area:SNCF:87686006

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

3. get_train_prices โš ๏ธ EXPERIMENTAL

Educational Proof of Concept Only - May Not Work

Attempts to scrape price information from SNCF's booking system.

โš ๏ธ IMPORTANT DISCLAIMERS:

  • This is an experimental feature for educational purposes only
  • May violate SNCF's Terms of Service
  • Likely blocked by anti-scraping measures (403 Forbidden)
  • NOT recommended for production use
  • For real pricing, use commercial APIs (Lyko, Trainline) or SNCF Connect website

Parameters:

  • origin (string): Origin station/city name
  • destination (string): Destination station/city name
  • departure_datetime (string, optional): Travel date/time (same formats as search_trains)
  • page (integer, optional): Page number (default: 1)
  • per_page (integer, optional): Results per page (default: 5, max: 20)

Example Output (if it worked):

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  SNCF PRICE CHECK (EXPERIMENTAL)
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โš ๏ธ  WARNING: Experimental feature
    May not work due to anti-scraping measures
    For educational purposes only

๐Ÿ“ Route: Paris Gare de Lyon โ†’ Marseille Saint-Charles
๐Ÿ“… Date: 2025-11-17

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Attempting to fetch prices...
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

โŒ Price check failed: Access forbidden - anti-scraping measures detected

This feature is experimental and may not work.
For real pricing, please visit:
- SNCF Connect: https://www.sncf-connect.com
- Or use commercial API providers

Why This Probably Won't Work:

  • SNCF employs anti-scraping measures (403 Forbidden)
  • Requires reverse-engineering their booking API
  • API structure is proprietary and undocumented
  • May violate Terms of Service

Recommended Alternatives for Production:

See sncf_scraper/README.md for technical details and ethical considerations.

๐Ÿ—๏ธ Architecture

sncf_mcp_server/
โ”œโ”€โ”€ server.py              # FastMCP server implementation
โ”œโ”€โ”€ price_checker.py       # Price scraping wrapper (experimental)
โ”œโ”€โ”€ pyproject.toml         # Dependencies & project config
โ”œโ”€โ”€ .env                   # API key (not committed)
โ”œโ”€โ”€ .gitignore             # Git ignore rules
โ”œโ”€โ”€ README.md              # This file
โ”œโ”€โ”€ test_notebook.ipynb    # Jupyter notebook for testing
โ”œโ”€โ”€ sncf_scraper/          # Price scraper module (experimental)
โ”‚   โ”œโ”€โ”€ __init__.py          # Module exports
โ”‚   โ”œโ”€โ”€ models.py            # TrainOffer, PriceSearchResult models
โ”‚   โ”œโ”€โ”€ scraper.py           # SNCFPriceScraper implementation
โ”‚   โ””โ”€โ”€ README.md            # Scraper documentation & disclaimers
โ””โ”€โ”€ tests/                 # Test suite
    โ”œโ”€โ”€ test_simple.py         # Simple train search test
    โ”œโ”€โ”€ test_pagination.py     # Pagination feature test
    โ”œโ”€โ”€ test_search.py         # MCP wrapper test
    โ”œโ”€โ”€ test_price_scraper.py  # Price scraper tests (experimental)
    โ”œโ”€โ”€ debug_*.py             # Debug/diagnostic scripts
    โ”œโ”€โ”€ run_all_tests.py       # Test runner
    โ””โ”€โ”€ README.md              # Test documentation

How It Works

  1. Station Search: Queries Navitia API's /places endpoint with fuzzy matching
  2. Journey Planning: Uses /journeys endpoint with origin, destination, and datetime
  3. Date Parsing: Flexible parser handles multiple date/time formats
  4. Response Formatting: Returns human-readable journey information with:
    • Departure and arrival times
    • Journey duration
    • Number of transfers
    • Route details for multi-leg journeys

Key Implementation Details

  • โœ… Real-time data (no local database needed)
  • โœ… Flexible date parsing with python-dateutil
  • โœ… European date format support (day-first parsing)
  • โœ… Automatic station ID resolution from city names
  • โœ… Shows top 3 station matches for transparency
  • โœ… Handles both domestic and international routes
  • โœ… Transfer information with route breakdown
  • โœ… Pagination support - Returns 10 results per page (up to 100 journeys)
  • โœ… Comprehensive test suite - See tests/README.md

๐ŸŒ Supported Routes

The server supports any route in the SNCF/Navitia network:

  • High-Speed (TGV): Paris-Lyon, Paris-Marseille, Paris-Bordeaux, Paris-Strasbourg
  • International: Paris-London (Eurostar), Paris-Munich, Paris-Barcelona, Paris-Brussels
  • Long-Distance (Intercitรฉs): Regional connections across France
  • TER (Regional Express): Local services
  • Cross-border: Connections to Germany, Italy, Spain, Switzerland, Belgium

Major Cities:

  • Paris (multiple stations: Gare du Nord, Gare de Lyon, Montparnasse, Est, Austerlitz, Saint-Lazare, Bercy)
  • Lyon, Marseille, Bordeaux, Toulouse
  • Strasbourg, Nantes, Nice, Lille
  • International: London, Munich, Barcelona, Brussels, Geneva, Milan
  • 1000+ stations across France and Europe!

Use find_station to discover available stations in any city.

๐Ÿ”ง Development

Project Setup

# Clone and install
git clone https://github.com/belgrano9/sncf_mcp_server.git
cd sncf_mcp_server
uv sync

# Set up your API key in .env
echo "SNCF_API=your-api-key-here" > .env

# Run the server
uv run server.py

# Or use FastMCP dev mode
fastmcp dev server.py

Dependencies

  • fastmcp - MCP server framework
  • requests (>=2.32.5) - HTTP client for API calls
  • python-dotenv (>=1.2.1) - Environment variable management
  • python-dateutil - Flexible date/time parsing
  • httpx (>=0.28.1) - Async HTTP client
  • loguru (>=0.7.3) - Logging
  • rich (>=14.2.0) - Terminal formatting

File Structure

  • server.py - Main MCP server with search_trains and find_station tools
  • .env - API key configuration (never commit!)
  • test_notebook.ipynb - Interactive testing notebook
  • tests/ - Test suite (see tests/README.md)

Testing

Run the test suite to verify everything works:

# Run all tests
uv run tests/run_all_tests.py

# Run individual tests
uv run tests/test_simple.py       # Simple train search
uv run tests/test_pagination.py   # Pagination feature
uv run tests/debug_env2.py         # Environment check

See tests/README.md for detailed test documentation.

๐Ÿ“ Data Source

Real-time data from SNCF Navitia API:

  • API Base URL: https://api.sncf.com/v1
  • Authentication: HTTP Basic Auth (API key as username)
  • Coverage: SNCF network across France and international connections
  • Update Frequency: Real-time (no manual updates needed)
  • Format: JSON responses
  • Documentation: Navitia API Docs

Getting an API Key

  1. Visit SNCF Digital
  2. Create an account
  3. Request access to the Navitia API
  4. Copy your API key to .env

๐Ÿ› Known Issues

  • Windows console may show encoding errors with Unicode characters (functionality not affected)
  • Station name matching uses first result - use find_station for ambiguous names
  • International routes may have limited availability depending on API coverage

๐Ÿค Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Ideas for Contributions

  • Add price information (if available in API)
  • Support for train status/real-time delays
  • Multi-leg journey optimization
  • Visualization of routes on maps
  • Additional query filters (train type, max transfers, etc.)
  • Support for round-trip queries
  • Save favorite routes

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • SNCF for providing the Navitia open API
  • FastMCP by @jlowin for the excellent MCP framework
  • Anthropic for Claude and the Model Context Protocol
  • Navitia for powering the transit data API

๐Ÿ“ฎ Support

๐Ÿ”— Related Projects


Built with โค๏ธ using FastMCP and Claude

Voyagez intelligent, voyagez en train! ๐Ÿš„

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages