Skip to main content
Glama
REMR11

El Oráculo del Mazmorrero

by REMR11
README.md
# El Oráculo del Mazmorrero

Práctica guiada (≈ 90–120 min) para construir tu **primer servidor MCP en Python** y conectarlo a Cursor, incluyendo una tool que llama al **proxy de Azure OpenAI** del curso.

| Primitiva | Qué construyes |
|---|---|
| **Tools** | `tirar_dados`, `generar_monstruo`, `gestionar_inventario`, `narrar_combate_ia` |
| **Resources** | `oraculo://pregunta/{id}` |
| **Prompts** | `crear_personaje` |

---

## Requisitos

- Python 3.10+
- Cursor con soporte MCP
- Credenciales del proxy: URL (`AZURE_PROXY_ENDPOINT`) y API key (`AZURE_PROXY_KEY`)

---

## 1. Clonar y preparar el entorno

```bash
git clone <url-de-este-repo>
cd practica_mcp_dungeons_and_dragons   # o el nombre de la carpeta clonada
python3 -m venv .venv
source .venv/bin/activate              # Windows: .venv\Scripts\activate
pip install -r requirements.txt
```

---

## 2. Explorar el servidor

Abre `server.py`. Está organizado en bloques:

1. **Tools locales** — dados, monstruos, inventario (sin red).
2. **Resource** — oráculo de solo lectura.
3. **Prompt** — plantilla para crear un personaje.
4. **Tool con IA** — `narrar_combate_ia` llama al proxy con `httpx` (async).

Las credenciales **nunca** van en el código: se leen de variables de entorno.

---

## 3. Probar en aislamiento (MCP Inspector)

Con el venv activo:

```bash
mcp dev server.py
```

**Checkpoint:** debes ver 4 tools, 1 resource y 1 prompt.

Para probar `narrar_combate_ia` en el Inspector, exporta antes:

```bash
export AZURE_PROXY_ENDPOINT="https://tu-proxy/v1/chat/completions"
export AZURE_PROXY_KEY="tu-api-key"
mcp dev server.py
```

---

## 4. Conectar a Cursor

1. Copia la plantilla de configuración:

```bash
cp .cursor/mcp.json.example .cursor/mcp.json
```

2. Edita `.cursor/mcp.json` y reemplaza:
   - Las rutas absolutas a `.venv/bin/python` y a `server.py`
   - `AZURE_PROXY_ENDPOINT` y `AZURE_PROXY_KEY` con las del curso

3. Reinicia Cursor o ve a **Settings → Tools & MCP** y confirma el indicador verde.

4. En el chat del Agente, prueba:

```
Tira 2 dados de 20 caras para mi ataque.
```

```
Genera un monstruo de dificultad difícil para mi próximo encuentro.
```

```
Agrega "espada legendaria" a mi inventario y luego muéstrame qué tengo.
```

```
Narra con IA un combate entre mi héroe Aria y un Dragón juvenil, resultado: crítico.
```

---

## 5. Retos (elige al menos 2)

1. Tool `curar_heroe(puntos)` — rechaza negativos.
2. Persistencia del inventario en `inventario.json`.
3. Resource `bestiario://lista` con el bestiario en JSON.
4. Parámetro opcional `tono` en `narrar_combate_ia` (`epico` / `comico` / `oscuro`).
5. Un reintento si el proxy hace timeout.

---

## Seguridad (imprescindible)

- No hardcodees la API key en `server.py`.
- No subas `.cursor/mcp.json` con secretos (ya está en `.gitignore`). Usa `mcp.json.example`.
- Valida parámetros de entrada antes de llamar APIs externas.
- No ejecutes servidores MCP de fuentes no verificadas sin revisar el código.

---

## Solución de problemas

| Síntoma | Qué revisar |
|---|---|
| Servidor no aparece en Cursor | Rutas absolutas en `mcp.json` |
| `ModuleNotFoundError: mcp` / `httpx` | Que `command` apunte a `.venv/bin/python` |
| Variables faltantes en `narrar_combate_ia` | Bloque `env` de `mcp.json` |
| Error HTTP 4xx/5xx del proxy | URL, formato del body y contrato del proxy del curso |

---

## Verificación rápida (sin Cursor)

```bash
source .venv/bin/activate
python scripts/smoke_test.py
```

Confirma que se registran las 4 tools, el resource y el prompt, e invoca las tools locales.

---

## Guía completa de la clase

El guion pedagógico paso a paso está en [`PRACTICA.md`](./PRACTICA.md) (contexto, conceptos, rúbrica y discusión de seguridad).

---

## Estructura del repo

```
.
├── server.py                 # Servidor MCP (FastMCP)
├── requirements.txt          # mcp, httpx
├── PRACTICA.md               # Guion completo de la clase
├── scripts/
│   └── smoke_test.py         # Verificación local sin Cursor
├── .cursor/
│   └── mcp.json.example      # Plantilla sin secretos
├── .env.example              # Variables de entorno de ejemplo
├── .gitignore
└── README.md
```