IndianRailwaysMCP
by Shadhai
README.md
<div align="center">
<img src="https://capsule-render.vercel.app/api?type=waving&color=0:1488cc,50:2b32b2,100:4facfe&height=220§ion=header&text=%F0%9F%9A%82%20Indian%20Railways%20MCP&fontSize=46&fontColor=ffffff&fontAlignY=38&desc=Real-time%20Indian%20Railways%20data%20for%20AI%20assistants&descAlignY=60&descSize=18&animation=fadeIn" width="100%" />
</div>
<div align="center">
<img src="https://img.shields.io/badge/Build-Passing-brightgreen?style=for-the-badge&logo=github-actions&logoColor=white" />
<img src="https://img.shields.io/badge/License-MIT-blue?style=for-the-badge&logo=open-source-initiative&logoColor=white" />
<img src="https://img.shields.io/badge/Version-1.0.0-orange?style=for-the-badge&logo=semver&logoColor=white" />
<img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?style=for-the-badge&logo=python&logoColor=white" />
<img src="https://img.shields.io/badge/MCP-Compatible-4facfe?style=for-the-badge&logo=data:image/svg%2Bxml;base64,&logoColor=white" />
</div>
<h3 align="center">π A powerful open-source alternative to IRCTC, RailYatri, and ixigo Trains β built for AI agents</h3>
<p align="center">
For developers building AI assistants, chatbots, and automation tools, the <b>Indian Railways MCP Server</b> exposes live train schedules, PNR status, seat availability, and fare data through the <a href="https://modelcontextprotocol.io">Model Context Protocol</a> β so any MCP-compatible client (Claude Desktop, Cursor, Continue.dev) can query Indian Railways in natural language, without you having to write a single scraper.
</p>
<div align="center">
<a href="#-quick-start"><img src="https://img.shields.io/badge/Quick%20Start-βΆ%20Get%20Running-1488cc?style=for-the-badge" /></a>
<a href="#-mcp-tool-reference"><img src="https://img.shields.io/badge/Tool%20Reference-π%20Explore-2b32b2?style=for-the-badge" /></a>
<a href="#-features"><img src="https://img.shields.io/badge/Features-β¨%20See%20All-4facfe?style=flat-square&labelColor=1488cc" /></a>
</div>
---
## π Table of Contents
- [Purpose & Philosophy](#-purpose--philosophy)
- [Architecture](#-architecture)
- [Features](#-features)
- [Tech Stack](#-tech-stack)
- [Quick Start](#-quick-start)
- [Environment Configuration](#-environment-configuration)
- [MCP Tool Reference](#-mcp-tool-reference)
- [Data Sources](#-data-sources)
- [Caching Strategy](#-caching-strategy)
- [Use Cases](#-use-cases)
- [Usage Examples](#-usage-examples)
- [Project Structure](#-project-structure)
- [Client Integrations](#-client-integrations)
- [Docker Deployment](#-docker-deployment)
- [Testing](#-testing)
- [Performance](#-performance)
- [Security Notes](#-security-notes)
- [Troubleshooting](#-troubleshooting)
- [Roadmap](#-roadmap)
- [Contributing](#-contributing)
- [Contributors](#-contributors)
- [Star History](#-star-history)
- [AI-Ready Files](#-ai-ready-files)
---
## π― Purpose & Philosophy
> Indian Railways runs over 13,000 trains a day, but its data lives behind inconsistent HTML pages and rate-limited endpoints β making it painful for AI agents to answer a simple question like *"is my train running late?"*
**Indian Railways MCP Server** solves this by normalizing schedules, live status, PNR, fares, and seat data into a single, structured MCP interface that any AI assistant can call directly.
- π **No auth, no secrets** β every data source is public; there's nothing to leak
- π§© **Layered architecture** β server, client, and parser layers are independently testable and swappable
- π **TTL-aware caching** β every tool call respects a data-freshness window instead of hammering upstream sites
- β‘ **Resilient by default** β exponential-backoff retries absorb upstream flakiness so your agent doesn't crash mid-conversation
---
## π Architecture
```mermaid
graph TD
Client["π₯οΈ MCP Client<br/>(Claude Desktop / Cursor / Continue.dev)"] -->|MCP Protocol Β· stdio| Server
subgraph Server["π Indian Railways MCP Server"]
direction TB
SL["π οΈ Server Layer<br/>Tool registration (10 tools)<br/>Pydantic input validation"]
CL["π Client Layer<br/>httpx session mgmt<br/>tenacity retry logic<br/>TTL response cache"]
PL["π Parser Layer<br/>BeautifulSoup HTML parsing<br/>Pydantic JSON parsing<br/>Regex extraction"]
SL --> CL --> PL
end
PL -->|HTTP/HTTPS| ERail[("ποΈ ERail.in<br/>Schedules Β· Live status<br/>PNR Β· Seats Β· Fares")]
PL -->|HTTP/HTTPS| IRInfo[("ποΈ IndianRailways.info<br/>Coach position<br/>Platform locator")]
```
**Data flow:** MCP client sends a tool call over stdio β Server layer validates input with Pydantic β Client layer issues an HTTP request with retry logic β Parser layer extracts structured data from HTML/JSON β Cache layer stores the result with a TTL β response is formatted and returned to the client.
---
## β¨ Features
| Module | Capability | Real-Time | Cache TTL |
|:---|:---|:---:|:---|
| π **Station & Train Search** | Search 8,000+ stations and 10,000+ trains by name or code | β | 24 hours |
| π **Train Schedule** | Complete route with all stations, timings, and distances | β | 1 hour |
| π **Live Running Status** | Real-time location, delays, and platform info | β
| 2 minutes |
| π« **PNR Status** | Passenger details, coach/berth allocation, journey info | β
| 30 seconds |
| πΊ **Seat Availability** | Class-wise availability β AVAILABLE / RAC / WL | β
| 2 minutes |
| π° **Fare Enquiry** | Fare breakdown across all travel classes | β | 1 hour |
| π **Trains Between Stations** | Every train connecting two stations | β | 1 hour |
| π’ **Station Live** | Upcoming departures from any station | β
| 2 minutes |
| π **Coach Position** | Coach layout at any station platform | β | 1 hour |
---
## π§° Tech Stack
| Layer | Technology |
|:---|:---|
| **Runtime** | Python 3.10+ |
| **Protocol** | Model Context Protocol (MCP) SDK 1.0+ |
| **HTTP Client** | httpx |
| **HTML Parsing** | BeautifulSoup4 |
| **Validation** | Pydantic 2.0+ |
| **Retry Logic** | tenacity (exponential backoff) |
| **Testing** | pytest, pytest-cov, pytest-mock, pytest-asyncio |
| **Packaging** | pyproject.toml (pip-installable) |
| **Containerization** | Docker (`python:3.11-slim`) |
| **Process Management** | systemd (Linux server deployments) |
---
## π Quick Start
### Prerequisites
| Tool | Version | Notes |
|:---|:---|:---|
| Python | 3.10+ | Check with `python --version` |
| pip | Latest | Ships with Python |
| An MCP client | Any | Claude Desktop, Cursor, or Continue.dev |
### Step 1 β Clone
```bash
git clone https://github.com/Shadhai/Railway_mcp.git
cd Railway_mcp
```
### Step 2 β Configure
```bash
# Create and activate a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
# Install dependencies
pip install mcp httpx beautifulsoup4 pydantic tenacity
```
> <!-- ADD your vars: this project ships with no required .env file β all data sources are public and unauthenticated. -->
### Step 3 β Run
```bash
# Run directly
python -m src.indian_railways_mcp.server
# Or install as a package and run the entry point
pip install -e .
indian-railways-mcp
```
**β
Success β expect this output:**
```
β
Available tools: 10
- search_stations: Search Indian Railways stations by name or code...
- search_trains: Search Indian Railways trains by number or name...
- get_train_schedule: Get complete train schedule with all stations...
...
```
---
## βοΈ Environment Configuration
No credentials are required β every upstream source is publicly accessible. The only environment variable in use configures the Python import path:
```env
# ββ Runtime βββββββββββββββββββββββββββββββββββββββββββββ
PYTHONPATH=/path/to/Railway_mcp/src
# <!-- VERIFY: add PORT/NODE_ENV-style vars here only if you front this
# server with a custom HTTP/SSE transport wrapper. Stdio transport
# (the default) needs nothing beyond PYTHONPATH. -->
```
---
## π MCP Tool Reference
This server communicates over the **MCP stdio protocol**, not a public REST API β tools are invoked by your AI client, not by HTTP requests you make yourself. Each tool maps to one or more upstream data-source calls.
#### Discovery Tools
| Tool | Description | Auth |
|:---|:---|:---:|
| `search_stations` | Find station code(s) by name, with fuzzy/case-insensitive matching | β |
| `search_trains` | Find train number(s) by name, with fuzzy/case-insensitive matching | β |
| `get_trains_between` | List all trains connecting two stations | β |
#### Schedule & Status Tools
| Tool | Description | Auth |
|:---|:---|:---:|
| `get_train_schedule` | Full route: every station, arrival/departure time, distance | β |
| `get_live_status` | Real-time location, delay minutes, last station | β |
| `get_station_live` | Upcoming departures at a given station | β |
#### Booking & Fare Tools
| Tool | Description | Auth |
|:---|:---|:---:|
| `check_pnr` | PNR status, passenger list, coach/berth, confirmation state | β |
| `check_seat_availability` | Class-wise seat status (AVAILABLE / RAC / WL) | β |
| `get_fare` | Fare breakdown by class | β |
#### Platform Tools
| Tool | Description | Auth |
|:---|:---|:---:|
| `get_coach_position` | Coach layout at a specific platform | β |
| `get_platform_locator` | Locate which platform a train arrives at | β |
> π See `docs/API_REFERENCE.md` in the repo for full parameter schemas.
---
## π Data Sources
#### ERail.in (Primary)
| Endpoint | Method | Format | Cache TTL |
|:---:|:---|:---|:---|
| `/js5/IRStations.js` | `GET` | JS/JSON array | 24 hours |
| `/js5/IRTrains.js` | `GET` | JS/JSON array | 24 hours |
| `/train-enquiry/{train}` | `GET` | HTML table | 1 hour |
| `/train-running-status/{train}` | `GET` | HTML | 2 minutes |
| `/pnr-status/{pnr}?format=json` | `GET` | JSON | 30 seconds |
| `/train-seats/{train}` | `POST` | HTML table | 2 minutes |
| `/train-fare/{train}` | `POST` | HTML table | 1 hour |
| `/trains-between-stations/{from}/{to}` | `POST` | HTML table | 1 hour |
| `/station-live/{station}` | `GET` | HTML table | 2 minutes |
#### IndianRailways.info (Secondary)
| Endpoint | Method | Format | Cache TTL |
|:---:|:---|:---|:---|
| `/coach_position/` | `POST` | HTML table | 1 hour |
| `/platform_locator/` | `POST` | HTML | 1 hour |
---
## β± Caching Strategy
| Data Type | TTL | Reason |
|:---|:---|:---|
| Station List | 24 hours | Rarely changes |
| Train List | 24 hours | Rarely changes |
| Train Schedule | 1 hour | Occasional updates |
| Live Status | 2 minutes | Real-time data |
| PNR Status | 30 seconds | Real-time data |
| Seat Availability | 2 minutes | Frequent updates |
---
## π§ Use Cases
### πΊοΈ AI Travel Planning Assistant
A chatbot built on Claude Desktop uses this server to plan an end-to-end journey β searching trains between two cities, checking live seat availability, pulling the fare, and confirming the schedule, all from one natural-language conversation.
### π Live Train Tracker for Commuters
A commuter-facing IVR or WhatsApp bot polls `get_live_status` every few minutes to tell passengers exactly how delayed their train is and which station it last passed.
### π« PNR Concierge Bot
A support bot integrated with `check_pnr` answers "is my ticket confirmed?" instantly, including per-passenger coach, berth, and waitlist position β without a human agent.
### π Academic / Portfolio Project
A student building an MCP-based AI agent uses this repo as a reference implementation of a layered, cached, retry-safe scraping architecture behind the Model Context Protocol.
---
## π‘ Usage Examples
**Complete journey planning**
```python
from indian_railways_mcp.client import IndianRailwaysClient
client = IndianRailwaysClient()
trains = client.get_trains_between("NDLS", "BCT")
train = trains['trains'][0]
seats = client.check_seat_availability(
train['train_number'], "NDLS", "BCT", "20-Jul-2026"
)
if any(c['status'] == 'AVAILABLE' for c in seats['classes']):
fare = client.get_fare(train['train_number'], "NDLS", "BCT")
print(f"Fare: βΉ{fare['classes'][0]['total_fare']}")
schedule = client.get_train_schedule(train['train_number'])
print(f"Travel time: {schedule['travel_time']} hours")
```
**Live train tracking**
```python
status = client.get_live_status("04815")
if status['status'] == 'RUNNING':
print(f"{status['train_name']} last seen at {status['last_station']}, "
f"delayed {status['delay_minutes']} min")
```
**PNR status check**
```python
pnr = client.check_pnr("4553137968")
for p in pnr['passengers']:
print(f"Passenger {p['serial']}: {p['current_status']} | "
f"Coach {p['coach']} | Berth {p['berth']} ({p['berth_type']})")
```
---
## π Project Structure
```
Railway_mcp/
βββ π README.md # Main documentation
βββ π pyproject.toml # Package configuration
βββ π LICENSE # MIT License
βββ π .gitignore # Git ignore rules
βββ π docs/
β βββ API_REFERENCE.md # Complete tool/API documentation
β βββ ARCHITECTURE.md # System architecture
β βββ EXAMPLES.md # Usage examples
βββ π src/
β βββ π indian_railways_mcp/
β βββ __init__.py # Package init
β βββ server.py # MCP server (10 tools)
β βββ client.py # HTTP client (all endpoints)
β βββ parsers.py # HTML/JSON parsers
β βββ models.py # Pydantic data models
β βββ utils.py # Caching + retry utilities
βββ π tests/
βββ test_client.py # Client tests
βββ test_parsers.py # Parser tests
```
---
## π Client Integrations
<details>
<summary><b>Claude Desktop</b></summary>
Edit your config file:
- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"indian-railways": {
"command": "python",
"args": ["-m", "src.indian_railways_mcp.server"],
"cwd": "/path/to/Railway_mcp",
"env": { "PYTHONPATH": "/path/to/Railway_mcp/src" }
}
}
}
```
Restart Claude Desktop β you'll see a π icon with the Indian Railways tools listed.
</details>
<details>
<summary><b>Cursor AI</b></summary>
Add to `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"indian-railways": {
"command": "python",
"args": ["-m", "src.indian_railways_mcp.server"],
"cwd": "/path/to/Railway_mcp"
}
}
}
```
</details>
<details>
<summary><b>Continue.dev (VS Code)</b></summary>
Add to `~/.continue/config.json`:
```json
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "python",
"args": ["-m", "src.indian_railways_mcp.server"],
"cwd": "/path/to/Railway_mcp"
}
}
]
}
}
```
</details>
<details>
<summary><b>MCP Inspector (debugging)</b></summary>
```bash
npx @modelcontextprotocol/inspector python -m src.indian_railways_mcp.server
```
</details>
---
## π³ Docker Deployment
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
ENV PYTHONPATH=/app
CMD ["python", "-m", "src.indian_railways_mcp.server"]
```
```bash
# Build
docker build -t indian-railways-mcp .
# Run (stdio requires interactive mode)
docker run -i indian-railways-mcp
```
<details>
<summary><b>Systemd service (Linux server)</b></summary>
`/etc/systemd/system/indian-railways-mcp.service`:
```ini
[Unit]
Description=Indian Railways MCP Server
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/indian-railways-mcp
Environment=PYTHONPATH=/opt/indian-railways-mcp/src
ExecStart=/usr/bin/python3 -m src.indian_railways_mcp.server
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
```
```bash
sudo systemctl daemon-reload
sudo systemctl enable indian-railways-mcp
sudo systemctl start indian-railways-mcp
sudo systemctl status indian-railways-mcp
```
</details>
---
## π§ͺ Testing
```bash
# Install test dependencies
pip install pytest pytest-cov pytest-mock pytest-asyncio
# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ -v --cov=src/indian_railways_mcp --cov-report=html
# Run a specific file / class / test
pytest tests/test_client.py -v
pytest tests/test_client.py::TestPNRStatus -v
pytest tests/test_client.py::TestPNRStatus::test_check_pnr_success -v
```
**Coverage summary**
| Module | Tests | Coverage |
|:---|:---:|:---:|
| `client.py` | 40+ | ~95% |
| `parsers.py` | 25+ | ~95% |
| `utils.py` | 10+ | ~90% |
| `models.py` | 5+ | ~85% |
| **Total** | **80+** | **~92%** |
---
## π Performance
**Response times (typical)**
| Operation | Cold (ms) | Cached (ms) |
|:---|:---:|:---:|
| Search Stations | 800 | 5 |
| Search Trains | 1000 | 5 |
| Train Schedule | 1500 | 100 |
| Live Status | 2000 | 200 |
| PNR Status | 1200 | 50 |
| Seat Availability | 2000 | 100 |
**Memory footprint:** ~50MB base (Python + deps) Β· ~65MB with station/train cache warm Β· ~80MB peak during HTML parsing.
---
## π Security Notes
- **No authentication required** β every data source is public
- **Rate-limit safe** β built-in exponential backoff prevents abusive request patterns
- **Validated inputs** β all tool arguments pass through Pydantic models
- **No persistence** β PNR and passenger data are never written to disk
- **HTTPS only** β every outbound request is encrypted
---
## π§ Troubleshooting
| Symptom | Likely Cause | Fix |
|:---|:---|:---|
| `Module not found` | `PYTHONPATH` not set | `export PYTHONPATH="/path/to/Railway_mcp/src:$PYTHONPATH"` or `pip install -e .` |
| `Permission denied` on server script | Missing execute bit | `chmod +x src/indian_railways_mcp/server.py` |
| Server silently exits | Docker missing `-i` flag | Always run with `docker run -i indian-railways-mcp` (stdio needs interactive mode) |
| Dependencies missing | Fresh clone, no install | `pip install -r requirements.txt` |
| `Invalid Train` error | Wrong or malformed train number | Verify it's a 5-digit number via `search_trains` |
| `No Data Found` | Train doesn't run that day | Check the train's days of operation |
| `Station Not Found` | Invalid station code | Run `search_stations` first to resolve the code |
| `Connection Timeout` | Upstream network issue | Handled automatically β 3x retry with exponential backoff |
| `Parse Error` | Upstream site changed its HTML structure | Requires a manual parser update in `parsers.py` |
| `Rate Limited` | Too many requests in a short window | Backs off automatically; avoid tight polling loops |
---
## πΊ Roadmap
<!-- Roadmap inferred from current feature set β update with real project plans -->
- [x] Core tool set β station/train search, schedule, live status
- [x] PNR status, seat availability, and fare enquiry tools
- [x] TTL-based caching layer with retry/backoff
- [x] Docker + systemd deployment paths
- [x] 80+ test suite with ~92% coverage
- [ ] π§ Streamable HTTP/SSE transport for remote (non-stdio) deployments
- [ ] π§ Multi-language station/train name matching (Hindi, regional scripts)
- [ ] π§ Webhook/push alerts for delay and platform changes
- [ ] π§ Official `llms.txt`-based tool discovery for broader agent frameworks
---
## π€ Contributing
```bash
# 1. Fork the repository
# 2. Clone your fork
git clone https://github.com/YOUR_USERNAME/Railway_mcp.git
cd Railway_mcp
# 3. Create a feature branch
git checkout -b feature/your-feature-name
# 4. Make your changes and add tests
pytest tests/ -v
# 5. Commit and push
git commit -m "Add: your feature description"
git push origin feature/your-feature-name
# 6. Open a Pull Request against main
```
Please keep parser changes covered by tests in `tests/test_parsers.py` β upstream HTML structure changes are the most common source of regressions in this project.
---
## π₯ Contributors
<div align="center">
<a href="https://github.com/Shadhai/Railway_mcp/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Shadhai/Railway_mcp" />
</a>
</div>
---
## β Star History
<div align="center">
[](https://star-history.com/#Shadhai/Railway_mcp&Date)
</div>
---
## π€ AI-Ready Files
This repo ships with agent-discovery stubs so AI coding assistants (and MCP-aware crawlers) can understand the project without parsing the full README:
- [`llms.txt`](./llms.txt) β machine-readable project summary for LLM tools
- [`AGENTS.md`](./AGENTS.md) β instructions for coding agents working in this repo
---
<div align="center">
<img src="https://capsule-render.vercel.app/api?type=waving&color=0:4facfe,50:2b32b2,100:1488cc&height=120§ion=footer" width="100%" />
</div>