Skip to main content
Glama
julio7879

mcp-colombia-demo

by julio7879
README.md
# 🇨🇴 mcp-colombia-demo: Servidor MCP de Departamentos de Colombia

> Servidor de **Model Context Protocol (MCP)** minimalista desarrollado en **Node.js** que conecta un Modelo de Lenguaje de Inteligencia Artificial (LLM) con la **API REST oficial y pública de la República de Colombia** para consultar información geográfica en tiempo real sobre los departamentos del país.

---

## 2. Descripción General

### ¿Qué es MCP (Model Context Protocol)?
**Model Context Protocol (MCP)** es un protocolo abierto y estandarizado desarrollado por Anthropic que actúa como un "conector universal" o "puerto USB" para aplicaciones de Inteligencia Artificial. Permite que los modelos de lenguaje (LLM) descubran, comprendan e invoquen de manera autónoma y segura fuentes de datos externas, bases de datos y herramientas locales.

### ¿Qué hace este proyecto?
Este proyecto expone un servidor MCP local que proporciona a cualquier cliente de IA (Claude Desktop, Cursor, VS Code, MCP Inspector) la capacidad de consultar datos geográficos reales sobre Colombia.

- **API que utiliza**: API pública de Colombia (`https://api-colombia.com/api/v1`).
- **Herramienta que expone**: `obtener_departamentos`.
- **Beneficio para la IA**: Gracias a este servidor MCP, el modelo de IA puede responder a preguntas del usuario utilizando **datos oficiales y en tiempo real** (capital, población, superficie en $\text{km}^2$, municipios y prefijo telefónico) evitando alucinaciones o datos desactualizados.

> 💡 **Diferencia Fundamental: API vs MCP**  
> - **API REST**: Es la fuente de información o servicio externo que almacena y entrega los datos mediante HTTP.  
> - **MCP**: Es el protocolo de comunicación estandarizado que describe la herramienta a la IA en formato **JSON Schema**, permitiendo que el modelo decida por sí solo cuándo y cómo invocar la API.

---

## 3. ¿Qué problema resuelve?

### Sin MCP (Desarrollo Tradicional)
En una aplicación convencional o chatbot estático sin conectores:
```text
Usuario / Aplicación ──► Petición Rígida ──► API Colombia ──► Datos Estáticos
```
- **Problema**: El código es rígido y programado a mano para consultas fijas. Si el usuario hace una pregunta abierta o compleja, la IA depende de su memoria estática preentrenada, lo que produce información desactualizada o inventada (alucinaciones).

### Con MCP (Model Context Protocol)
```text
[Usuario] ──► [IA] ──► [MCP Client] ──► [MCP Server] ──► [Tool] ──► [API REST] ──► [Datos] ──► [MCP] ──► [IA] ──► [Usuario]
```
- **Ventajas de MCP**:
  1. **Autonomía**: La IA razona dinámicamente sobre la pregunta del usuario y decide por sí misma si debe consultar todos los departamentos o filtrar uno específico.
  2. **Estandarización**: Se escribe el servidor MCP una sola vez en Node.js y funciona en cualquier cliente compatible con MCP (Claude, Cursor, etc.).
  3. **Veracidad**: Garantiza respuestas basadas en datos reales provenientes directamente de la fuente oficial en tiempo real.

---

## 4. Arquitectura del Proyecto

```text
┌──────────┐
│ Usuario  │
└────┬─────┘
     │ 1. Hace una pregunta en lenguaje natural ("¿Existe el departamento de Antioquia?")
     ▼
┌──────────────┐
│ Modelo de IA │ 2. Analiza las herramientas disponibles y emite un Tool Call
└──────┬───────┘
       │ 3. Solicitud JSON-RPC con argumentos ({ "nombre": "Antioquia" })
       ▼
┌──────────────┐
│  MCP Client  │ 4. Transmite el mensaje al servidor local mediante Stdio
└──────┬───────┘
       │
       ▼
┌──────────────┐
│  MCP Server  │ 5. Recibe la orden y ejecuta el controlador en index.js
└──────┬───────┘
       │ 6. Invoca la función interna de la Tool
       ▼
┌───────────────────────────┐
│ Tool obtener_departamentos│ 7. Petición HTTP GET con fetch()
└──────────┬────────────────┘
           │
           ▼
┌───────────────────────────┐
│  API Colombia (Externa)   │ 8. Devuelve objeto JSON con datos reales
└──────────┬────────────────┘
           │
           │ 9. Retorna la respuesta HTTP JSON
           ▼
┌───────────────────────────┐
│  MCP Server (Node.js)     │ 10. Filtra los campos y empaqueta en formato MCP
└──────────┬────────────────┘
           │
           │ 11. Envía resultado estructurado a la IA
           ▼
┌──────────────┐
│ Modelo de IA │ 12. Interpreta la información y genera la respuesta final
└──────┬───────┘
       │
       ▼
┌──────────┐
│ Usuario  │ 13. Recibe la respuesta informada en lenguaje natural
└──────────┘
```

### Explicación de Componentes:
- **Usuario**: Entabla conversación mediante texto en lenguaje natural.
- **Modelo de IA (LLM)**: Motor que razona la intención del usuario y decide si invocar herramientas.
- **MCP Client**: Aplicación (Claude Desktop, MCP Inspector, Cursor) que gestiona el canal de comunicación y le pasa las herramientas al LLM.
- **MCP Server**: Nuestro programa Node.js (`index.js`) que escucha por `StdioServerTransport` y ejecuta las funciones de la herramienta.
- **Tool (`obtener_departamentos`)**: Función JavaScript que construye la URL y realiza la llamada `fetch` a la API.
- **API Colombia**: Servicio público externo REST que almacena los datos de la República de Colombia.

---

## 5. ¿Qué hace nuestra Tool?

### Nombre
`obtener_departamentos`

### Descripción
Obtiene información oficial de los departamentos de Colombia desde la API pública de Colombia. Permite obtener la lista completa de departamentos o consultar/buscar un departamento específico por su nombre.

### Parámetros (JSON Schema)
- `nombre` *(opcional, string)*: Nombre o palabra clave del departamento a consultar (ejemplo: `"Antioquia"`, `"Norte de Santander"`, `"Cundinamarca"`). Si se omite, retorna la lista completa.

### Entrada (Input)
```json
{
  "nombre": "Antioquia"
}
```

### Proceso Interno
1. Captura y sanitiza el parámetro `nombre`.
2. Si se recibió un nombre, construye la URL `https://api-colombia.com/api/v1/Department/search/Antioquia`. Si no, usa `https://api-colombia.com/api/v1/Department`.
3. Ejecuta la llamada `fetch(url)` a la API REST.
4. Procesa la respuesta JSON y extrae únicamente los 7 campos más relevantes (`id`, `nombre`, `capital`, `poblacion`, `superficie_km2`, `cantidad_municipios`, `prefijo_telefonico`).
5. Empaqueta y devuelve la respuesta a la IA en el formato estándar MCP `{ content: [{ type: "text", text: "..." }] }`.

### Salida (Output para la IA)
```json
[
  {
    "id": 2,
    "nombre": "Antioquia",
    "capital": "Medellín",
    "poblacion": 6887306,
    "superficie_km2": 63612,
    "cantidad_municipios": 125,
    "prefijo_telefonico": "4"
  }
]
```

---

## 6. Tecnologías y Herramientas Necesarias

| Herramienta | Para qué sirve | Por qué se necesita |
| :--- | :--- | :--- |
| **Node.js** (v18+) | Entorno de ejecución de JavaScript en el servidor. | Permite ejecutar nuestro código del servidor MCP fuera del navegador. |
| **npm** | Gestor de paquetes de Node.js. | Necesario para instalar el SDK de MCP (`@modelcontextprotocol/sdk`). |
| **@modelcontextprotocol/sdk** | Librería oficial de MCP para Node.js. | Proporciona las clases `Server`, `StdioServerTransport` y esquemas de mensajes. |
| **API pública de Colombia** | Servicio web REST externo de libre acceso. | Suministra la base de datos oficial y actualizada sobre los departamentos. |
| **MCP Inspector / Claude Desktop** | Cliente ejecutor de MCP. | Permite interactuar visualmente con el servidor MCP y la IA. |

---

## 7. Requisitos Previos

- **Node.js**: Versión 18.0.0 o superior instalada.
- **Acceso a Internet**: Perteneciente al entorno donde se ejecuta el servidor para consultar `api-colombia.com`.
- **Sin llaves de API (API Keys)**: La API de Colombia es 100% libre y no requiere autenticación.

---

## 8. Estructura de Carpetas

```text
mcp-colombia-demo/
├── index.js             # Código fuente principal del Servidor MCP y la Tool
├── package.json         # Configuración de dependencias y scripts de Node.js
├── package-lock.json    # Registro exacto de versiones instaladas
└── README.md            # Documentación general y guía del proyecto
```

---

## 9. Crear el Proyecto desde Cero (Paso a Paso)

Si deseas recrear este proyecto en una carpeta completamente vacía, sigue estos pasos:

### Paso 1: Crear la carpeta del proyecto
```bash
mkdir mcp-colombia-demo
cd mcp-colombia-demo
```
*Crea un directorio llamado `mcp-colombia-demo` y entra en él.*

### Paso 2: Inicializar el proyecto Node.js
```bash
npm init -y
```
*Genera un archivo `package.json` por defecto con la configuración básica.*

### Paso 3: Configurar ES Modules y scripts en `package.json`
Edita `package.json` para asegurarte de incluir `"type": "module"` y el script de inspección:
```json
{
  "name": "mcp-colombia-demo",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node index.js",
    "inspect": "npx @modelcontextprotocol/inspector node index.js"
  }
}
```

### Paso 4: Instalar las dependencias de MCP
```bash
npm install @modelcontextprotocol/sdk
```
*Descarga e instala el SDK oficial de Model Context Protocol en la carpeta `node_modules`.*

### Paso 5: Crear el archivo principal `index.js`
Crea el archivo `index.js` e incluye el código del servidor:

```javascript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const API_BASE_URL = "https://api-colombia.com/api/v1";

const server = new Server(
  {
    name: "mcp-colombia-departamentos",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 1. Declarar la herramienta
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "obtener_departamentos",
        description:
          "Obtiene información oficial de los departamentos de Colombia desde la API pública de Colombia. Permite obtener la lista completa de departamentos o consultar/buscar un departamento específico por su nombre.",
        inputSchema: {
          type: "object",
          properties: {
            nombre: {
              type: "string",
              description:
                "Nombre o palabra clave del departamento a consultar (ejemplo: 'Antioquia', 'Norte de Santander', 'Cundinamarca'). Si se omite, retorna la lista de todos los departamentos de Colombia.",
            },
          },
          required: [],
        },
      },
    ],
  };
});

// 2. Ejecutar la herramienta
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name !== "obtener_departamentos") {
    throw new Error(`La herramienta '${name}' no existe en este servidor MCP.`);
  }

  const nombreFiltro = args?.nombre ? String(args.nombre).trim() : null;

  try {
    let url = `${API_BASE_URL}/Department`;
    if (nombreFiltro) {
      url = `${API_BASE_URL}/Department/search/${encodeURIComponent(nombreFiltro)}`;
    }

    const response = await fetch(url);
    if (!response.ok) {
      return {
        isError: true,
        content: [{ type: "text", text: `Error en la API de Colombia: Status ${response.status}` }],
      };
    }

    const data = await response.json();
    if (!data || (Array.isArray(data) && data.length === 0)) {
      return {
        content: [{ type: "text", text: `No se encontraron departamentos para: '${nombreFiltro}'.` }],
      };
    }

    const departamentos = Array.isArray(data) ? data : [data];
    const resultadoLimpio = departamentos.map((dept) => ({
      id: dept.id,
      nombre: dept.name,
      capital: dept.cityCapital?.name || "No reportada",
      poblacion: dept.population,
      superficie_km2: dept.surface,
      cantidad_municipios: dept.municipalities,
      prefijo_telefonico: dept.phonePrefix,
    }));

    return {
      content: [{ type: "text", text: JSON.stringify(resultadoLimpio, null, 2) }],
    };
  } catch (error) {
    return {
      isError: true,
      content: [{ type: "text", text: `Excepción en la Tool: ${error.message}` }],
    };
  }
});

// 3. Iniciar servidor Stdio
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("🟢 Servidor MCP de Colombia listo (Stdio)...");
}

main().catch((err) => {
  console.error("🔴 Error al iniciar servidor MCP:", err);
  process.exit(1);
});
```

---

## 10. Instalación y Ejecución

### Probar en el Navegador con MCP Inspector (Recomendado para Pruebas)
```bash
npm run inspect
```
*Abre la herramienta visual interactiva MCP Inspector en tu navegador para ejecutar `obtener_departamentos` sin configurar un cliente de IA aún.*

---

## 11. Integración con Clientes MCP

### Configuración en Claude Desktop
Para conectar este servidor MCP con la aplicación de escritorio **Claude Desktop**, agrega la siguiente ruta a tu archivo `%APPDATA%\Claude\claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "colombia-departamentos": {
      "command": "node",
      "args": [
        "C:/Users/Usuario/Desktop/Julio trabajos del sena/Hyalure/index.js"
      ]
    }
  }
}
```

Al reiniciar Claude Desktop, verás el icono de herramienta 🛠️ activo en la interfaz de chat.

---

## 📜 Licencia
Este proyecto es de código abierto bajo la licencia **MIT** y está diseñado exclusivamente con fines educativos y de investigación académica.

TDQS

A4.2/5.0

Scored across 1 tool

Disambiguation5/5

With only a single tool, there is no possibility of confusion with other tools. The tool's purpose is clearly focused on retrieving Colombian department information.

Naming Consistency5/5

The tool name follows a clear verb_noun pattern ('obtener_departamentos') which is consistent and readable. With one tool, there are no naming conflicts or mixed conventions.

Tool Count3/5

A one-tool server feels thin, even for a demo, but the tool itself covers a well-defined narrow slice of Colombian data. It sits at the borderline of being just enough for a minimal demonstration.

Completeness4/5

The tool provides both full listing and name-based search for departments, covering the core read operations for this domain. A minor gap is the lack of lookup by department code or integration with other Colombian geographic entities, but the department surface is adequately covered.