Skip to main content
Glama
README.md
# 🚌 sitp-bogota-mcp

[![tests](https://github.com/tamagonocammy/sitp-bogota-mcp/actions/workflows/tests.yml/badge.svg)](https://github.com/tamagonocammy/sitp-bogota-mcp/actions/workflows/tests.yml)
[![Licencia MIT](https://img.shields.io/badge/licencia-MIT-blue.svg)](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

A3.6/5.0

Scored across 7 tools

Disambiguation4/5

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.

Naming Consistency3/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues