Skip to main content
Glama
hectorcast44

mcp-distributed-sse-poc

by hectorcast44
README.md
# PoC: Protocolo MCP Distribuido sobre HTTP/SSE (TypeScript)

Esta Prueba de Concepto (PoC) implementa la especificación del **Model Context Protocol (MCP)** en una arquitectura distribuida de red de 3 capas en Node.js y TypeScript, sin dependencias de LLMs externos. Demuestra el handshake, la negociación de capacidades, el descubrimiento dinámico de herramientas y la ejecución remota de herramientas mediante **Server-Sent Events (SSE)** y **HTTP POST**.

---

## 🏗 Arquitectura de las 3 Capas

```
┌─────────────────────────────────────────────────────────────────────────┐
│                           CAPA 3: MCP HOST                              │
│                            (src/host.ts)                                │
│    - Orquesta la aplicación cliente.                                    │
│    - Controla el flujo secuencial: descubrimiento y llamadas a tools.    │
└────────────────────────────────────┬────────────────────────────────────┘
                                     │ (Invoca API del cliente)
┌────────────────────────────────────▼────────────────────────────────────┐
│                          CAPA 2: MCP CLIENT                             │
│                           (src/client.ts)                               │
│    - Implementa SSEClientTransport (@modelcontextprotocol/sdk).        │
│    - Inicia GET /sse para handshake y recibe evento 'endpoint'.         │
│    - Envía mensajes JSON-RPC (initialize, tools/list, tools/call) POST. │
│    - Recibe resultados JSON-RPC de forma asíncrona vía SSE stream.      │
└────────────────────────────────────┬────────────────────────────────────┘
                                     │ Red IP / HTTP (LAN, VPN o Internet)
                                     │ GET /sse  (Server -> Client stream)
                                     │ POST /messages?sessionId=...
┌────────────────────────────────────▼────────────────────────────────────┐
│                          CAPA 1: MCP SERVER                             │
│                           (src/server.ts)                               │
│    - Servidor HTTP (Express) escuchando en 0.0.0.0:3001                 │
│    - Implementa SSEServerTransport (@modelcontextprotocol/sdk).         │
│    - Expone endpoints /sse (stream) y /messages (POST).                 │
│    - Valida parámetros estrictos con Zod.                               │
│    - Herramientas: `calculate_loan_amortization` y                     │
│      `analyze_investment_projection`.                                   │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 🛠 Herramientas Disponibles para Razonamiento del Agente

1. **`calculate_loan_amortization`**:
   - **Propósito**: Evalúa la deuda financiera y el impacto de prepagos a capital (sistema francés).
   - **Parámetros**:
     - `principal` (número > 0): Monto total financiado.
     - `annualInterestRate` (número > 0): Tasa de interés anual (%).
     - `termMonths` (entero > 0): Plazo en meses.
     - `extraMonthlyPayment` (número opcional): Pago mensual adicional a capital.
   - **Métricas devueltas**: Cuota mensual regular, desembolso total, intereses pagados, meses y dinero ahorrados por aceleración.

2. **`analyze_investment_projection`**:
   - **Propósito**: Evalúa crecimiento compuesto de patrimonio, poder adquisitivo real deflactado y escenarios por riesgo.
   - **Parámetros**:
     - `initialCapital` (número >= 0): Capital inicial.
     - `monthlyContribution` (número >= 0): Aportación mensual.
     - `annualReturnRate` (número): Rendimiento nominal anual estimado (%).
     - `timeHorizonYears` (entero > 0): Horizonte temporal en años.
     - `annualInflationRate` (número opcional, default: 4.0%): Inflación estimada.
     - `riskProfile` (`"conservative"` | `"moderate"` | `"aggressive"`): Perfil de volatilidad.
   - **Métricas devueltas**: Capital nominal final, ganancias netas nominales, poder de compra real deflactado, escenarios pesimista/esperado/optimista y tasa real anual.

### 🧠 ¿Cómo probar el razonamiento de un Agente con estas herramientas?

Puedes plantearle al agente problemas de toma de decisiones como:
> *"Tengo $50,000 libres en el banco y un crédito automotriz de $250,000 con tasa del 12.5% a 48 meses. ¿Me conviene aportar esos $50,000 a capital para reducir mi deuda o invertirlos a 4 años con un rendimiento estimado del 11% anual moderado e inflación del 4%? Analiza ambas opciones con las herramientas disponibles y dame tu recomendación fundamentada."*

El agente deberá:
1. Identificar ambas herramientas en el catálogo (`tools/list`).
2. Mapear y ejecutar `calculate_loan_amortization` para medir el costo de los intereses.
3. Mapear y ejecutar `analyze_investment_projection` para calcular el rendimiento real.
4. Contrastar el costo de oportunidad financiero y formular una conclusión razonada.

---

## 🔄 Flujo Detallado de Red y Handshake MCP

1. **Apertura de Canal SSE:**
   - El cliente realiza una solicitud HTTP `GET /sse`.
   - El servidor responde con `Content-Type: text/event-stream` y mantiene abierta la conexión.
   - El servidor genera un `sessionId` (UUID) único y emite inmediatamente un evento SSE llamado `endpoint`:
     ```http
     event: endpoint
     data: /messages?sessionId=df193f22-9b80-4297-9039-2e818054826d
     ```

2. **Handshake de Inicialización:**
   - El cliente recibe el endpoint de retorno y envía una solicitud JSON-RPC `initialize` vía `POST /messages?sessionId=...`.
   - El servidor procesa la inicialización y envía la respuesta JSON-RPC con sus capacidades y versión a través del **stream SSE**.
   - El cliente confirma enviando la notificación `notifications/initialized` vía POST.

3. **Descubrimiento y Ejecución de Herramientas:**
   - **`tools/list`**: El cliente envía `POST /messages?sessionId=...` con el método `tools/list`. El servidor responde por SSE con el catálogo y los esquemas Zod convertidos a JSON Schema.
   - **`tools/call`**: El cliente envía `POST /messages?sessionId=...` con el método `tools/call`, el nombre de la herramienta y sus argumentos. El servidor ejecuta la lógica y devuelve el resultado enriquecido vía SSE.

4. **Desconexión Limpia:**
   - El cliente cierra el canal SSE; el servidor detecta el evento `close`, elimina la sesión de memoria y libera los recursos.

---

## 🚀 Requisitos Previos

- Node.js v18 o superior.
- Dependencias instaladas:
  ```bash
  npm install
  ```

---

## 🖥 Instrucciones de Ejecución

### Opción A: Prueba Local (Misma máquina, dos terminales)

**Terminal 1 (Servidor MCP):**
```bash
npm run start:server
```
El servidor quedará a la espera en `http://0.0.0.0:3001`.

**Terminal 2 (Host MCP):**
```bash
npm run start:host
```
Por defecto se conectará a `http://localhost:3001/sse`.

---

### Opción B: Entorno Distribuido en Red (Dos máquinas distintas)

1. **En la Máquina Servidor (ej. IP `192.168.1.50`):**
   ```bash
   npm run start:server
   ```
   *(Asegúrate de que el puerto `3001` no esté bloqueado por el firewall).*

2. **En la Máquina Cliente / Host:**
   Puedes indicar la URL mediante argumento de línea de comandos o variable de entorno:

   **Vía argumento CLI:**
   ```bash
   npm run start:host -- http://192.168.1.50:3001/sse
   ```

   **Vía variable de entorno:**
   ```bash
   SERVER_URL=http://192.168.1.50:3001/sse npm run start:host
   ```