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.
  
✨ 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
- Clone the repository
git clone https://github.com/belgrano9/sncf_mcp_server.git
cd sncf_mcp_server
- Install dependencies
uv sync
- Get your SNCF API key
- Register at SNCF Digital API Portal
- Request access to the Navitia API
- Copy your API key
- Configure environment variables
Create a .env file in the project root: ``env SNCF_API=your-api-key-here ``
⚠️ IMPORTANT: Never commit your .env file! It's already in .gitignore.
- 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): ``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): ``json { "mcpServers": { "sncf": { "command": "uv", "args": [ "--directory", "/path/to/sncf_mcp_server", "run", "server.py" ] } } } ``
Linux (~/.config/Claude/claude_desktop_config.json): ``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):
- Depart: 2025-11-28 08:55 → Arrive: 2025-11-28 14:54
Duration: 5h 59min | Direct
- Depart: 2025-11-28 10:55 → Arrive: 2025-11-28 16:54
Duration: 5h 59min | Direct
- 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 namedestination(string): Destination station/city namedeparture_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:**
- [Lyko SNCF Connect API](https://lyko.tech/en/portfolio/train-api/sncf-connect-api/) - Commercial provider
- [Trainline API](https://www.thetrainline.com) - Multi-operator booking
- Official SNCF partnership programs
See [sncf_scraper/README.md](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
- Station Search: Queries Navitia API's
/placesendpoint with fuzzy matching - Journey Planning: Uses
/journeysendpoint with origin, destination, and datetime - Date Parsing: Flexible parser handles multiple date/time formats
- 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 withsearch_trainsandfind_stationtools.env- API key configuration (never commit!)test_notebook.ipynb- Interactive testing notebooktests/- 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
- Visit SNCF Digital
- Create an account
- Request access to the Navitia API
- 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_stationfor ambiguous names - International routes may have limited availability depending on API coverage
🤝 Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - 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
- Issues: GitHub Issues
- API Documentation: Navitia API Docs
- MCP Docs: Model Context Protocol
🔗 Related Projects
- Renfe MCP Server - Similar server for Spanish railways
- FastMCP - The framework powering this server
- MCP Servers - Official MCP server implementations
---
Built with ❤️ using FastMCP and Claude
Voyagez intelligent, voyagez en train! 🚄











