subway-congestion-mcp
Provides real-time and predicted congestion data, route optimization, and train arrival information for Seoul subway lines 1-8, helping users choose the best travel times.
README
π μ§νμ² νΌμ‘λ μ리미 MCP μλ²
μμΈ μ§νμ² 1~8νΈμ μ νΌμ‘λ μ 보λ₯Ό μ 곡νλ Model Context Protocol (MCP) μλ²
μΆν΄κ·Ό μκ°λμ μ§νμ² μ΄ μΌλ§λ νΌμ‘νμ§ λ―Έλ¦¬ μκ³ , κ°μ₯ μΎμ ν μκ°μ μ΄λν μ μλλ‘ λμμ£Όλ λλν λΉμμ λλ€.
π λͺ©μ°¨
- μ£Όμ κΈ°λ₯
- μ μ΄ νλ‘μ νΈμΈκ°?
- μμνκΈ°
- μ¬μ© λ°©λ²
- ν΄λ ꡬ쑰
- κ°λ° κ°μ΄λ
- λ¬Έμ ν΄κ²°
β¨ μ£Όμ κΈ°λ₯
1. π κ²½λ‘ κ²μ
"κ°λ¨μμμ μμΌμ κ°λ €λλ°"
β μ΅μ κ²½λ‘ + νΌμ‘λ μ 보 + λμ κ²½λ‘ 2κ° μ μ
2. π μ νΌμ‘λ μ‘°ν
"κ°λ¨μ μ§κΈ νΌμ‘ν΄?"
β μ€μκ° νΌμ‘λ + λ€μ μ΄μ°¨ λμ°© μκ°
3. β° λμ°© μκ° κ³μ°
"κ°λ¨μμ μμΌκΉμ§ 9μκΉμ§ λμ°©ν΄μΌ ν΄"
β νμν μΆλ° μκ° + κ·Έ μκ°λ νΌμ‘λ
4. π μ΄μ°¨ λμ°© μ 보
"κ°λ¨μ μ΄μ°¨ μΈμ μ?"
β λ€μ 3κ° μ΄μ°¨ λμ°© μκ° + κ° νΌμ‘λ
5. π μ§νμ² μ΄μ κ²μ
"2νΈμ μ§κΈ μ§μ°λΌ?"
β μ΅μ μ΄ν μ΄μ, κ³ μ₯, μμ μ 보
π― μ μ΄ νλ‘μ νΈμΈκ°?
κΈ°μ‘΄ μ±μ νκ³
- λ€μ΄λ²/μΉ΄μΉ΄μ€λ§΅: νΌμ‘λ μ 보 μμ
- μμΈκ΅ν΅κ³΅μ¬ μ±: μ€μκ° μ λ³΄λ§ μ 곡, μμΈ‘ λΆκ°
μ°λ¦¬μ μ°¨λ³μ
β
ν΅κ³ κΈ°λ° μμΈ‘: κ³Όκ±° λ°μ΄ν°λ‘ μκ°λλ³ νΌμ‘λ μμΈ‘
β
μμ¬κ²°μ μ§μ: "μ§κΈ vs 30λΆ ν" λΉκ΅ μ 곡
β
λνν μΈν°νμ΄μ€: Claudeμ μμ°μ΄λ‘ μν΅
β
λμ μ μ: λ¨μ μ 보 β μ΅μ μ ν μΆμ²
π μμνκΈ°
νμ μꡬμ¬ν
- Python 3.10 μ΄μ
- pip λλ uv (κΆμ₯)
- Claude Desktop (MCP ν΄λΌμ΄μΈνΈ)
- API ν€ 2κ° (무λ£, νμ):
- ODsay API Key
- μμΈμ Open API Key
- (μ ν) Kakao REST API Key
μ€μΉ λ°©λ²
1λ¨κ³: μ μ₯μ 볡μ
git clone https://github.com/yourusername/subway-congestion-mcp.git
cd subway-congestion-mcp
2λ¨κ³: κ°μνκ²½ μμ± (κΆμ₯)
# uv μ¬μ© (κΆμ₯ - λΉ λ¦)
uv venv
source .venv/bin/activate # Mac/Linux
# λλ
.venv\Scripts\activate # Windows
# λλ μΌλ° venv
python -m venv .venv
source .venv/bin/activate
3λ¨κ³: μμ‘΄μ± μ€μΉ
# uv μ¬μ©
uv pip install -e .
# λλ pip μ¬μ©
pip install -e .
4λ¨κ³: νκ²½ μ€μ
cp .env.example .env
# .env νμΌμ μ΄μ΄μ API ν€ μ
λ ₯
5λ¨κ³: λ°μ΄ν° λ€μ΄λ‘λ
python scripts/download_data.py
6λ¨κ³: ν μ€νΈ
pytest
7λ¨κ³: μ€ν
# κ°μνκ²½ νμ±ν μνμμ μ€ν
python -m subway_congestion_mcp
API ν€ λ°κΈ
1. ODsay API (λμ€κ΅ν΅ κ²½λ‘ κ²μ)
λ°κΈ μ¬μ΄νΈ: https://lab.odsay.com
- νμκ°μ (무λ£)
- "API μ¬μ© μ μ²" ν΄λ¦
- μ± μ 보 μ
λ ₯:
- μ± μ΄λ¦:
μ§νμ² νΌμ‘λ μ리미 - μ¬μ© λͺ©μ :
κ°μΈ νλ‘μ νΈ - νλ«νΌ:
Web/Mobile
- μ± μ΄λ¦:
- API ν€ λ³΅μ¬ β
.envνμΌμODSAY_API_KEYμ λΆμ¬λ£κΈ°
μ ν: ν루 1,000건 (무λ£)
2. μμΈμ Open API (μ€μκ° λμ°© μ 보)
λ°κΈ μ¬μ΄νΈ: https://data.seoul.go.kr
- νμκ°μ (무λ£)
- μλ¨ λ©λ΄ "μΈμ¦ν€ μ μ²" ν΄λ¦
- "νμ© μ μ²" λ²νΌ ν΄λ¦
- μΈμ¦ν€ λ³΅μ¬ β
.envνμΌμSEOUL_API_KEYμ λΆμ¬λ£κΈ°
μ ν: ν루 1,000건 (무λ£)
μ€μ
.env νμΌ μμ
# ODsay API (νμ)
ODSAY_API_KEY=your_odsay_api_key_here
# μμΈμ Open API (νμ)
SEOUL_API_KEY=your_seoul_api_key_here
# λ‘κ·Έ λ 벨 (DEBUG, INFO, WARNING, ERROR)
LOG_LEVEL=INFO
# μΊμ TTL (μ΄)
CACHE_TTL=300
Claude Desktop μ€μ
Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"subway-congestion": {
"command": "uv",
"args": [
"--directory",
"/μ λκ²½λ‘/subway-congestion-mcp",
"run",
"subway-congestion-mcp"
]
}
}
}
λλ μΌλ° Python μ¬μ© μ:
{
"mcpServers": {
"subway-congestion": {
"command": "python",
"args": [
"-m",
"subway_congestion_mcp"
],
"env": {
"PYTHONPATH": "/μ λκ²½λ‘/subway-congestion-mcp/src"
}
}
}
}
μ€μ ν Claude Desktopμ μ¬μμνμΈμ.
π¬ μ¬μ© λ°©λ²
μμ 1: κ²½λ‘ κ²μ
μ¬μ©μ: "κ°λ¨μμμ μμΌμ κ°λ €λλ°"
Claude:
π μ΅μ κ²½λ‘: 2νΈμ μμ μ§ν΅ (1μ, 2λΆ)
β’ κ°λ¨μ: νΌμ‘λ 152% (λ§€μ°νΌμ‘) β
β’ μμΌμ: νΌμ‘λ 148% (νΌμ‘) π΄
π λμ κ²½λ‘:
1. 9νΈμ νμΉ (12λΆ) - νΌμ‘λ μ 보 μμ
2. 146λ² λ²μ€ (15λΆ) - νΌμ‘λ μ 보 μμ
π‘ 2νΈμ μ΄ κ°μ₯ λΉ λ₯΄μ§λ§ νμ¬ λ§€μ° νΌμ‘ν©λλ€.
π ν΄λ ꡬ쑰
subway-congestion-mcp/
βββ README.md # π μ§κΈ λ³΄κ³ μλ νμΌ
βββ pyproject.toml # νλ‘μ νΈ λ©νλ°μ΄ν° λ° μμ‘΄μ±
βββ .env.example # νκ²½ λ³μ ν
νλ¦Ώ
βββ .gitignore # Git μ μΈ νμΌ
β
βββ src/
β βββ subway_congestion_mcp/ # λ©μΈ ν¨ν€μ§
β βββ __init__.py
β βββ __main__.py # MCP μλ² μ§μ
μ
β β
β βββ server.py # MCP μλ² μ€μ
β β
β βββ tools/ # MCP λꡬ μ μ
β β βββ __init__.py
β β βββ search_route.py # κ²½λ‘ κ²μ
β β βββ get_station_congestion.py # μ νΌμ‘λ μ‘°ν
β β βββ get_route_congestion.py # κ²½λ‘ νΌμ‘λ + μκ° κ³μ°
β β βββ get_train_arrival.py # μ΄μ°¨ λμ°© μ 보
β β βββ search_issues.py # μ§νμ² μ΄μ κ²μ
β β
β βββ services/ # λΉμ¦λμ€ λ‘μ§
β β βββ __init__.py
β β βββ odsay_service.py # ODsay API νΈμΆ
β β βββ seoul_metro_service.py # μμΈμ API νΈμΆ
β β βββ congestion_service.py # νΌμ‘λ κ³μ° λ‘μ§
β β βββ cache_service.py # μΊμ± λ μ΄μ΄
β β
β βββ data/ # λ°μ΄ν° μ²λ¦¬
β β βββ __init__.py
β β βββ loader.py # CSV λ°μ΄ν° λ‘λ
β β βββ parser.py # λ°μ΄ν° νμ±
β β βββ validator.py # λ°μ΄ν° κ²μ¦
β β
β βββ utils/ # μ νΈλ¦¬ν°
β β βββ __init__.py
β β βββ logger.py # λ‘κΉ
μ€μ
β β βββ time_utils.py # μκ° λ³ν
β β βββ error_handler.py # μλ¬ νΈλ€λ§
β β βββ constants.py # μμ μ μ
β β
β βββ models/ # λ°μ΄ν° λͺ¨λΈ (Pydantic)
β βββ __init__.py
β βββ route.py # κ²½λ‘ κ΄λ ¨ λͺ¨λΈ
β βββ station.py # μ κ΄λ ¨ λͺ¨λΈ
β βββ congestion.py # νΌμ‘λ κ΄λ ¨ λͺ¨λΈ
β
βββ data/ # μ μ λ°μ΄ν°
β βββ congestion/ # νΌμ‘λ CSV νμΌ
β β βββ line1.csv
β β βββ line2.csv
β β βββ ...
β βββ stations.json # μ μ 보 (μ’ν, λ
Έμ λ±)
β
βββ tests/ # ν
μ€νΈ μ½λ
β βββ __init__.py
β βββ test_services/ # μλΉμ€ ν
μ€νΈ
β β βββ test_odsay_service.py
β β βββ test_congestion_service.py
β βββ test_tools/ # λꡬ ν
μ€νΈ
β βββ test_search_route.py
β βββ test_get_station_congestion.py
β
βββ scripts/ # μ νΈλ¦¬ν° μ€ν¬λ¦½νΈ
β βββ download_data.py # CSV λ°μ΄ν° λ€μ΄λ‘λ
β βββ validate_env.py # νκ²½ λ³μ κ²μ¦
β
βββ logs/ # λ‘κ·Έ νμΌ (gitignore)
π κΈ°μ μ€ν
ν΅μ¬ κΈ°μ
- Python 3.10+ - λ°νμ
- MCP SDK - Model Context Protocol
- Pydantic - λ°μ΄ν° κ²μ¦
- pandas - CSV λ°μ΄ν° μ²λ¦¬
μ£Όμ λΌμ΄λΈλ¬λ¦¬
[project]
dependencies = [
"mcp>=0.9.0", # MCP SDK
"pydantic>=2.0.0", # λ°μ΄ν° κ²μ¦
"pandas>=2.0.0", # CSV μ²λ¦¬
"requests>=2.31.0", # HTTP ν΄λΌμ΄μΈνΈ
"python-dateutil>=2.8.2", # λ μ§/μκ° μ²λ¦¬
"python-dotenv>=1.0.0", # νκ²½ λ³μ
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0", # ν
μ€νΈ νλ μμν¬
"pytest-asyncio>=0.21.0", # λΉλκΈ° ν
μ€νΈ
"black>=23.0.0", # μ½λ ν¬λ§·ν
"ruff>=0.1.0", # λ¦°ν
"mypy>=1.5.0", # νμ
체νΉ
]
π¨βπ» κ°λ° κ°μ΄λ
κ°λ° μλ² μ€ν
# MCP Inspectorλ‘ ν
μ€νΈ
npx @modelcontextprotocol/inspector uv --directory . run subway-congestion-mcp
# λλ μ§μ μ€ν
python -m subway_congestion_mcp
ν μ€νΈ
# μ 체 ν
μ€νΈ
pytest
# νΉμ νμΌ ν
μ€νΈ
pytest tests/test_services/test_congestion_service.py
# 컀λ²λ¦¬μ§ νμΈ
pytest --cov=subway_congestion_mcp --cov-report=html
μ½λ νμ§
# ν¬λ§·ν
black src/
# λ¦°ν
ruff check src/
# νμ
체νΉ
mypy src/
λ‘κ·Έ νμΈ
# μ€μκ° λ‘κ·Έ
tail -f logs/app.log
# μλ¬ λ‘κ·Έλ§
tail -f logs/error.log
π λ¬Έμ ν΄κ²°
Q1. MCP μλ²κ° Claude Desktopμ μ°κ²°λμ§ μμμ
νμΈ μ¬ν:
claude_desktop_config.jsonκ²½λ‘κ° μ ννκ°?- μ λ κ²½λ‘λ₯Ό μ¬μ©νλκ°?
- κ°μνκ²½μ΄ νμ±νλμ΄ μλκ°?
- Claude Desktopμ μ¬μμνλκ°?
λλ²κΉ :
# μ§μ μ€νν΄λ³΄κΈ°
cd /μ λκ²½λ‘/subway-congestion-mcp
source .venv/bin/activate
python -m subway_congestion_mcp
# λ‘κ·Έ νμΈ
cat ~/Library/Logs/Claude/mcp*.log
Q2. API νΈμΆμ΄ μ€ν¨ν΄μ
νμΈ μ¬ν:
.envνμΌμ API ν€κ° μ νν μ λ ₯λμλκ°?- API ν€κ° μ ν¨νκ°?
- μΈν°λ· μ°κ²°μ΄ μ μμΈκ°?
λλ²κΉ :
# μ€ν¬λ¦½νΈλ‘ API ν€ ν
μ€νΈ
python scripts/test_api_keys.py
Q3. νΌμ‘λ λ°μ΄ν°κ° μλ€κ³ λμμ
νμΈ μ¬ν:
- CSV λ°μ΄ν°λ₯Ό λ€μ΄λ‘λνλκ°?
python scripts/download_data.py data/congestion/ν΄λμ νμΌμ΄ μλκ°?- 1~8νΈμ μμΈκ°? (9νΈμ λ―Έμ§μ)
π μ±λ₯ μ΅μ ν
μΊμ± μ λ΅
- νΌμ‘λ λ°μ΄ν°: λ©λͺ¨λ¦¬ μΊμ (pandas DataFrame)
- μ€μκ° λμ°© μ 보: 30μ΄ TTL
- κ²½λ‘ κ²μ κ²°κ³Ό: 10λΆ TTL
μλ¬ νΈλ€λ§
# Retry λ°μ½λ μ΄ν°
@retry(max_attempts=3, backoff=exponential)
async def call_api():
...
# Fallback μ λ΅
try:
return await get_realtime_data()
except APIError:
return get_statistical_data() # ν΅κ³ λ°μ΄ν°λ‘ λ체
π 보μ
- β
API ν€λ
.envνμΌμλ§ μ μ₯νκ³.gitignoreλ‘ μ»€λ° μ μΈ - β ν€ μ μΆ μ μ¦μ μ¬λ°κΈ λ° νκΈ°
- β
μν μ€μ μ
.env.exampleλ§ κ³΅μ - β λ―Όκ°ν μ 보λ λ‘κ·Έμ λ¨κΈ°μ§ μμ
- β
μμ‘΄μ±μ
pyproject.tomlμμ κ΄λ¦¬
π λ‘λλ§΅
v1.0 (νμ¬) - MVP
- β κΈ°λ³Έ 5κ°μ§ λꡬ ꡬν
- β 1~8νΈμ μ§μ
- β ν΅κ³ κΈ°λ° νΌμ‘λ
v1.1 (μμ )
- β¬ 9νΈμ , μ λΆλΉμ μ§μ
- β¬ λμ μ μΆμ²
- β¬ μΉ μΈν°νμ΄μ€
v2.0 (κ³ν)
- β¬ κ°μΈν κΈ°λ₯
- β¬ μλ¦Ό μ€μ
- β¬ ν΅κ³ λμ보λ
π€ κΈ°μ¬νκΈ°
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
π λΌμ΄μΌμ€
MIT License - μμ λ‘κ² μ¬μ©νμΈμ!
π¬ μ°λ½μ²
λ¬Έμμ¬νμ΄λ μ μμ¬νμ΄ μμΌμλ©΄:
- GitHub Issues
- Email: kimjinjuind@gmail.com
Made with β€οΈ for Seoul Subway Commuters
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.