Skip to main content
Glama
Jotarose

mcp-server-multitask

by Jotarose
README.md
# mcp_training

Servidor **MCP** con herramientas de clima, geocodificación y divisas, y un
cliente de consola que conversa con un modelo de OpenAI capaz de usarlas.

```
Tú › ¿Qué tiempo hace en Madrid?

Modelo:
  En Madrid hay 24,3 °C, humedad del 41 % y cielo despejado.

  · geocode_city → get_current_weather
```

## Cómo funciona

Por defecto (`MCP_MODE=local`) todo ocurre en tu máquina: el cliente se conecta
al servidor MCP en `127.0.0.1`, descubre sus herramientas, se las declara al
modelo y las ejecuta él cuando el modelo las pide.

```
main_server.py (MCP) <── 127.0.0.1:8002 ── main_client.py ──> OpenAI
5 herramientas                              tu terminal        el modelo decide
sobre APIs públicas                                            qué usar
```

La alternativa (`MCP_MODE=connector`) usa el conector MCP nativo de la Responses
API: se le pasa a OpenAI la URL del servidor y es OpenAI quien lista, llama y
encadena las herramientas. Como la conexión la abre OpenAI desde *sus*
servidores, `127.0.0.1` no le vale y hay que publicar el servidor con un túnel.

```
main_client.py ──> OpenAI (Responses API) ──> [túnel] ──> main_server.py (MCP)
```

En los dos modos el modelo encadena las llamadas por su cuenta (ciudad →
coordenadas → clima) y la CLI muestra la misma traza.

### Herramientas

| Herramienta | Entrada | Salida |
|---|---|---|
| `geocode_city` | nombre de ciudad | latitud, longitud, país y zona horaria |
| `get_current_weather` | coordenadas | temperatura, humedad, estado del cielo |
| `get_weather_forecast` | coordenadas | pronóstico de 7 días |
| `convert_currency` | importe + dos códigos ISO | importe convertido y tasa aplicada |
| `get_exchange_rates` | código ISO de la moneda base | sus tasas frente al resto de monedas |

Clima y geocodificación usan [Open-Meteo](https://open-meteo.com/) (gratis, sin
clave). Las divisas usan [ExchangeRate-API](https://www.exchangerate-api.com/),
que sí requiere clave, y admiten 20 monedas (`/monedas` en la CLI).

### Estructura

```
config/settings.py     configuración y logging (todo sale del .env)
server/                herramientas + clientes HTTP de las APIs externas
client/                cliente de OpenAI + interfaz de terminal
main_server.py         arranca el servidor MCP
main_client.py         arranca la conversación
```

## Instalación

Requiere **Python 3.11+**. Con [uv](https://docs.astral.sh/uv/) (recomendado):

```bash
git clone <url-del-repo>
cd mcp_training
uv sync
```

O con pip y un entorno virtual:

```bash
python -m venv .venv
.venv\Scripts\activate        # Windows;  en Linux/macOS: source .venv/bin/activate
pip install -r requirements.txt
```

### Configuración

Copia el ejemplo y rellena tus claves:

```bash
cp .env.example .env
```

Solo dos variables son obligatorias:

| Variable | Para qué |
|---|---|
| `API_KEY_EXCHANGE` | tasas de cambio ([clave gratuita aquí](https://www.exchangerate-api.com/)) |
| `OPENAI_API_KEY` | el modelo del cliente |

Todo lo demás (modo, modelo, puerto, transporte, timeouts, nivel de log) tiene
valores por defecto sensatos y está documentado en [.env.example](.env.example).

## Uso

Hacen falta **dos terminales**: servidor y cliente.

### 1. Arranca el servidor MCP

```bash
uv run python main_server.py
```

Queda escuchando en `http://127.0.0.1:8002/mcp`.

### 2. Lanza el cliente

```bash
uv run python main_client.py
```

Escribe tu consulta y pulsa Enter. La conversación tiene memoria: tras
preguntar por Madrid puedes decir simplemente «¿y mañana?».

```
Convierte 100 USD a EUR
¿Cuál es el clima actual en Madrid?
Dame el pronóstico del tiempo para Nueva York
¿Qué coordenadas tiene Tokio?
```

Comandos de la CLI:

| Comando | Qué hace |
|---|---|
| `/ayuda` | herramientas, ejemplos y comandos |
| `/monedas` | códigos de moneda soportados |
| `/salir` | terminar (también Ctrl+C y Ctrl+D) |

### Modo connector: dejar que OpenAI llame a las herramientas

Con `MCP_MODE=connector` es OpenAI quien lista y ejecuta las herramientas, así
que el servidor tiene que ser accesible desde internet. Hace falta una tercera
terminal con un túnel; con
[devtunnel](https://learn.microsoft.com/azure/developer/dev-tunnels/):

```bash
devtunnel port create -p 8002 --allow-anonymous
devtunnel host
```

Copia la URL que imprime y ponla en el `.env`:

```
MCP_MODE=connector
MCP_PUBLIC_URL=https://xxxxxxx-8002.euw.devtunnels.ms
```

Vale cualquier túnel (ngrok, Cloudflare Tunnel…); solo importa que la URL sea
accesible desde fuera. El cliente añade `/mcp` por su cuenta si no lo lleva.

### Usar el servidor sin el cliente

El servidor es un MCP estándar: sirve para cualquier cliente compatible. Para
conectarlo como subproceso (Claude Desktop, Claude Code…) pon
`MCP_TRANSPORT=stdio` en el `.env`; así no hace falta ni el puerto.

## Problemas frecuentes

| Síntoma | Causa |
|---|---|
| `API_KEY_EXCHANGE Field required` al arrancar | falta el `.env` o la clave |
| `No se pudo conectar con el servidor MCP en http://127.0.0.1:8002/mcp` | falta arrancar `main_server.py` en otra terminal |
| El cliente no arranca y avisa de `MCP_PUBLIC_URL` | con `MCP_MODE=connector`, falta la URL del túnel en el `.env` |
| El modelo dice que no puede usar las herramientas | en modo connector, el túnel está caído o `MCP_PUBLIC_URL` está obsoleta (cambia en cada `devtunnel host`) |
| Error de cuota de OpenAI | saldo agotado; reintentar no lo arregla |

Para ver el detalle de cada llamada (argumentos, respuestas, URLs) pon
`LOG_LEVEL=DEBUG` en el `.env`. Los logs van a stderr, así que
`python main_client.py > charla.txt` guarda solo la conversación.