sitp-bogota-mcp
# 🚌 sitp-bogota-mcp
[](https://github.com/tamagonocammy/sitp-bogota-mcp/actions/workflows/tests.yml)
[](LICENSE)
Servidor [MCP](https://modelcontextprotocol.io) para consultar el **SITP y TransMilenio de Bogotá** desde Claude (u otro asistente compatible con MCP), usando los **datos abiertos oficiales** de TransMilenio S.A.
Pregúntale cosas como:
- *"¿Qué rutas paran en la estación Banderas?"*
- *"¿Cuándo pasa el próximo bus por el paradero 064A08_TM?"*
- *"¿Cómo llego de Portal Américas a la Universidad Nacional mañana a las 7?"*
- *"¿A qué hora sale el primer B72 los domingos?"*
Cubre **todo el SITP**: troncales, alimentadores, rutas duales, zonales urbanas, complementarias, especiales y TransMiCable.
## Herramientas
| Herramienta | Qué hace |
|---|---|
| `buscar_paraderos` | Busca paraderos y estaciones por nombre, código (`064A08_TM`) o id. Entiende abreviaturas (*Cll*, *Kr*, *Av*…) y no le importan las tildes. |
| `paraderos_cercanos` | Paraderos y estaciones cerca de una coordenada. |
| `rutas_en_paradero` | Rutas que paran en un paradero o estación (todas sus plataformas o vagones). |
| `info_ruta` | Recorrido, tipo, primer y último bus y frecuencia promedio de una ruta. Acepta el código que dice el bus, también en las rutas zonales en pareja (`K635` o `H635`, que el GTFS publica como `HK635`). |
| `proximos_buses` | Próximas salidas de un paradero. Usa el **GTFS Realtime** oficial cuando está disponible y, si no, el horario programado. |
| `planear_viaje` | Rutas directas o con un transbordo entre dos lugares (nombres, códigos o `lat,lon`), con caminatas y tiempo estimado. |
| `info_datos` | Versión del GTFS cargada y estado del tiempo real. |
## Ejemplos reales
Respuestas del servidor con el GTFS oficial del 13 de octubre de 2026 (recortadas).
**"¿Cómo llego de Banderas a la Universidad Nacional mañana a las 7?"** → `planear_viaje`
```json
{
"origen": "Banderas",
"destino": "Universidad Nacional",
"consulta": "2026-11-10 07:00",
"opciones": [{
"transbordos": 0,
"tiempo_total_estimado_min": 24,
"tramos": [{
"ruta": "E32", "hacia": "NQS Calle 75", "tipo": "TransMilenio troncal",
"subir_en": "Banderas T2 (F016)", "bajar_en": "U. Nacional C - 4 ó 6",
"paradas": 6, "min_en_bus": 24, "proxima_salida_programada": "07:03"
}]
}],
"nota": "Tiempos estimados con el horario programado; no incluyen trancones ni la espera exacta en el paradero."
}
```
**"¿Qué buses salen de Banderas a las 7:30?"** → `proximos_buses`
```json
{
"paradero": "Banderas",
"tipo": "estación",
"consulta": "2026-11-10 07:30",
"proximos": [
{"ruta": "F19", "hacia": "P. Américas", "tipo": "TransMilenio troncal", "hora": "07:30", "desde": "Banderas T1", "fuente": "horario programado"},
{"ruta": "B26", "hacia": "Alcalá", "tipo": "TransMilenio troncal", "hora": "07:30", "desde": "Banderas T8", "fuente": "horario programado"},
{"ruta": "F63 · Z63", "hacia": "Pradera · Tibanica", "tipo": "Ruta dual", "hora": "07:30", "desde": "Banderas T7", "fuente": "horario programado"}
]
}
```
**"¿Cuál es el horario del B72?"** → `info_ruta`
```json
{
"ruta": "B72", "hacia": "ToberÃn", "tipo": "TransMilenio troncal",
"duracion_aprox_min": 68,
"horario": [
{"dias": "lunes a viernes", "primer_bus": "04:30", "ultimo_bus": "23:00", "frecuencia_promedio_min": 4},
{"dias": "sábados", "primer_bus": "04:30", "ultimo_bus": "00:00 (dÃa siguiente)", "frecuencia_promedio_min": 6},
{"dias": "domingos y festivos", "primer_bus": "04:00", "ultimo_bus": "00:00 (dÃa siguiente)", "frecuencia_promedio_min": 7}
]
}
```
Si un nombre no coincide exactamente (por ejemplo *"Kennedy"*, que es una localidad y no una estación), la respuesta trae un `aviso` con el paradero que se usó y `otras_coincidencias` para elegir otro.
## Instalación
Necesitas Python 3.10 o superior y [uv](https://docs.astral.sh/uv/).
**1. Instala uv** (solo una vez):
| Sistema | Comando |
|---|---|
| macOS | `brew install uv` o `curl -LsSf https://astral.sh/uv/install.sh \| sh` |
| Linux | `curl -LsSf https://astral.sh/uv/install.sh \| sh` |
| Windows (PowerShell) | `winget install --id=astral-sh.uv -e` o `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 \| iex"` |
**2. Descarga el proyecto y los datos** (igual en todos los sistemas):
```bash
git clone https://github.com/tamagonocammy/sitp-bogota-mcp.git
cd sitp-bogota-mcp
uv sync
uv run sitp-mcp-update # descarga el GTFS oficial (~120 MB) y arma la base (~1 min)
```
También funciona con `pip install -e .` y luego `sitp-mcp-update`. Si te saltas `sitp-mcp-update`, el servidor descarga los datos la primera vez que lo usas (tarda unos minutos).
### Claude Code
```bash
claude mcp add sitp-bogota -- uv --directory /ruta/a/sitp-bogota-mcp run sitp-mcp
```
En Windows usa la ruta completa, por ejemplo `C:\Users\tu-usuario\sitp-bogota-mcp`.
### Claude Desktop
Abre *Configuración → Desarrollador → Editar configuración*, o edita el archivo directamente:
| Sistema | Archivo |
|---|---|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
**macOS:**
```json
{
"mcpServers": {
"sitp-bogota": {
"command": "/opt/homebrew/bin/uv",
"args": ["--directory", "/Users/tu-usuario/sitp-bogota-mcp", "run", "sitp-mcp"]
}
}
}
```
Claude Desktop no hereda el `PATH` de la terminal, asà que pon la ruta completa de `uv` (la ves con `which uv`; con el instalador `curl` suele ser `~/.local/bin/uv`).
**Windows:**
```json
{
"mcpServers": {
"sitp-bogota": {
"command": "uv",
"args": ["--directory", "C:\\Users\\tu-usuario\\sitp-bogota-mcp", "run", "sitp-mcp"]
}
}
}
```
En JSON las barras invertidas van dobles (`\\`); también puedes usar `/` (`C:/Users/tu-usuario/sitp-bogota-mcp`). Si Claude no encuentra `uv`, usa la ruta que muestra `where uv`. Reinicia Claude Desktop después de guardar.
## Datos
- **GTFS estático:** el servidor busca automáticamente la versión más reciente en el [Portal de Datos Abiertos de TransMilenio](https://datosabiertos-transmilenio.hub.arcgis.com/) (se publica cada pocas semanas). Para actualizar: `sitp-mcp-update --force`.
- **GTFS Realtime:** `https://gis.transmilenio.gov.co/gtfs/tripupdate.pb` ([anunciado en noviembre de 2026](https://bogota.gov.co/mi-ciudad/movilidad/2026-11/transmilenio-conecta-la-operacion-del-sistema-con-tecnologia-bogota)). Al 9 de noviembre de 2026 los feeds (`tripupdate.pb`, `vehiclepos.pb`, `serviceAlerts.pb`) responden `HTTP 500` incluso desde Bogotá. Mientras no funcionen, el servidor usa los horarios programados y lo indica en cada respuesta (`"fuente": "horario programado"`). Cuando el feed vuelva, se usa solo, sin cambiar nada.
- La base local se guarda en `~/.sitp-mcp/` (≈550 MB; en Windows, `C:\Users\tu-usuario\.sitp-mcp`). Cambia la carpeta con `SITP_MCP_DATA`.
| Variable | Para qué |
|---|---|
| `SITP_MCP_DATA` | Carpeta de la base local (por defecto `~/.sitp-mcp`). |
| `SITP_RT_TRIP_UPDATES_URL` | URL alternativa del feed de tiempo real. |
| `SITP_RT_DISABLE=1` | Desactiva el tiempo real. |
En Claude Desktop, las variables se agregan con `"env": {"SITP_MCP_DATA": "..."}` junto a `"args"`.
## Limitaciones
- Los tiempos de viaje salen del **horario programado**: no incluyen trancones ni la espera exacta en el paradero.
- La planeación busca viajes **directos o con un transbordo**. De noche, cuando hay pocas rutas, puede no encontrar nada aunque exista un viaje con dos transbordos. No reemplaza a TransMiApp para trayectos muy complejos.
- Las opciones mucho más lentas que la mejor (más de 1.5× y más de 15 min extra) no se muestran, igual que los transbordos que usan una ruta que ya va directo.
- Algunos nombres de paraderos vienen tal cual en el GTFS oficial (por ejemplo `FF425_8-6`).
## Desarrollo
```bash
uv sync --extra dev
uv run pytest
```
Las pruebas usan un GTFS miniatura inventado (`tests/conftest.py`), asà que no necesitan internet. GitHub Actions las corre en Python 3.10 y 3.13 (Linux), y en 3.13 en Windows y macOS.
## Agradecimientos
- A [Paradero](https://github.com/croma-labs/paradero) de Croma (MIT), por la idea de sacar los códigos de las rutas zonales en pareja del `route_long_name` para que se puedan buscar por lo que dice el bus.
## Licencia
[MIT](LICENSE). Los datos son de TransMilenio S.A., publicados como datos abiertos. Este proyecto no es oficial ni está afiliado a TransMilenio.
---
### English
MCP server for Bogotá's public transport (SITP / TransMilenio) built on TransMilenio's official open GTFS and GTFS-Realtime feeds. Tools: stop search, nearby stops, routes at a stop, route info, next departures (realtime with schedule fallback) and trip planning with up to one transfer. Install with `uv sync && uv run sitp-mcp-update`, then add `uv run sitp-mcp` to your MCP client. MIT licensed.
TDQS
Scored across 7 tools
Each tool targets a distinct query type: stop search by name/code, stops by coordinates, routes at a stop, route details, upcoming buses, GTFS metadata, and trip planning. The only mild overlap is between buscar_paraderos and paraderos_cercanos (both return stop lists), but the input difference (text vs coordinates) is clearly documented. rutas_en_paradero vs info_ruta is the inverse relationship (stop→routes vs route→details) and is legible from the names.
All names are Spanish snake_case, which is consistent, but the grammatical patterns are mixed: verb-first (buscar_paraderos, planear_viaje), noun-adjective (paraderos_cercanos, proximos_buses), and noun_noun (info_ruta, info_datos). The result is readable and domain-idiomatic but lacks a predictable verb_noun template across the set.
Seven tools is well-scoped for a transit data server, with each tool mapping to a distinct user intent (search, proximity, route lookup, departures, planning, metadata). No tool feels redundant or out of place, and none of the core capabilities are missing.
The surface covers the full read-only transit lifecycle: discovery (search/nearby), route detail, departures/realtime, and end-to-end trip planning, plus metadata about data freshness. Minor gaps exist (e.g. no route geometry/shape or a way to list/browse all routes without knowing a code), but agents can work around these.