Skip to main content
Glama
Renfe MCP Server

Renfe MCP Server

by belgrano9

Renfe MCP Server ๐Ÿš„

A Model Context Protocol (MCP) server for querying Renfe (Spanish national railway) train schedules using official GTFS data. Integrates seamlessly with Claude Desktop and other MCP-compatible clients.

Python 3.12+ FastMCP License: MIT

โœจ Features

  • ๐Ÿ” Search trains between any two Spanish cities on a specific date with pagination

  • ๐Ÿ’ฐ Check prices - real-time price scraping from Renfe website with pagination support

  • ๐Ÿš‰ Find stations in any city (Madrid has 7 stations!)

  • ๐Ÿ“… Flexible date parsing - accepts ISO, European, and written date formats

  • ๐Ÿ”„ Auto-updates - automatically downloads latest GTFS schedules from Renfe

  • โšก Fast & accurate - uses official Renfe GTFS data with complete timetables

  • ๐ŸŽฏ Smart filtering - handles service calendars, holidays, and exceptions

  • ๐Ÿ› ๏ธ Claude Desktop ready - works out of the box with MCP clients

Related MCP server: railinfo-mcp

๐Ÿš€ Quick Start

Prerequisites

  • Python 3.12 or higher

  • uv (recommended) or pip

Installation

  1. Clone the repository

    git clone https://github.com/yourusername/renfe_mcp.git
    cd renfe_mcp
  2. Install dependencies

    uv sync
  3. Run the server (GTFS data downloads automatically)

    uv run python -m renfe_mcp.server

๐Ÿ“– Usage

Standalone Testing

Test the search functionality directly:

from renfe_mcp.schedule_searcher import ScheduleSearcher
from renfe_mcp.price_checker import check_prices

# Search trains
searcher = ScheduleSearcher("renfe_schedule")
trains = searcher.search("Madrid", "Barcelona", "2025-11-20")

# Check prices
prices = check_prices("Madrid", "Barcelona", "2025-11-20")

Claude Desktop Integration

Add to your Claude Desktop config file:

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

{
  "mcpServers": {
    "renfe": {
      "command": "uv",
      "args": [
        "--directory",
        "C:\\Users\\YourName\\path\\to\\renfe_mcp",
        "run",
        "python",
        "-m",
        "renfe_mcp.server"
      ]
    }
  }
}

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

{
  "mcpServers": {
    "renfe": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/renfe_mcp",
        "run",
        "python",
        "-m",
        "renfe_mcp.server"
      ]
    }
  }
}

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

{
  "mcpServers": {
    "renfe": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/renfe_mcp",
        "run",
        "python",
        "-m",
        "renfe_mcp.server"
      ]
    }
  }
}

Restart Claude Desktop, and you can ask:

  • "Show me trains from Madrid to Barcelona tomorrow"

  • "What's the earliest train from Barcelona to Valencia on December 1st?"

  • "What train stations are in Madrid?"

  • "How many trains run between Madrid and Sevilla in the afternoon?"

  • "Check prices for trains from Madrid to Barcelona on December 1st"

  • "What are the ticket prices for the first 5 trains?"

๐Ÿ› ๏ธ MCP Tools

1. search_trains

Find trains between two cities on a specific date with pagination support.

Parameters:

  • origin (string): Origin city name (e.g., "Madrid", "Barcelona")

  • destination (string): Destination city name (e.g., "Valencia", "Sevilla")

  • date (string, optional): Travel date in flexible formats:

    • ISO: "2025-11-28"

    • European: "28/11/2025"

    • Written: "November 28, 2025"

    • Default: today's date

  • page (integer, optional): Page number to display (default: 1)

  • per_page (integer, optional): Results per page (default: 10, max: 50)

Example Output:

Found 36 train(s) total
Showing page 1 of 4 (10 trains)

  1. AVE
     Madrid Pta.Atocha - Almudena Grandes โ†’ Barcelona-Sants
     Departs: 6:16:00 | Arrives: 9:05:00
     Duration: 2h 49min

  2. AVE
     Madrid Pta.Atocha - Almudena Grandes โ†’ Barcelona-Sants
     Departs: 6:27:00 | Arrives: 9:25:00
     Duration: 2h 58min
  ...

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
To see more trains, use page=2
Total pages: 4

2. find_station

Search for train stations in a city.

Parameters:

  • city_name (string): City name to search (e.g., "Madrid")

Example Output:

Found 7 stations:

All stations found:
  1. Madrid-Chamartรญn-Clara Campoamor (ID: 17000)
  2. Madrid - Atocha Cercanรญas (ID: 18000)
  3. Madrid Pta.Atocha - Almudena Grandes (ID: 60000)
  ...

3. get_train_prices

Check actual ticket prices by scraping the Renfe website with pagination support.

Parameters:

  • origin (string): Origin city name (e.g., "Madrid", "Barcelona")

  • destination (string): Destination city name (e.g., "Valencia", "Sevilla")

  • date (string, optional): Travel date (same formats as search_trains)

  • page (integer, optional): Page number to display (default: 1)

  • per_page (integer, optional): Results per page (default: 5, max: 20)

Example Output:

PRICE CHECK RESULTS
From: Madrid -> Barcelona
Date: 2025-11-17
Showing 5 train(s)

  1. AVE
     Departs: 06:16 | Arrives: 09:05
     Duration: 2h 49min
     Price: 94.90 EUR | [Available]

  2. AVE
     Departs: 06:27 | Arrives: 09:25
     Duration: 2h 58min
     Price: 118.60 EUR | [Available]
  ...

To see more prices, try page=2

Note: This tool scrapes the Renfe website and may take a few seconds to complete. Pagination now matches search_trains so you can get prices for trains on any page (e.g., page 2 shows prices for trains 6-10).

๐Ÿ“Š Data Updates

The server includes automatic GTFS data updates from Renfe's open data portal.

Automatic Updates

On server startup, it checks for new data and downloads if needed:

uv run python -m renfe_mcp.server
# [CHECK] Checking data versions:
#         Server: 2025-11-15T00:40:21
#         Local:  2025-11-10T00:30:15
# [UPDATE] Server has newer data
# [DOWNLOAD] Downloading GTFS data...
# [OK] GTFS data updated successfully!

Manual Updates

Check and update if needed:

uv run python -m renfe_mcp.update_data

Force update (download regardless of version):

uv run python -m renfe_mcp.update_data --force

The update system:

  • โœ… Compares server version with local version

  • โœ… Only downloads when new data is available

  • โœ… Stores version info in renfe_schedule/.last_updated

  • โœ… Automatically extracts GTFS CSV files

๐Ÿ—๏ธ Architecture

renfe_mcp/
โ”œโ”€โ”€ pyproject.toml           # Dependencies & build config
โ”œโ”€โ”€ README.md                # This file
โ”œโ”€โ”€ src/renfe_mcp/           # Main package
โ”‚   โ”œโ”€โ”€ __init__.py          # Package exports
โ”‚   โ”œโ”€โ”€ server.py            # FastMCP server implementation
โ”‚   โ”œโ”€โ”€ config.py            # Pydantic configuration
โ”‚   โ”œโ”€โ”€ exceptions.py        # Exception hierarchy
โ”‚   โ”œโ”€โ”€ logging.py           # Structured logging
โ”‚   โ”œโ”€โ”€ security.py          # Auth & rate limiting
โ”‚   โ”œโ”€โ”€ price_checker.py     # Price checking module
โ”‚   โ”œโ”€โ”€ schedule_searcher.py # GTFS schedule search
โ”‚   โ”œโ”€โ”€ station_service.py   # Unified station lookups
โ”‚   โ”œโ”€โ”€ update_data.py       # GTFS data updater
โ”‚   โ””โ”€โ”€ scraper/             # Price scraper package
โ”‚       โ”œโ”€โ”€ __init__.py      # Package exports
โ”‚       โ”œโ”€โ”€ scraper.py       # RenfeScraper with DWR protocol
โ”‚       โ”œโ”€โ”€ dwr.py           # DWR utilities
โ”‚       โ”œโ”€โ”€ models.py        # Pydantic models
โ”‚       โ”œโ”€โ”€ exceptions.py    # Scraper exceptions
โ”‚       โ””โ”€โ”€ stations.json    # Station code database
โ”œโ”€โ”€ tests/                   # Test suite
โ”‚   โ”œโ”€โ”€ test_final_integration.py
โ”‚   โ”œโ”€โ”€ test_security.py
โ”‚   โ””โ”€โ”€ ...
โ””โ”€โ”€ renfe_schedule/          # GTFS data (auto-downloaded)
    โ”œโ”€โ”€ stops.txt            # Station information
    โ”œโ”€โ”€ routes.txt           # Train routes
    โ”œโ”€โ”€ trips.txt            # Trip schedules
    โ”œโ”€โ”€ stop_times.txt       # Arrival/departure times
    โ”œโ”€โ”€ calendar.txt         # Service schedules
    โ”œโ”€โ”€ calendar_dates.txt   # Holiday exceptions
    โ””โ”€โ”€ .last_updated        # Version tracking

How It Works

  1. City to Station Mapping: Fuzzy matches city names to station IDs

  2. Date Filtering:

    • Checks calendar.txt for service schedules (day of week)

    • Applies exceptions from calendar_dates.txt (holidays, special dates)

  3. Route Finding:

    • Joins trips, stop_times, and stops tables

    • Validates stop sequences and pickup/dropoff permissions

    • Ensures origin comes before destination

  4. Results: Returns all trains sorted chronologically with proper numeric time sorting

Key Implementation Details

  • โœ… Handles multiple stations per city (e.g., Madrid has 7)

  • โœ… Respects service exceptions (holidays, maintenance)

  • โœ… Validates passenger boarding/alighting permissions (pickup_type, drop_off_type)

  • โœ… Fixed sorting bug: Proper numeric time sorting (not lexicographic!)

  • โœ… CSV column whitespace handling (strips on load)

  • โœ… Complete result sets (no truncation)

๐Ÿ—บ๏ธ Supported Routes

The server supports any route in the Renfe network:

  • High-Speed (AVE): Madrid-Barcelona, Madrid-Sevilla, Madrid-Valencia

  • Long-Distance (ALVIA, Intercity): Major city connections

  • International (AVE INT): Cross-border services

  • Regional: Local routes across Spain

  • Commuter (Cercanรญas): Urban networks

Popular Cities:

  • Madrid (7 stations), Barcelona, Valencia

  • Sevilla, Mรกlaga, Bilbao, Zaragoza

  • Alicante, Cรณrdoba, Granada, Murcia

  • 100+ cities across Spain!

Use find_station to discover available stations in any city.

๐Ÿ”ง Development

Project Setup

# Clone and install
git clone https://github.com/yourusername/renfe_mcp.git
cd renfe_mcp
uv sync

# Run the server
uv run python -m renfe_mcp.server

# Run tests
uv run python tests/test_final_integration.py

Dependencies

  • fastmcp (>=0.7.0) - MCP server framework

  • pandas (>=2.3.3) - GTFS data processing

  • pydantic (>=2.11.7) - Data validation and models

  • pydantic-settings (>=2.0.0) - Environment-based configuration

  • httpx (>=0.27.0) - Modern HTTP client for price scraping

  • python-dateutil (>=2.8.2) - Flexible date parsing

  • json5 (>=0.12.0) - JavaScript object parsing for DWR responses

  • python-dotenv (>=1.0.0) - Environment variables

Configuration

Configure via environment variables (prefix RENFE_) or .env file:

# Authentication
RENFE_ENABLE_AUTH=true
RENFE_API_KEY=your-secret-key

# Rate Limiting
RENFE_RATE_LIMIT_ENABLED=true
RENFE_MAX_REQUESTS_PER_MINUTE=30
RENFE_MAX_REQUESTS_PER_HOUR=200

# Development
RENFE_DEV_MODE=false
RENFE_LOG_LEVEL=INFO

๐Ÿ“ Data Source

GTFS data from Renfe's Open Data Portal:

  • API Endpoint: https://data.renfe.com/api/3/action/resource_show

  • Resource ID: 25d6b043-9e47-4f99-bd91-edd51d782450

  • Update Frequency: Updated regularly by Renfe (checked on server startup)

  • Format: GTFS (General Transit Feed Specification)

  • Size: ~800 KB compressed, ~40 MB extracted

๐Ÿ› Known Issues

  • Windows console may show encoding errors with Unicode characters (functionality not affected)

  • Very large result sets (100+ trains) can be verbose but complete

๐Ÿค 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 (โœ… Implemented via web scraping)

  • Support for train status/delays

  • Multi-leg journey planning

  • Visualization of routes on maps

  • Additional query filters (train type, duration, etc.)

  • Return trip price checking

๐Ÿ“„ License

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

๐Ÿ™ Acknowledgments

  • Renfe Operadora for providing open GTFS data

  • FastMCP by @jlowin for the excellent MCP framework

  • Anthropic for Claude and the Model Context Protocol

  • The GTFS community for standardizing transit data

๐Ÿ“ฎ Support

๐Ÿ™ Sources & Inspiration

  • renfe-bot by @emartinez-dev - Telegram bot for Renfe train ticket monitoring. The DWR (Direct Web Remoting) protocol reverse-engineering and price scraping techniques were inspired by renfe-bot's implementation. This MCP server features a custom-built scraper using modern Python (httpx, pydantic) while preserving the core DWR protocol logic.


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

Travel smart, travel by train! ๐Ÿš„

Available Tools

3 tools
find_stationA

Search for train stations in a city and return matching options.

Useful for checking what stations are available in a city before searching for journeys.

Args: city_name: City name to search for (e.g., "Madrid", "Barcelona", "Valencia") api_key: API key for authentication (optional if configured via environment)

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

Inputs: city_name (required), api_key. Returns: result

get_train_pricesA

Check actual ticket prices for trains between two cities using web scraping with pagination.

NOTE: This tool scrapes the Renfe website and may take a few seconds to complete. It complements the search_trains tool by providing real-time price information. This endpoint has stricter rate limits due to web scraping.

Args: origin: Starting city name (e.g., "Madrid", "Barcelona", "Valencia") destination: Destination city name (e.g., "Madrid", "Barcelona", "Sevilla") date: Travel date. Accepts flexible formats: - ISO: "2025-11-28" (RECOMMENDED) - European: "28/11/2025" - Written: "November 28, 2025" or "28 November 2025" If not provided, checks prices for today's date. page: Page number to display (default: 1) per_page: Number of results per page (default: 5, max: 20) api_key: API key for authentication (optional if configured via environment)

Returns: Formatted string with train prices, availability, and booking information.

Inputs: origin (required), destination (required), date, page, +2 more. Returns: result

search_trainsA

Search for train journeys between two cities on a specific date.

Args: origin: Starting city name (e.g., "Madrid", "Barcelona", "Valencia") destination: Destination city name (e.g., "Madrid", "Barcelona", "Sevilla") date: Travel date. Accepts flexible formats: - ISO: "2025-11-28" (RECOMMENDED) - European: "28/11/2025" - Written: "November 28, 2025" or "28 November 2025" If not provided, searches for today's date. page: Page number to display (default: 1) per_page: Number of results per page (default: 10, max: 50) api_key: API key for authentication (optional if configured via environment)

Returns: Formatted string with available train options including times and durations.

Inputs: origin (required), destination (required), date, page, +2 more. Returns: result

Tool Schema Changelog

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

Loading tool schema changelogโ€ฆ

    TDQS

    A4.4/5.0

    Scored across 3 tools

    Disambiguation5/5

    Each tool serves a distinct purpose: station lookup, journey search, and price retrieval. No overlap in functionality.

    Naming Consistency5/5

    All tools follow a consistent verb_noun pattern in snake_case: find_station, get_train_prices, search_trains.

    Tool Count4/5

    Three tools cover the core workflow of finding stations, searching journeys, and checking prices. While minimal, it's appropriate for the scope.

    Completeness4/5

    Covers the essential travel information needs: station lookup, journey search, and pricing. Missing booking or detailed trip info, but acceptable for an info-focused server.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables real-time Indian Railways information retrieval, including live train running status, station schedules, and upcoming arrivals/departures.
      ISC
    • F
      license
      A
      quality
      D
      maintenance
      Enables querying SNCF train schedules and stations in France using the official Navitia API, with support for flexible date parsing and real-time journey planning.
      3
      1
      -
    • 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