rickandmorty-mcp
# rickandmorty-mcp
Servidor MCP para la [API pública de Rick and Morty](https://rickandmortyapi.com/api/).
Expone personajes, localizaciones y episodios como herramientas de sólo lectura,
con una capa de seguridad propia en `src/rickandmorty_mcp/security/`.
- Gestión de paquetes: **uv**
- SDK: `mcp` 2.x (`MCPServer`), transporte **stdio**
- Sin claves ni secretos: la API es pública
## Puesta en marcha
```bash
uv sync
uv run pytest # 134 tests
```
> **macOS:** los tests funcionan siempre. Si al arrancar el servidor a mano ves
> `ModuleNotFoundError`, ejecuta `./scripts/fix_venv_pth.sh`.
> Ver [Problemas conocidos](#problemas-conocidos).
## Conectarlo
Las tres configuraciones ya llevan la ruta absoluta de este proyecto.
### Claude Code
El `.mcp.json` de la raíz ya está listo: abre Claude Code en este directorio y
aprueba el servidor cuando lo pregunte. Comprueba con `/mcp`.
Para tenerlo en **todos** tus proyectos:
```bash
claude mcp add-json rickandmorty "$(jq -c .mcpServers.rickandmorty configs/claude_code.mcp.json)" --scope user
```
### Claude Desktop
```bash
uv run python scripts/install_configs.py --claude-desktop # muestra qué haría
uv run python scripts/install_configs.py --claude-desktop --apply # lo escribe (deja .bak)
```
O fusiona a mano el bloque `mcpServers` de `configs/claude_desktop_config.json`
en `~/Library/Application Support/Claude/claude_desktop_config.json` y reinicia
la app.
### Codex CLI
Codex lee TOML (`~/.codex/config.toml`), no JSON. `configs/codex.mcp.json` es
la fuente canónica y el script hace la traducción:
```bash
uv run python scripts/install_configs.py --codex # muestra el bloque TOML
uv run python scripts/install_configs.py --codex --apply # lo añade (deja .bak)
codex mcp list # comprobar
```
También puedes pegar a mano `configs/codex_config.toml`.
## Herramientas
| Herramienta | Para qué |
|---|---|
| `list_characters` | Busca personajes por `name`, `status`, `species`, `type`, `gender`, `page` |
| `get_character` | Ficha de un personaje por id |
| `get_characters` | Hasta 20 personajes por lista de ids, en una sola llamada |
| `list_locations` | Busca localizaciones por `name`, `type`, `dimension`, `page` |
| `get_location` | Ficha de una localización por id |
| `list_episodes` | Busca episodios por `name` o `episode_code` (`S01E01`) |
| `get_episode` | Ficha de un episodio por id |
Recursos: `rickandmorty://character/{id}`, `rickandmorty://location/{id}`,
`rickandmorty://episode/{id}`.
Todas están marcadas como `read_only_hint`: el servidor no escribe nada.
### Forma de la respuesta
Las respuestas no son el JSON crudo de la API. Se proyectan a los campos
declarados en `api/models.py` y las URLs relacionadas se sustituyen por ids,
lo que ahorra bastantes tokens (un personaje trae hasta 51 URLs de episodio):
```json
{
"id": 1,
"name": "Rick Sanchez",
"status": "Alive",
"species": "Human",
"gender": "Male",
"origin": { "name": "Earth (C-137)", "id": 1 },
"location": { "name": "Citadel of Ricks", "id": 3 },
"episode_ids": [1, 2, 3, "…"],
"episode_count": 51
}
```
Los `*_ids` se pasan directamente a `get_characters`, `get_episode` o
`get_location` para profundizar.
## Seguridad
Está aislada en `src/rickandmorty_mcp/security/` — validación de entradas,
guardia anti-SSRF, rate limiting, saneamiento de salida y auditoría. El detalle
completo, con el modelo de amenazas y lo que **no** cubre, está en
[`docs/SEGURIDAD.md`](docs/SEGURIDAD.md).
Se configura por variables de entorno con prefijo `RM_MCP_` (ver
[`.env.example`](.env.example)); los configs de `configs/` ya traen los valores
recomendados en su bloque `env`.
## Estructura
```
src/rickandmorty_mcp/
├── server.py # herramientas y recursos MCP
├── api/
│ ├── client.py # cliente HTTP: timeouts, reintentos, caché, redirecciones
│ └── models.py # proyección de las respuestas
└── security/ # ← toda la seguridad, aislada
├── policy.py # límites configurables por entorno
├── validation.py # validación de entradas
├── net.py # allowlist de destino y anti-SSRF
├── ratelimit.py # token bucket
├── sanitize.py # saneamiento de salida
├── audit.py # log a stderr, con redacción
├── middleware.py # aplicación por petición
├── tooling.py # rechazos → ToolError legible
└── errors.py # tipos de error
configs/ # configuración para Claude Code, Claude Desktop y Codex
scripts/ # instalador de configs y arreglo del venv en macOS
tests/ # 134 tests
docs/SEGURIDAD.md
```
## Desarrollo
```bash
uv run pytest -v
uv run pytest tests/test_net.py # sólo el guardia anti-SSRF
uv run python -m rickandmorty_mcp # arranca el servidor por stdio
```
Los tests no tocan la red: `respx` simula la API y una fixture parchea la
resolución DNS.
## Problemas conocidos
**macOS oculta los `.pth` del venv.** `uv` escribe los archivos con un nombre
temporal que empieza por punto y luego los renombra; macOS les deja el flag
`UF_HIDDEN`. CPython **ignora** los `.pth` ocultos, así que la instalación
editable nunca entra en `sys.path` y `import rickandmorty_mcp` falla con
`ModuleNotFoundError`. El flag vuelve tras cada `uv sync`.
```bash
./scripts/fix_venv_pth.sh # quita el flag y comprueba el import
```
Dos partes del proyecto ya son inmunes al problema y no necesitan el script:
- **Los tests**, porque `pyproject.toml` declara `pythonpath = ["src"]`.
- **Los clientes MCP**, porque los configs de `configs/` pasan
`PYTHONPATH=<proyecto>/src` en su bloque `env`.
El script sólo hace falta para arrancar el servidor o abrir un REPL a mano.
TDQS
Scored across 7 tools
Each tool has a clear, distinct purpose: list_* tools search with filters, get_* tools fetch by ID, and get_characters is explicitly for bulk retrieval. The singular/plural distinction between get_character and get_characters is clarified in descriptions.
All tools follow a consistent verb_noun pattern (list_<resource>, get_<resource>) using snake_case. The naming is predictable and immediately conveys the action and target resource.
Seven tools is well-scoped for a read-only API client covering three resource types with list and get operations plus a bulk getter. Every tool serves a distinct need without redundancy.
For a read-only Rick and Morty data access server, the surface is complete: all three core resources (characters, locations, episodes) have both search and direct lookup. The bulk character fetch complements the list results and episode character ID lists.