belgrano9/sncf_mcp_server
If you are the rightful owner of sncf_mcp_server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
The SNCF MCP Server is a Model Context Protocol server designed for querying French national railway train schedules using the official Navitia API.
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
.envfile in the project root:SNCF_API=your-api-key-here⚠️ IMPORTANT: Never commit your
.envfile! 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):
{
"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
- ISO:
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 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 - Commercial provider
- Trainline API - Multi-operator booking
- Official SNCF partnership programs
See 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
🌍 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 )
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 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 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! 🚄