Build Your Own 12306 Train-Ticket Bot in 10 Minutes

A step-by-step English guide to the open-source 12306 MCP Server—no prior railway API experience required.


Why You Should Keep Reading

Have you ever:

  • wished you could check Chinese train tickets without opening the 12306 app?
  • needed real-time seat availability for a travel-assistant bot?
  • been told by your product manager, “Just plug railway data into our AI agent—by next Friday”?

This post walks you through one single repository that solves all three problems.
Everything here is taken straight from the official project page; nothing is added from outside sources.


1. What Exactly Is the 12306 MCP Server?

Think of it as a concierge between you and the official 12306 system.

  • It speaks MCP (Model Context Protocol), a lightweight language that AI agents, scripts, and even smart speakers understand.
  • Inside, it uses FastAPI and async Python to return answers in milliseconds.
  • Outside, it looks like a normal REST service running on port 8000.
You ask for Server gives back
“Tomorrow Beijing → Shanghai” Train numbers, times, seat counts
“Any transfer via Wuhan?” First-class one-stop itineraries
“Station code for Shenzhen North” IOQ, plus coordinates

2. Quick Start—Two Roads, Same Destination

2.1 Local Source (for developers)

# Action Copy-paste command
1 Clone git clone https://github.com/drfccv/12306-mcp-server.git
2 Enter folder cd 12306-mcp-server
3 Install deps uv sync
4 Update stations uv run python scripts/update_stations.py
5 Start server uv run python scripts/start_server.py

You will see:

INFO:     Uvicorn running on http://0.0.0.0:8000

Open http://localhost:8000/docs for an interactive Swagger UI.

2.2 Docker One-liner (for everyone else)

docker pull drfccv/12306-mcp-server:latest
docker run -d -p 8000:8000 --name 12306-mcp-server drfccv/12306-mcp-server:latest

That is literally it. The container ships with stations pre-loaded.


3. The Five Core Tools Explained in Plain English

Tool What it does Everyday example
query_tickets Lists trains, times, seat availability “Show me the 8 a.m. bullet train from Beijing South to Shanghai Hongqiao tomorrow.”
search_stations Fuzzy search station names or codes “Is Beijing South called VNP or BXP?”
get_station_info Full details (name, pinyin, geo point) Drop a pin on a map for every station
query_transfer One-stop transfer plans “No direct train—how do I go via Nanjing?”
get_train_route_stations Complete timetables for a given train “Does G103 stop at Jinan West?”
get_current_time Server time + relative dates “Calculate the date three days from now in yyyy-mm-dd”

Each tool has its own Markdown manual under /docs. They contain:

  • exact request/response JSON
  • field-by-field explanations
  • common error messages and fixes

4. Mini-FAQ: Ten Questions Beginners Always Ask

Q1. Do I need a 12306 account?
No. The server only consumes public endpoints.

Q2. How often should I update station data?
Once a week is plenty. Run update_stations.py or rebuild the Docker image.

Q3. Will my IP get banned?
The server paces itself with exponential back-off. Stay under 3 requests per second and you are safe.

Q4. Can I run this on a cloud VM?
Yes. Use Docker or systemd. Example service files are in /examples.

Q5. How do I plug this into my AI assistant?
Add one JSON block to your MCP client:

{
  "mcpServers": {
    "12306": {
      "url": "http://<your-server>:8000/mcp"
    }
  }
}

Q6. Which station codes are supported?
Every passenger station in mainland China, including high-speed rail stations in Hong Kong. Use search_stations to verify.

Q7. Does it show student or child fares?
Adult fares only. Student and child pricing rules are not publicly documented.

Q8. How fast are transfer calculations?
Usually under 200 ms for a single transfer.

Q9. How can I contribute code?
Fork, write tests, open a PR. CI runs on Python 3.10 and 3.11.

Q10. Can I use this commercially?
The license is MIT, so yes. Evaluate 12306’s own terms separately.


5. Directory Map for Future Hacking

12306-mcp-server/
├─ src/mcp_12306/
│  ├─ server.py        # FastAPI entry point
│  ├─ services/        # Business logic
│  │  ├─ ticket.py
│  │  ├─ station.py
│  │  └─ transfer.py
│  ├─ models/          # Pydantic schemas
│  └─ utils/           # Logging & helpers
├─ scripts/
│  ├─ update_stations.py
│  └─ start_server.py
├─ docs/               # One file per tool
└─ tests/              # pytest suite
  • Want new endpoints? Edit server.py and add tests.
  • Need to cache results? Drop a decorator in utils/.
  • Prefer async Redis? Swap the in-memory cache in five lines.

6. Hands-On Lab: Query a Ticket with curl

  1. Find the station code for Beijing South:
curl -s "http://localhost:8000/search_stations?keyword=Beijing%20South" | jq

Response:

[{"name":"Beijing South","code":"VNP"}]
  1. Check tomorrow’s trains to Shanghai Hongqiao:
curl -s "http://localhost:8000/query_tickets?from=VNP&to=AOH&date=2025-07-17" | jq '.[].train_no'

Sample output:

"G1"
"G3"
"G101"
  1. Need a transfer plan?
    Replace query_tickets with query_transfer, keep the same parameters.

7. Testing & Continuous Integration

uv run pytest

The test suite finishes in under ten seconds and covers:

  • HTTP 200 responses for all tools
  • Station-code edge cases (pinyin, fuzzy search)
  • Rate-limit back-off logic

Every pull request triggers:

  • Python 3.10 & 3.11 matrix tests
  • ruff linting
  • mypy type checking

Green CI means master is always deploy-ready.


8. Real-World Integration Recipes

Use case Tech stack 30-second recipe
WeChat Work bot Python + Flask Listen for group messages → hit MCP → return train cards
Voice assistant Node.js + MCP SDK Convert speech → parameters → speak back departures
Mini-program WeChat Cloud Functions Cloud function calls MCP → returns JSON to mini-program
Cron-based watcher cron + curl Every 5 min check seats → email on availability

All cases use the same MCP endpoint; language and platform do not matter.


9. Legal & Ethical Usage Reminders

  • Frequency: Keep requests ≤ 3 per second.
  • Privacy: Never log passenger names or ID numbers.
  • Attribution: Display “Data from 12306 public endpoints” to users.

The project’s disclaimer is explicit:

“Any consequences arising from the use of this project are the sole responsibility of the user.”


10. Cheat Sheet: One-Minute Reference

Task One-liner
Start locally uv run python scripts/start_server.py
Update stations uv run python scripts/update_stations.py
Docker run docker run -d -p 8000:8000 drfccv/12306-mcp-server:latest
Run tests uv run pytest
Read docs Open /docs/*.md or Swagger at /docs

Happy coding, happy travels, and may your bots never miss the last train home.