mal-mcp
Allows deployment of the MCP server as a hosted multi-user service on Cloudflare Workers, where each user gets isolated state stored in Durable Objects and can connect via unique URLs.
Provides tools for interacting with the MyAnimeList v2 API, enabling AI agents to search anime and manga, get detailed information, rankings, seasonal listings, and manage user anime/manga lists including adding, updating, and removing entries.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mal-mcpsearch for anime similar to Attack on Titan"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mal-mcp
A Model Context Protocol server that exposes the MyAnimeList v2 API to Claude and other MCP-compatible clients. Written in TypeScript, runs locally via Bun over stdio or deploys to Cloudflare Workers as a hosted multi-user server.
Tools
Setup
configure— stdio only — store the user's MyAnimeListclient_id(andclient_secretif issued). Must be called before any other tool. Not registered on the Worker; on the Worker, each user signs in through the MCP OAuth flow when they add the server to their client.authenticate— stdio only (meaningful) — start the MAL OAuth flow; opens a browser and waits for the local callback. On the Worker this is a no-op kept for compatibility — auth happens automatically on connect via MCP OAuth.get_auth_status— check whether credentials and user tokens are available.
Public (Client ID only)
search_anime— search anime by titleget_anime_details— full details for an anime IDget_anime_ranking— ranked lists (all, airing, upcoming, tv, ova, movie, special, bypopularity, favorite)get_seasonal_anime— anime by year + seasonsearch_manga— search manga by titleget_manga_details— full details for a manga IDget_manga_ranking— ranked lists (all, manga, novels, oneshots, doujin, manhwa, manhua, bypopularity, favorite)
User-scoped (OAuth2 access token required)
get_current_user— profile + anime statistics for the authenticated userget_anime_suggestions— personalized anime recommendationsget_user_anime_list— read any user's public anime list (or@me)update_anime_list_status— add / update list status, score, episodes watched, etc.delete_anime_list_item— remove an anime from your listget_user_manga_list— read any user's public manga list (or@me)update_manga_list_status— add / update list status, score, chapters read, etc.delete_manga_list_item— remove a manga from your list
Option 1: Run locally over stdio
1. Install
bun install2. Wire it up to your MCP client
Add to claude_desktop_config.json (Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"mal": {
"command": "bun",
"args": ["C:\\BrunoLM\\Projects\\mal-mcp\\src\\index.ts"]
}
}
}For Claude Code, use claude mcp add or drop the equivalent block into .claude/mcp.json.
3. Configure your MAL credentials
Create an API client at https://myanimelist.net/apiconfig:
App Type: other / web
App Redirect URL:
http://localhost:8765/callback
Then, from your MCP client, call the configure tool with your client_id (and client_secret if MAL issued one). Credentials are persisted to ~/.mal-mcp-config.json.
4. (Optional) Authorize for user-scoped tools
Call authenticate from your MCP client. A browser opens, you approve the request, the local server on port 8765 catches the redirect, and tokens land in ~/.mal-mcp-tokens.json. The server refreshes them automatically from there.
If you prefer a CLI:
$env:MAL_CLIENT_ID = "your-client-id"
# $env:MAL_CLIENT_SECRET = "your-client-secret" # only if issued
bun run authOption 2: Host on Cloudflare Workers (multi-user, MCP OAuth)
A single Worker serves every user behind standard MCP OAuth 2.1 (Dynamic Client Registration). One URL for everyone: https://mal-mcp.<account>.workers.dev/mcp. During sign-in each user supplies their own MAL client_id (and client_secret if issued); per-user state lives in a Durable Object keyed by a hash of those credentials.
1. Operator setup (once)
bun install
bunx wrangler login
bunx wrangler kv namespace create OAUTH_KVPaste the returned namespace id into wrangler.jsonc (replace REPLACE_WITH_KV_ID), then deploy:
bun run worker:deployFor local development:
bunx wrangler kv namespace create OAUTH_KV --preview
bun run worker:dev2. Each user connects
Create a MAL API client at https://myanimelist.net/apiconfig (App Type: other). Set App Redirect URL to:
https://mal-mcp.<account>.workers.dev/mal/callback(This exact URL — same for every user of a given deployment.)
Add the MCP server to your client:
claude mcp add --transport http mal https://mal-mcp.<account>.workers.dev/mcpOr equivalently in config:
{ "mcpServers": { "mal": { "url": "https://mal-mcp.<account>.workers.dev/mcp" } } }Your MCP client will pop a browser tab on first connect. The Worker's authorize page asks for your MAL
client_id(andclient_secretif issued), redirects you to MyAnimeList to approve, then returns you to your MCP client — now signed in. Access and refresh tokens are persisted in your Durable Object; the MAL access token is refreshed automatically.
Security notes for hosted deployments
The Worker is its own OAuth 2.1 authorization server for MCP. Bearer tokens issued to your MCP client are scoped to you; leaking one lets the bearer call MAL on your behalf until the token expires.
Different MAL credentials → different Durable Object → fully separate state. There is no cross-user shared state.
The Worker holds no MAL credentials of its own; each user supplies their own MAL API client.
Data storage
stdio
Two plaintext JSON files in your home directory, created with mode 0600 (owner read/write only):
File | Contents |
| Your MAL |
| MAL |
Delete either file to reset the corresponding state. Nothing is sent anywhere besides myanimelist.net and api.myanimelist.net.
Hosted Worker
Two Cloudflare storage surfaces:
OAUTH_KV (Workers KV namespace) — used by @cloudflare/workers-oauth-provider and by the MAL authorize relay:
Registered OAuth clients (Dynamic Client Registration), authorization grants, and access/refresh tokens. The provider stores grant
propsencrypted; the encryption key is wrapped into the issued token itself, so KV snapshots alone are not enough to recover props.Short-lived (10-minute TTL) pending-MAL-auth records keyed by a random state string. Each record holds the pending authorize URL, your MAL
client_id/client_secret, the PKCE verifier, and the callback URL. Entries are deleted as soon as the MAL callback consumes them, or expire automatically otherwise. They are stored as plaintext JSON in KV.
MAL_SESSION (Durable Object, one per user) — keyed by u:<32-hex> where the hex is the first 32 chars of sha256("v1:" + mal_client_id + ":" + (mal_client_secret ?? "")). Stored as plaintext in the DO's SQLite storage (Cloudflare encrypts DO storage at rest on disk):
config: your MALclient_idand (if issued)client_secret.tokens: MALaccess_token,refresh_token,expires_at.
Two different MAL credential pairs produce two different hashes → two fully separate Durable Objects with no shared state.
What is not stored: anime/manga lists, user profile data, search results, or anything else returned from MAL — those flow straight through the request on demand. No analytics, no logs of request contents beyond standard Cloudflare observability metrics.
What travels over the wire: MAL client_id/client_secret are submitted as form fields from your browser to the authorize page over HTTPS. MAL access tokens are forwarded as Authorization: Bearer … to api.myanimelist.net.
Resetting a user's state: revoke the grant from your MCP client (or reconnect), or contact the operator to delete the matching Durable Object. Re-authorizing with the same MAL credentials will reuse the same DO and its existing tokens.
Environment variables (stdio only)
Variable | Required | Purpose |
| no | Seeds the stdio config store on first boot if nothing is saved yet. |
| no | Same, for clients that were issued a secret. |
| no | Port the one-shot OAuth callback listens on (default |
On hosted Worker deployments these env vars are not used; each end user supplies their own MAL credentials through the Worker's authorize page during MCP OAuth sign-in.
Development
bun run dev # stdio, watch mode
bun run worker:dev # Worker, local (miniflare)
bun run typecheck # tsc --noEmitAll tools take an optional fields string that passes straight through to MAL — see the field spec if you need to override the defaults.
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/brunolm/mal-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server