anime-helper (MCP server)
Servidor Model Context Protocol (MCP) para Anime & Manga que entrega JSON estructurado desde AniList GraphQL (sin API key) con Jikan (MyAnimeList) como *fallback*. El LLM del host usa estos datos para redactar resúmenes, recomendaciones y respuestas al usuario.
- 🔎
search_media— búsqueda de ANIME/MANGA (AniList por defecto; Jikan fallback) - 📄
media_details— ficha normalizada (títulos, formato/estado, episodios/capítulos, géneros, sinopsis, enlaces externos, recomendaciones) - 📈
trending— lo que está en tendencia (AniList) - 🩺
health/ ℹ️about— diagnóstico y metadatos del servidor - 🧱 Contrato estable con
schemaVersion, *timeouts*, reintentos con backoff y errores uniformes
No necesitas API key para AniList ni Jikan.
Requisitos
- Python 3.10+
pip- Un host MCP (por ejemplo, tu host OpenAI por STDIO)
Instalación
Opción A — desde tag (recomendado para usuarios)
pip install -U --no-cache-dir git+https://github.com/Ctribsz/AnimeHelper-MCP.git@v0.1.0Opción B — desde main (último código)
pip install -U --no-cache-dir git+https://github.com/Ctribsz/AnimeHelper-MCP.git@mainOpción C — modo dev (editable)
git clone https://github.com/Ctribsz/AnimeHelper-MCP
cd AnimeHelper-MCP
python -m venv .venv
# Linux/Mac:
source .venv/bin/activate
# Windows (PowerShell):
.\.venv\Scripts\Activate.ps1
pip install -U pip
pip install -e .Uso desde un host MCP (STDIO)
En el mcp.config.json de tu host añade:
{
"servers": {
"anime-helper": {
"command": "python",
"args": ["-m", "anime_helper.server"],
"transport": "stdio"
}
}
}Arranca tu host (ejemplo OpenAI):
python -m src.host_openaiDeberías ver algo como:
✔️ Conectado a 'anime-helper' con herramientas: ['search_media', 'media_details', 'trending', 'health', 'about']Prompts de prueba (para el chat del host)
- Búsqueda
Usa anime-helper__search_media {"query":"one piece","kind":"ANIME","limit":3} y muéstrame los títulos con su id.- Detalles (AniList)
Llama anime-helper__media_details {"source":"anilist","id":21,"kind":"ANIME"} y resume en 5 puntos. Cita la URL.- Tendencia (Manga)
Usa anime-helper__trending {"kind":"MANGA","limit":5} y ordénalos por score descendente con título y año.- Salud / versión
Ejecuta anime-helper__health y luego anime-helper__about para ver versión y endpoints.Tools & contrato JSON
search_media(query, kind="ANIME|MANGA", source="anilist|jikan", limit=5)
Éxito:
{
"schemaVersion": "1.0.0",
"query": "one piece",
"kind": "ANIME",
"source": "anilist",
"results": [
{
"source": "anilist",
"id": 21,
"idMal": 21,
"titles": {"romaji":"One Piece","english":"One Piece","native":"ワンピース"},
"year": 1999,
"format": "TV",
"episodes": 1100,
"chapters": null,
"score": 86,
"url": "https://anilist.co/anime/21"
}
]
}media_details(source, id, kind="ANIME|MANGA")
Éxito (campos principales):
{
"schemaVersion": "1.0.0",
"source": "anilist",
"id": 21,
"idMal": 21,
"titles": {"romaji":"One Piece","english":"One Piece","native":"ワンピース"},
"format": "TV",
"status": "RELEASING",
"episodes": 1100,
"chapters": null,
"genres": ["Action","Adventure"],
"tags": ["Shounen", "Pirates"],
"score": {"anilist": 86, "mal": null},
"synopsis": "…",
"url": "https://anilist.co/anime/21",
"external": [{"site":"Official","url":"…"}],
"recommendations": [ /* MediaHit[] */ ]
}trending(kind="ANIME|MANGA", limit=10)
Éxito:
{
"schemaVersion": "1.0.0",
"kind": "MANGA",
"results": [ /* MediaHit[] */ ]
}health() / about()
{"schemaVersion":"1.0.0","ok":true,"sources":["anilist","jikan"]}{
"schemaVersion": "1.0.0",
"name": "anime-helper",
"version": "0.1.0",
"endpoints": {"anilist": "https://graphql.anilist.co", "jikan": "https://api.jikan.moe/v4"},
"limits": {"maxPerPage": 25, "timeoutSec": 15}
}Errores (uniforme)
{
"schemaVersion": "1.0.0",
"error": {
"code": "UPSTREAM_429",
"message": "rate limited by upstream",
"source": "anilist"
}
}Smoke test (opcional, desde tu host)
Crea scripts/smoke_test.sh:
#!/usr/bin/env bash
set -euo pipefail
printf "anime-helper__health\nanime-helper__search_media {\"query\":\"one piece\",\"kind\":\"ANIME\",\"limit\":2}\nsalir\n" | python -m src.host_openaiLinux/Mac:
chmod +x scripts/smoke_test.sh
./scripts/smoke_test.shWindows (PowerShell):
"anime-helper__health`nanime-helper__search_media {""query"":""one piece"",""kind"":""ANIME"",""limit"":2}`nsalir" | python -m src.host_openaiSolución de problemas
- No aparecen las tools → confirma instalación:
pip show anime-helpery la entrada en mcp.config.json.
- 429/5xx → reintenta; el server implementa backoff. Baja
limitsi persiste.
- Sin Internet → AniList/Jikan requieren red.
Arquitectura (modular)
El servidor se ha modularizado para mejorar mantenibilidad y pruebas. Estructura principal:
anime_helper/
├── __init__.py # exporta create_app()
├── server.py # entrypoint: instancia FastMCP y registra tools
├── server_legacy.py # copia de seguridad del servidor monolítico (temporal)
├── core/ # núcleo: red, cache y normalizadores
│ ├── http_client.py # http_get/http_post + err_payload
│ ├── cache.py # cache GQL + función gql()
│ └── normalizers.py # normalizadores AniList (Title/MediaHit/Details)
├── models/
│ └── types.py # TypedDicts: Title, MediaHit, Details, AiringItem
├── tools/ # herramientas MCP (cada archivo registra sus tools)
│ ├── search.py # search_media, resolve_title
│ ├── details.py # media_details
│ ├── trending.py # trending, season_top
│ ├── airing.py # airing_status, airing_calendar
│ ├── cache_tools.py # cache_info, cache_clear
│ ├── nlp.py # ask (router de lenguaje natural)
│ └── meta.py # health, help, help_text, about
└── utils/
└── helpers.py # season_from_monthNotas de diseño:
- Registro explícito de tools: cada módulo en
tools/exponeregister_tools(mcp)para evitar usar decoradores@mcp.tool()en tiempo de importación. - Separación de concerns: red/cache/normalización/modelos separados de las herramientas MCP.
- Backwards compatible:
python -m anime_helper.serversigue siendo el punto de entrada.
Desarrollo local (rápido)
python3 -m venv .venv
source .venv/bin/activate # Linux/Mac
pip install -U pip
pip install -e . # instala deps (incluye mcp[cli] y requests)
# smoke test de import/registro
python3 - << 'PY'
from anime_helper import create_app
app = create_app()
print('app ok:', bool(app))
PYRoadmap
- [ ] Tests unitarios para
core/(http, cache, normalizers) aislando red con mocks. - [ ] Tipos estrictos (mypy) y validación opcional de payloads (pydantic dataclasses ligeras).
- [ ] Mejoras de NLP: ampliar reglas, soportar sinónimos/español neutro y variantes.
- [ ] Config: permitir
ANILIST_GQL,CACHE_TTL,DEFAULT_TIMEOUTvía variables de entorno. - [ ] Docs: ejemplos por herramienta en
READMEcon entradas/salidas reales (golden samples). - [ ] CI: flujo simple (lint + tests) con GitHub Actions.
Versionado
- El paquete declara versión en
pyproject.tomlyabout()la expone. - Publica tags (ej.
v0.1.0) y recomienda instalar por tag:
pip install -U --no-cache-dir git+https://github.com/Ctribsz/AnimeHelper-MCP.git@v0.1.0- Crear/actualizar tag:
git add -A
git commit -m "chore: bump version"
git tag -a v0.1.1 -m "Release v0.1.1"
git push origin main --tagsLicencia
MIT (ver LICENSE).
