Proyecto · Open source · Go
MCP para tramites.gub.uy
Servidor Model Context Protocol open source en Go que usa los datos abiertos de AGESIC para que agentes de IA — Claude, Claude Code, otros clientes compatibles — consulten trámites del Estado uruguayo con fuentes verificables.
En 2015 implementé la norma UNIT 1215 de Accesibilidad Web en el portal tramites.gub.uy desde AGESIC. Diez años después, este MCP permite a agentes de IA operar ese mismo portal usando los datos abiertos publicados por AGESIC. Mismo trámite, distinta capa.
Por qué importa
Hay una pregunta recurrente cuando uno trabaja con modelos de lenguaje: ¿cómo lograr que respondan con información útil, verificable y actualizada, sin depender de lo que "recuerdan"?
Para trámites del Estado uruguayo, esa pregunta es especialmente importante. Un trámite puede cambiar de requisitos, costos, oficinas, canales de atención o enlaces oficiales. Si un asistente responde desde memoria, puede sonar convincente y estar mal. Para este tipo de casos, el camino razonable es conectar el modelo a una fuente de datos concreta.
Este MCP es esa conexión. Los datos vienen del dataset abierto Guía de Trámites de AGESIC (catalogodatos.gub.uy), publicado bajo licencia CC BY 4.0. El código del servidor está bajo MIT.
Qué expone el servidor
Transporte: HTTP Streamable en /mcp. 4 tools y 1 resource:
search_uruguay_government_procedures(query, organismo?, limit?)— búsqueda de trámites con FTS5 o híbrida si hay embeddings.get_uruguay_government_procedure(id)— detalle completo de un trámite por ID, con URL oficial, última actualización, atribución a AGESIC y licencia de los datos.list_uruguay_government_organismos()— listado de organismos del Estado que publican trámites.find_uruguay_procedure_offices(procedure_id, departamento?)— oficinas físicas donde se gestiona un trámite, con filtro opcional por departamento.- Resource:
tramite://{id}— para que el LLM traiga el trámite completo como recurso MCP.
Cada respuesta incluye url_oficial, last_updated_at, atribución a AGESIC y licencia de los datos. Esto permite que el asistente cite el enlace oficial y advierta sobre la frescura de la información.
Arquitectura
El proyecto tiene una arquitectura deliberadamente simple:
CKAN API → XML mensual → ingest streaming → SQLite → FTS5 / embeddings → MCP HTTPStack
- Go + Gin (HTTP routing).
- SQLite con
modernc.org/sqlite(driver Go puro, sin CGO). - FTS5 para búsqueda léxica (tokenizer
unicode61 remove_diacritics 2). - OpenAI embeddings para búsqueda semántica.
- mcp-go para el servidor MCP.
- Docker Compose para deploy con volumen persistente.
Búsqueda en 3 modos
- FTS5: búsqueda léxica rápida con SQLite.
- Vector: embeddings en memoria con similitud coseno.
- Híbrida: combinación de FTS + vector con Reciprocal Rank Fusion.
Por defecto el servidor usa FTS5. Si hay embeddings cargados y OPENAI_API_KEY configurada, intenta búsqueda híbrida. Si no puede, cae a FTS5 y lo declara en la respuesta.
Ingest reproducible
El ingest descarga el XML real de AGESIC, lo parsea en streaming con encoding/xml, calcula un content_hash por trámite y hace upsert solo cuando detecta cambios. Si un trámite cambia, se resetea su embedding para regenerarlo. Si un trámite desaparece del XML actual, se marca con soft delete.
Cómo se instala y se prueba
Claude Desktop o Claude.ai (custom connector remoto)
El endpoint debe ser público y accesible por HTTPS. Ejemplo: https://tramites.example.com/mcp. En Claude Desktop o Claude.ai:
Settings → Customize → Connectors → Add custom connectorClaude Code (desarrollo local)
claude mcp add --transport http tramites-gub-uy http://localhost:8080/mcpEjemplo: buscar trámites de pasaporte vía cURL
curl -sS -X POST https://tramites.example.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_uruguay_government_procedures","arguments":{"query":"pasaporte","limit":3}}}'Deploy con Docker / Dokploy
Pensado para correr en Docker simple. El primer arranque puede cargar la base automáticamente con BOOTSTRAP_INGEST=true: si la tabla de trámites está vacía, el entrypoint corre /app/ingest --if-empty y después levanta el server. La base vive en un volumen persistente (/data/tramites.db), así que reinicios posteriores arrancan rápido.
Hardening y operación
- Rate limit en memoria: 60 requests/min por IP.
- Logs JSON estructurados, con eventos específicos de búsquedas MCP (
event=mcp_query). - Healthcheck HTTP para orquestadores.
- Dockerfile multi-stage.
- GitHub Actions con
go build,go test,go vetystaticcheck. - Cron de ejemplo para refrescar datos el día 5 de cada mes (cuando AGESIC publica el dump).
Decisiones de diseño
SQLite alcanza perfectamente para este volumen de datos. FTS5 resuelve muy bien la búsqueda textual. Para búsqueda semántica, cargar los embeddings en memoria es más simple que meter una base vectorial adicional, y para unos miles de trámites funciona sin drama.
El contenedor arranca con una DB funcional en el primer deploy. En un proyecto como este, la experiencia de despliegue importa: si alguien lo corre en Dokploy, debería poder levantar el servicio y empezar a consultar datos sin ejecutar cinco comandos manuales.
El proyecto es deliberadamente sobrio. No es una plataforma enorme. Es una pieza chica, mantenible y desplegable.
Próximos pasos posibles
- Endpoint administrativo para recargar el índice vectorial después de un ingest.
- Métricas Prometheus.
- Autenticación opcional para deployments públicos.
- Panel web simple para explorar trámites.
- Caché de respuestas MCP frecuentes.
- Job mensual integrado en el propio contenedor (hoy es cron externo).
La base ya está: datos abiertos, ingest reproducible, búsqueda en 3 modos, MCP y deploy reproducible.
Preguntas frecuentes
Sobre MCP y este proyecto
OPENAI_API_KEY, intenta híbrida. https://tu-dominio.com/mcp. Para desarrollo local con Claude Code: claude mcp add --transport http tramites-gub-uy http://localhost:8080/mcp. ¿Tu organismo necesita un MCP a medida?
Si tu organización quiere conectar agentes de IA con sus datos o sistemas internos — trámites, bases de datos, APIs, workflows — construyo MCPs a medida con foco en producción, no demo. Misma arquitectura: chico, mantenible, desplegable.
