@cyanheads/anime-mcp-server
Search anime/manga, get full detail, franchise relations, seasonal schedule, characters, rankings, and studio filmography via MCP. STDIO or Streamable HTTP.
8 Tools • 2 Resources
Overview
Anime and manga data from AniList, Jikan (MyAnimeList), and Kitsu. Search titles, pull full detail with side-by-side AniList and MAL scores, walk a franchise's relation graph, check the airing schedule, and look up characters, voice actors, and studio filmographies.
Tools
Resources
Media resource data is also reachable via tools. Use anime_search_media to discover AniList IDs before fetching its resource URI.
Capability reference
anime_search_media tool
- Search anime or manga by title, genre, tag, season/year, format, status, or up to 5 sort values; at least one criterion is required.
page/per_page pages results (max 50), and include_adult: true opts into adult titles
- Results carry AniList IDs, titles, scores, and episode/chapter counts. AniList is primary; title-only searches with no match can fall back to Jikan at
per_page 25 or less. Follow has_next_page; total_results is exact only on the final page
- AniList serves only the first 5,000 search, season, and ranking entries; deeper pages fail with
page_depth_exceeded, so narrow the criteria instead
anime_get_media tool
- Fetch full detail by AniList
id, with adult content requiring include_adult: true; discover IDs through anime_search_media
- Returns synopsis, genres, spoiler-flagged tags, studios, direct relations, images, streaming links, and separate AniList/MAL scores.
data_sources identifies successful supplements; not_found means the ID did not resolve
full_text: true returns the complete result as fenced JSON; by default the synopsis is a 500-character preview and tags and relations are shortened, with counts of what was omitted
anime_get_relations tool
- Walk a franchise from an AniList
id up to max_depth hops (default 2, max 4)
- Returns
main and supplementary entries with season year and episode/chapter counts, ordered by relation priority then year. not_found means the root ID did not resolve
depth, parent_id, relation_to_parent, and path show the shortest route to each entry. relation_to_root is set only for entries linked directly to the root, and is null otherwise. Entries at the hop limit are returned without their own relations; depth_reached is the deepest hop returned
anime_get_schedule tool
season mode requires season and season_year; upcoming uses days_ahead (default 7, max 30). Page with page/per_page (max 50); adult titles require include_adult: true
- Returns UTC ISO 8601 airing times and
time_until_airing_seconds. Follow has_next_page; total_results is exact only on the final season page. invalid_season and conflicting_inputs identify invalid mode inputs
anime_find_characters tool
- Supply exactly one of media
id, character_name, or voice_actor_name. language filters only media cast lookups; per_page is capped at 25
- Returns cast, voice actors, or media appearances according to
mode. truncated: true carries next-page guidance for capped cast lists; media_not_found/not_found distinguish an unknown media ID from an unmatched name
voice_actor_data_available: false means the provider had no voice actor data, as opposed to an empty list. full_text: true returns every role on the page and the full biography as fenced JSON; by default biographies are 500-character previews and staff roles stop at 20, with counts of what was omitted
anime_get_recommendations tool
- Fetch recommendations for an AniList
id with source: "anilist" (default) or source: "jikan"; optional liked_aspects is echoed unchanged. AniList pages its recommendations and adds matching MAL votes. Jikan deduplicates its supplied list by maximum votes, orders votes descending/MAL ID ascending, and locally pages candidates with page/per_page (max 25) before resolving that slice through AniList. Adult and unresolved candidates are omitted; has_next_page still follows candidate pages. Jikan does not guarantee a global ranking or a stable snapshot across calls
- Both surfaces report
source and jikan_status (available, unavailable, or not_applicable when the source lacks a MAL ID), plus separate anilist_rating, jikan_votes, and item sources. Jikan mode uses null anilist_rating and sources: ["jikan"]. Optional annotation failures retain AniList results; selected Jikan/resolution failures return retry-or-switch guidance. truncated: true supplies continuation with the same source; not_found means the source ID did not resolve, while valid empty pages succeed
anime_get_rankings tool
- Rank
ANIME or MANGA in top/trending; seasonal and season/year filters apply only to ANIME (anime_only_season otherwise). Genre/tag/format filters and page/per_page (max 50) remain available. Adult titles require include_adult: true
- Entries carry 1-based
rank and season_label. Follow has_next_page; total_results is exact only on the final page. Seasonal mode takes season/season_year together or neither for the current season (invalid_season otherwise)
anime_get_studio tool
- Identify a studio with exactly one of
name or id; sort by popularity, score, or release date and page with page/per_page (max 25)
- Returns one row per distinct title within the page, with
is_main_studio identifying main credits. Follow has_next_page; total_titles is exact only when the whole filmography fits on page 1. not_found means the studio did not resolve
anime://media/{id} resource
- Read a compact
application/json media record using an AniList id from anime_search_media or anime_get_media
- The ID must be a whole number from 1 to 2147483647; anything else fails with
invalid_id before any upstream call
- Returns title variants, synopsis, scores, genres, streaming count, and cover image; use
anime_get_media for tags, studios, streaming links, and relations
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Anime/manga-specific:
- Three-source architecture: AniList GraphQL (primary), Jikan v4 REST (MAL scores + recommendations), Kitsu JSON:API (streaming links with sub/dub language detail)
- ID reconciliation via AniList's
idMal bridge — no cross-source ID guessing
- Franchise relation graph traversal with heuristic ordering by relation-type priority, then season year
- Rate-limit-aware service layer: AniList 30 req/30s with automatic backoff; Jikan 350ms floor between calls
- Keyless by design — all three sources are public and require no API credentials
Agent-friendly output:
- Dual scores surfaced separately — AniList
meanScore (0–100) and MAL score (0–10) with population size (scored_by) so agents can reason about weight; never blended into a composite
- Spoiler flags — the tag summary hides spoiler/adult tags; structured output and
full_text: true carry all tags with their flags
- Supplement provenance —
anime_get_media.data_sources reports whether AniList, MAL/Jikan, and Kitsu data was retrieved; an unavailable supplement leaves its flag false
- UTC timestamps throughout; season labels echoed (
WINTER 2024) to avoid the winter/spring/summer/fall boundary footgun
Getting started
No API keys required — all three upstream sources (AniList, Jikan, Kitsu) are keyless public APIs.
Add the following to your MCP client configuration file:
Or with npx (no Bun required):
Or with Docker:
For Streamable HTTP, set the transport and start the server:
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+). No API keys needed.
Installation
- Clone the repository:
- Navigate into the directory:
- Install dependencies:
- Configure environment (optional):
Configuration
No server-specific env vars are required. All framework variables are optional with sensible defaults.
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
-
Run checks and tests:
Docker
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/anime-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catch in tool logic
- Use
ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
- Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
- AniList is primary — supplement failures (Jikan, Kitsu) degrade gracefully via
Promise.allSettled
Contributing
Issues are welcome. Run checks and tests before submitting:
License
Apache-2.0 — see LICENSE for details.