Skip to main content
Glama
SNCF MCP Server

SNCF MCP Server

by belgrano9

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

Related MCP server: mcp-sncf-navitia

๐Ÿš€ 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


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

Voyagez intelligent, voyagez en train! ๐Ÿš„

Available Tools

3 tools
find_stationA

Search for a train station by name and return matching options.

Useful for checking station names before searching for journeys, or when you're not sure of the exact station name.

Args: station_name: Station name to search for (e.g., "Paris", "Munich", "Lyon")

Returns: A formatted string showing matching stations with their IDs and full names.

Inputs: station_name (required). Returns: result

get_train_pricesA

Get train prices (EXPERIMENTAL - Educational Proof of Concept).

โš ๏ธ WARNING: This is an experimental feature that attempts to scrape prices from SNCF. It may not work due to:

  • Anti-scraping measures

  • API changes

  • Terms of Service restrictions

For production use, consider:

  • Lyko SNCF Connect API

  • Trainline API

  • Official SNCF partnerships

Args: origin: Origin station name (e.g., "Paris", "Lyon") destination: Destination station name (e.g., "Marseille") departure_datetime: Date/time in flexible formats (default: today) page: Page number for pagination (default: 1) per_page: Results per page (default: 5, max: 20)

Returns: Formatted string with price information (if available)

Inputs: origin (required), destination (required), page, per_page, +1 more. Returns: result

search_trainsA

Search for train journeys between two stations with pagination.

Args: origin: Starting station name (e.g., "Paris Est", "Lyon") destination: Destination station name (e.g., "Mรผnchen Hbf", "Barcelona") departure_datetime: Optional datetime. Accepts flexible formats: - ISO: "2025-11-28 08:00" (RECOMMENDED) - European: "28/11/2025 08:00" - Written: "November 28, 2025 8:00am" If not provided, searches from current time. page: Page number for pagination (default: 1). Shows 10 results per page. Request different pages to see more trains (e.g., page=2, page=3).

Inputs: origin (required), destination (required), page, departure_datetime. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelogโ€ฆ

    TDQS

    A4.7/5.0

    Scored across 3 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: search_trains finds journeys, find_station resolves station names, and get_train_prices retrieves pricing. Although search_trains and get_train_prices share origin/destination parameters, their descriptions and return types make them unambiguous.

    Naming Consistency5/5

    All tool names follow the verb_noun pattern with lowercase and underscores: search_trains, find_station, get_train_prices. This is consistent and predictable.

    Tool Count5/5

    With 3 tools, the server is minimal but well-scoped for train journey searching. Each tool serves a necessary function and there is no redundancy.

    Completeness4/5

    The server covers the core workflow: station lookup, journey search, and price lookup. Missing booking or real-time status, but these are beyond the apparent scope. The experimental nature of get_train_prices introduces some uncertainty, but the surface is otherwise complete for planning.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      A modular Python wrapper for the SNCF API that integrates with Claude Desktop, enabling intelligent journey planning and train information retrieval across France's railway network.
      21
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables querying SNCF Open Data (train schedules, stations, punctuality, etc.) through natural language or direct tool calls, with dataset search, metadata retrieval, and ODSQL querying.
      105 npm
      MIT
    • F
      license
      A
      quality
      D
      maintenance
      Connects AI assistants to Swiss Federal Railways (SBB/CFF/FFS) data: train schedules, station search, ticket prices, and direct ticket purchase links.
      6
      79 npm
      -