El MCP de DatosVivos
El mismo motor que responde en el buscador está expuesto como servidor MCP (Model Context Protocol): cualquier agente de IA — Claude, o cualquier cliente compatible — puede buscar, consultar y cruzar los datos abiertos de Colombia como herramientas nativas.
Cómo conectarse
El servidor es de código abierto y corre junto al resto del stack. Clona el repositorio y levanta el servicio:
git clone https://github.com/jsricop/DatosVivos.git cd DatosVivos docker compose up -d mcp-server # SSE endpoint: http://localhost:3000/sse
MCP es un protocolo abierto: el servidor funciona con cualquier cliente que lo soporte. Configuración por cliente:
Claude (Code / Desktop)
# Claude Code — un comando:
claude mcp add --transport sse datosvivos http://localhost:3000/sse
# Claude Desktop — claude_desktop_config.json:
{ "mcpServers": { "datosvivos": { "url": "http://localhost:3000/sse" } } }OpenAI (Agents SDK / Responses API)
# Agents SDK (pip install openai-agents):
from agents import Agent, Runner
from agents.mcp import MCPServerSse
async with MCPServerSse(params={"url": "http://localhost:3000/sse"}) as mcp:
agent = Agent(name="datos-colombia", mcp_servers=[mcp])
out = await Runner.run(agent, "¿Cuántos colegios oficiales hay en Boyacá?")
# Responses API (exige URL pública — expón el servidor o usa un túnel):
client.responses.create(
model="gpt-4.1",
tools=[{"type": "mcp", "server_label": "datosvivos",
"server_url": "https://<tu-host>/sse"}],
input="¿Cuántos colegios oficiales hay en Boyacá?")Cursor · VS Code (GitHub Copilot) · Gemini CLI
# Cursor — ~/.cursor/mcp.json:
{ "mcpServers": { "datosvivos": { "url": "http://localhost:3000/sse" } } }
# VS Code (Copilot agent mode) — .vscode/mcp.json:
{ "servers": { "datosvivos": { "type": "sse", "url": "http://localhost:3000/sse" } } }
# Gemini CLI — ~/.gemini/settings.json:
{ "mcpServers": { "datosvivos": { "url": "http://localhost:3000/sse" } } }Grok, DeepSeek, Llama u otro modelo
Esos modelos no traen cliente MCP propio: se conectan a través de un cliente que sí lo soporte eligiendo el modelo ahí (Cursor, Cline, Continue aceptan Grok/DeepSeek como backend), o programáticamente con el SDK oficial de MCP — útil para cualquier stack:
# pip install mcp — cliente universal en Python:
from mcp import ClientSession
from mcp.client.sse import sse_client
async with sse_client("http://localhost:3000/sse") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
r = await session.call_tool("query_data", {
"dataset_id": "emd6-ef7x",
"soql_query": "SELECT count(*) AS n WHERE sector='OFICIAL'"})
# → [{ "n": "1721" }] — desde aquí, cualquier LLM consume el resultadoLas herramientas consultan la API pública de datos.gov.co — no necesitan credenciales; un App Token de Socrata (opcional, variable SOCRATA_APP_TOKEN) sube los límites de tasa.
Qué puede hacer un agente conectado
Importante: estas herramientas no se llaman a mano. Al conectarse, el cliente las descubre automáticamente y desde ahí el propio modelo decide cuál usar, con qué argumentos y en qué orden, según lo que le pidas en lenguaje natural. Una sola pregunta puede disparar la cadena completa:
Tú: "¿Cuántos colegios oficiales hay en Boyacá?"
El agente decide y encadena, solo:
1. search_datasets("establecimientos educativos Boyacá") → encuentra emd6-ef7x
2. get_metadata("emd6-ef7x") → descubre la columna sector
3. query_data("emd6-ef7x", "SELECT count(*) WHERE sector='OFICIAL'") → 1721
Agente: "Hay 1.721 establecimientos oficiales en Boyacá,
según la Gobernación de Boyacá (dataset emd6-ef7x)."Las 4 herramientas que el agente tiene disponibles — cada tarjeta muestra un ejemplo real de petición, llamada y respuesta:
search_datasetsBusca datasets en el catálogo por palabras clave. Devuelve id, nombre, entidad, filas y enlace de los mejores matches.
Pides «Busca datasets de establecimientos educativos en Boyacá»
El agente llamasearch_datasets(query="establecimientos educativos Boyacá", limit=5)
La herramienta devuelve[{ "id": "emd6-ef7x", "name": "Establecimientos Educativos del sector oficial y no oficial…", "entity": "Gobernación de Boyacá", "rows_count": 2184, … }]get_metadataEl esquema completo de un dataset: columnas tipadas con descripción, filas, entidad y fechas de actualización.
Pides «¿Qué columnas tiene ese dataset?»
El agente llamaget_metadata(dataset_id="emd6-ef7x")
La herramienta devuelve{ "columns": [{ "field_name": "sector", "type": "text", … }, { "field_name": "municipio", "type": "text", … }, … ], "rows_count": 2184, … }query_dataEjecuta una consulta SoQL sobre el dataset y devuelve las filas. El agente arma la consulta; los datos salen del portal oficial.
Pides «¿Cuántos son del sector oficial?»
El agente llamaquery_data(dataset_id="emd6-ef7x", soql_query="SELECT count(*) AS n WHERE sector='OFICIAL'")
La herramienta devuelve[{ "n": "1721" }]cross_datasetsCruza de 2 a 5 datasets por una clave compartida (DIVIPOLA, código DANE, NIT) — verifica que la clave exista en cada uno antes del join.
Pides «Cruza los establecimientos con la matrícula por municipio»
El agente llamacross_datasets(dataset_ids=["emd6-ef7x", "qpq9-e4ne"], join_keys="municipio", select_columns=["municipio", "sector", "total_ie"])La herramienta devuelve[{ "municipio": "TUNJA", "sector": "OFICIAL", "total_ie": … }, …]
Las herramientas devuelven filas y metadatos reales del portal oficial: el agente razona, los datos salen de la fuente. Código en mcp_server/, licencia abierta.