Version License Docker MCP SDK npm TypeScript Bun
Install in Claude Desktop Install in Cursor Install in VS Code
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
| Tool | Description |
|---|---|
anime_search_media | Search anime or manga by title, genre, tag, season, year, format, or status. Returns ranked results with IDs, titles, scores, format, and episode/chapter counts. AniList primary; Jikan (MAL) fallback when AniList has no match for a title-only query. |
anime_get_media | Full detail for one anime or manga by AniList ID — synopsis, format, episode/chapter count, status, season, studios, source material, genres and tags (spoiler-flagged), AniList and MAL scores side by side, streaming links, cover/banner, and direct relations. |
anime_get_relations | Walks the related-works graph within a hop limit. Groups main and supplementary entries by relation priority, then year; not a strict chronology. |
anime_get_schedule | Airing schedule for a season or upcoming episode window. Season mode lists all anime airing in a given season/year. Upcoming mode returns the next episode for each airing title within a date window, with UTC timestamp and countdown. |
anime_find_characters | Characters and voice actors for a title, or look up a character/VA by name. Returns characters with role (main/supporting/background), voice actors by language, and cross-links to other media. |
anime_get_recommendations | Page AniList recommendations with matching MAL votes, or Jikan candidates resolved through AniList. Reports the selected source and Jikan availability; optionally echoes what you liked. |
anime_get_rankings | Top, trending, or seasonal rankings. Filterable by genre, tag, and format. Top returns all-time by score; trending uses AniList's trending order; seasonal returns the current or specified season sorted by popularity. |
anime_get_studio | A studio's full filmography by name or AniList studio ID — all titles the studio produced, sortable by year or score, with format, status, and episode count. |
Resources
| Resource | Description |
|---|---|
anime://media/{id} | Compact media record by AniList ID — title, synopsis, scores, genres, streaming count, and cover image. Stable URI for injectable context. |
skill://anime-guide/SKILL.md | Caller guide for franchise research, cast-to-career lookups, studio filmographies, and recommendation coverage. Also included in plugin, npm, Docker, and MCPB installs. |
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_pagepages results (max 50), andinclude_adult: trueopts 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_page25 or less. Followhas_next_page;total_resultsis 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 requiringinclude_adult: true; discover IDs throughanime_search_media - Returns synopsis, genres, spoiler-flagged tags, studios, direct relations, images, streaming links, and separate AniList/MAL scores.
data_sourcesidentifies successful supplements;not_foundmeans the ID did not resolve full_text: truereturns 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
idup tomax_depthhops (default 2, max 4) - Returns
mainandsupplementaryentries with season year and episode/chapter counts, ordered by relation priority then year.not_foundmeans the root ID did not resolve depth,parent_id,relation_to_parent, andpathshow the shortest route to each entry.relation_to_rootis 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_reachedis the deepest hop returned
anime_get_schedule tool
seasonmode requiresseasonandseason_year;upcomingusesdays_ahead(default 7, max 30). Page withpage/per_page(max 50); adult titles requireinclude_adult: true- Returns UTC ISO 8601 airing times and
time_until_airing_seconds. Followhas_next_page;total_resultsis exact only on the final season page.invalid_seasonandconflicting_inputsidentify invalid mode inputs
anime_find_characters tool
- Supply exactly one of media
id,character_name, orvoice_actor_name.languagefilters only media cast lookups;per_pageis capped at 25 - Returns cast, voice actors, or media appearances according to
mode.truncated: truecarries next-page guidance for capped cast lists;media_not_found/not_founddistinguish an unknown media ID from an unmatched name voice_actor_data_available: falsemeans the provider had no voice actor data, as opposed to an empty list.full_text: truereturns 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
idwithsource: "anilist"(default) orsource: "jikan"; optionalliked_aspectsis 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 withpage/per_page(max 25) before resolving that slice through AniList. Adult and unresolved candidates are omitted;has_next_pagestill follows candidate pages. Jikan does not guarantee a global ranking or a stable snapshot across calls - Both surfaces report
sourceandjikan_status(available,unavailable, ornot_applicablewhen the source lacks a MAL ID), plus separateanilist_rating,jikan_votes, and itemsources. Jikan mode uses nullanilist_ratingandsources: ["jikan"]. Optional annotation failures retain AniList results; selected Jikan/resolution failures return retry-or-switch guidance.truncated: truesupplies continuation with the same source;not_foundmeans the source ID did not resolve, while valid empty pages succeed
anime_get_rankings tool
- Rank
ANIMEorMANGAintop/trending;seasonaland season/year filters apply only toANIME(anime_only_seasonotherwise). Genre/tag/format filters andpage/per_page(max 50) remain available. Adult titles requireinclude_adult: true - Entries carry 1-based
rankandseason_label. Followhas_next_page;total_resultsis exact only on the final page. Seasonal mode takesseason/season_yeartogether or neither for the current season (invalid_seasonotherwise)
anime_get_studio tool
- Identify a studio with exactly one of
nameorid; sort by popularity, score, or release date and page withpage/per_page(max 25) - Returns one row per distinct title within the page, with
is_main_studioidentifying main credits. Followhas_next_page;total_titlesis exact only when the whole filmography fits on page 1.not_foundmeans the studio did not resolve
anime://media/{id} resource
- Read a compact
application/jsonmedia record using an AniListidfromanime_search_mediaoranime_get_media - The ID must be a whole number from 1 to 2147483647; anything else fails with
invalid_idbefore any upstream call - Returns title variants, synopsis, scores, genres, streaming count, and cover image; use
anime_get_mediafor 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
idMalbridge — 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 MALscore(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: truecarry all tags with their flags - Supplement provenance —
anime_get_media.data_sourcesreports 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:
{
"mcpServers": {
"anime-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/anime-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"anime-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/anime-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"anime-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/anime-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+). No API keys needed.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/anime-mcp-server.git
- Navigate into the directory:
cd anime-mcp-server
- Install dependencies:
bun install
- Configure environment (optional):
cp .env.example .env
# edit .env if you want to change transport or log level
Configuration
No server-specific env vars are required. All framework variables are optional with sensible defaults.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_HTTP_HOST | Hostname for HTTP server. | 127.0.0.1 |
MCP_HTTP_ENDPOINT_PATH | Endpoint path for the MCP server. | /mcp |
MCP_SESSION_MODE | Session mode: auto, stateful, or stateless. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424): debug, info, notice, warning, error. | info |
LOG_TOOL_FAILURE_PAYLOADS | Log failed calls' arguments and results, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). Secrets inside free-form values are not redacted. | false |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t anime-mcp-server .
docker run --rm -p 3010:3010 anime-mcp-server
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
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, resources, and inits services. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/services/anilist | AniList GraphQL client — primary source for all queries. |
src/services/jikan | Jikan v4 REST client — MAL scores and recommendations. |
src/services/kitsu | Kitsu JSON:API client — streaming links with sub/dub language detail. |
tests/ | Unit and integration tests mirroring src/. |
skills/ | Published caller guide, available through plugins and MCP skill discovery. |
changelog/ | Per-version changelog files (changelog/<minor>.x/<version>.md). |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor 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:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.