Skip to main content
Glama
MorpKnight

MyAnimeList MCP Server

by MorpKnight
README.md
<div align="center">

# MyAnimeList MCP Server

Search, inspect, rank, and manage MyAnimeList anime and manga from any MCP-compatible AI client.

<p>
  <a href="https://github.com/MorpKnight/myanimelist-mcp/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/MorpKnight/myanimelist-mcp/ci.yml?label=CI&logo=github" alt="CI status"></a>
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white" alt="Python 3.12+"></a>
  <a href="https://github.com/modelcontextprotocol/python-sdk"><img src="https://img.shields.io/badge/MCP-SDK%20v2-6B4FBB" alt="MCP SDK v2"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT License"></a>
</p>

</div>

MyAnimeList MCP Server is a Python MCP server for the MyAnimeList API. It uses MCP SDK v2, keeps stdio as the default transport, and exposes the MAL API through typed tools that work with Claude, Codex, Gemini, and other MCP clients.

> [!TIP]
> Public tools work with a MAL client ID. Authenticated tools use OAuth and can either open a local browser flow or use a refresh token in headless environments.

## Features

- 15 tools for anime, manga, rankings, seasonal releases, public lists, and the authenticated user profile.
- MCP SDK v2 with stdio transport and protocol compatibility for existing clients.
- One reusable async HTTP client per server lifespan.
- Explicit timeouts, bounded retries for safe GET requests, connection limits, and sanitized errors.
- MAL OAuth with PKCE plain mode, state validation, localhost callback handling, token reuse, and concurrency locking.
- Memory-only access and refresh tokens; no token persistence files.
- Docker image built from the locked dependency graph with uv.

## How it works

The server starts an MCP stdio process. Each tool call is translated into a MyAnimeList API request through the shared client. Public requests use the MAL client ID; authenticated requests add a bearer token obtained from the in-memory OAuth manager.

Successful responses preserve the MAL response shape. Error responses use a stable <code>error</code> field and, when available, <code>status_code</code>, without returning raw response bodies, URLs, authorization codes, or tokens.

## Prerequisites

- Python 3.12 or newer
- [uv](https://docs.astral.sh/uv/)
- A MyAnimeList API client ID
- A MyAnimeList client secret for authenticated tools
- Docker, only if you want to run the container image

## Quick start

Clone the repository and install the locked environment:

~~~bash
git clone https://github.com/MorpKnight/myanimelist-mcp.git
cd myanimelist-mcp
cp .env.example .env
uv sync --locked
~~~

Edit <code>.env</code> and set at least <code>MAL_CLIENT_ID</code>. Add <code>MAL_CLIENT_SECRET</code> before using authenticated tools.

Run the server:

~~~bash
uv run --locked main.py
~~~

The default transport is stdio. stdout is reserved for MCP messages; OAuth diagnostics are sent to stderr.

## MyAnimeList application setup

Create an application from [MyAnimeList API Config](https://myanimelist.net/apiconfig).

Use these values as a starting point:

- **App Description:** <code>An open-source MCP server for searching and managing MyAnimeList data from AI clients.</code>
- **App Redirect URL:** <code>http://127.0.0.1:8080/callback</code>
- **Homepage URL:** <code>https://github.com/MorpKnight/myanimelist-mcp</code>

Copy the generated client ID and client secret into <code>.env</code>. The redirect URL must exactly match the URL registered in MAL.

## Configure an MCP client

### Claude Desktop

Add this entry to <code>claude_desktop_config.json</code> and replace the project path:

~~~json
{
  "mcpServers": {
    "myanimelist": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/myanimelist-mcp",
        "run",
        "--locked",
        "main.py"
      ]
    }
  }
}
~~~

Keep <code>.env</code> in the project directory so the server can load it when started with <code>--directory</code>.

### Codex and other stdio clients

Use the same command in the client's MCP server configuration:

~~~text
uv --directory /absolute/path/to/myanimelist-mcp run --locked main.py
~~~

MCP clients can use different configuration wrappers, but discovery, schemas, and tool calls use the same MCP protocol.

### Smithery

The repository includes a stdio <code>smithery.yaml</code> manifest. The manifest can be published under the project's own Smithery namespace when that namespace is available. No upstream Smithery namespace is assumed by this repository.

## Docker

Build the image:

~~~bash
docker build -t myanimelist-mcp .
~~~

Run it as an MCP stdio server:

~~~bash
docker run --rm -i --env-file .env myanimelist-mcp
~~~

The image installs dependencies with <code>uv sync --locked</code> and does not include <code>.env</code>, tests, Git metadata, or local caches.

## Configuration

| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| <code>MAL_CLIENT_ID</code> | Yes | — | MyAnimeList API client ID. |
| <code>MAL_CLIENT_SECRET</code> | OAuth | — | MyAnimeList OAuth client secret. |
| <code>MAL_REFRESH_TOKEN</code> | No | — | Refresh token for headless authenticated deployments. |
| <code>MAL_API_URL</code> | No | <code>https://api.myanimelist.net/v2</code> | MAL API base URL. |
| <code>MAL_OPEN_BROWSER</code> | No | <code>true</code> | Open the browser for interactive OAuth. |
| <code>MAL_CALLBACK_HOST</code> | No | <code>127.0.0.1</code> | Loopback host for the OAuth callback. |
| <code>MAL_CALLBACK_PORT</code> | No | <code>8080</code> | Local OAuth callback port. |
| <code>MAL_CALLBACK_TIMEOUT</code> | No | <code>300</code> | OAuth callback timeout in seconds. |

> [!IMPORTANT]
> Keep <code>.env</code> private. Access tokens and refresh tokens are held in memory only, but the values in <code>.env</code> still grant access to your MAL application or account.

### Headless OAuth

For a deployment without a browser, set a valid refresh token and disable interactive browser opening:

~~~dotenv
MAL_REFRESH_TOKEN=your_refresh_token
MAL_OPEN_BROWSER=false
~~~

Refresh tokens are never written back to disk by this server.

## Available tools

### Anime

| Tool | Auth | Purpose |
| --- | --- | --- |
| <code>get_anime</code> | Public | Search anime by query. |
| <code>get_anime_details</code> | Public | Fetch details for an anime ID. |
| <code>get_anime_ranking</code> | Public | Fetch anime rankings. |
| <code>get_seasonal_anime</code> | Public | Fetch anime for a season and year. |
| <code>get_anime_list</code> | Public | Fetch a user's public anime list. |
| <code>get_suggested_anime</code> | OAuth | Fetch suggestions for the authenticated user. |
| <code>update_myanimelist</code> | OAuth | Update an anime list entry. |
| <code>delete_myanimelist_item</code> | OAuth | Delete an anime list entry. |

### Manga

| Tool | Auth | Purpose |
| --- | --- | --- |
| <code>get_manga</code> | Public | Search manga by query. |
| <code>get_manga_details</code> | Public | Fetch details for a manga ID. |
| <code>get_manga_ranking</code> | Public | Fetch manga rankings. |
| <code>get_manga_list</code> | Public | Fetch a user's public manga list. |
| <code>update_mymangalist</code> | OAuth | Update a manga list entry. |
| <code>delete_mymangalist_item</code> | OAuth | Delete a manga list entry. |

### User

| Tool | Auth | Purpose |
| --- | --- | --- |
| <code>get_user_profile</code> | OAuth | Fetch the authenticated user's profile. |

## Development and testing

Install all locked dependencies, including the development group:

~~~bash
uv sync --locked
~~~

Run linting and tests:

~~~bash
uv run --locked ruff check .
uv run --locked pytest -q
~~~

The default suite uses mocked HTTP responses, MCP in-memory tests, OAuth callback tests, and stdio subprocess tests. It does not mutate a real MAL account.

## Troubleshooting

### <code>MAL_CLIENT_ID is not configured</code>

Set <code>MAL_CLIENT_ID</code> in <code>.env</code> or in the MCP client's process environment, then restart the client.

### OAuth callback port conflict

Stop the process using port 8080, or choose another loopback port and register the matching redirect URL in MAL:

~~~dotenv
MAL_CALLBACK_PORT=18080
~~~

### OAuth does not open a browser

Use <code>MAL_OPEN_BROWSER=true</code> for interactive authorization. For headless use, provide <code>MAL_REFRESH_TOKEN</code> and set <code>MAL_OPEN_BROWSER=false</code>.

### MCP client reports malformed output

Start the server with the stdio command above. Do not add application prints to stdout; stdout must contain only MCP protocol messages.

### Authenticated tool returns an OAuth error

Check the client ID, client secret, refresh token, redirect URL, and callback port. If the refresh token is expired or revoked, run the interactive flow again.

## Resources

- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [MCP documentation](https://modelcontextprotocol.io/)
- [MyAnimeList authorization reference](https://myanimelist.net/apiconfig/references/authorization)
- [MyAnimeList API v2 reference](https://myanimelist.net/apiconfig/references/api/v2)
- [MyAnimeList API Config](https://myanimelist.net/apiconfig)

Project policies and attribution are documented in [CONTRIBUTING.md](CONTRIBUTING.md), [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), [SECURITY.md](SECURITY.md), and [NOTICE.md](NOTICE.md).

TDQS

A3.5/5.0

Scored across 15 tools

Disambiguation5/5

Each tool has a distinct purpose: search vs details vs rankings vs seasonal vs user lists vs suggestions, and clear update/delete operations for user lists. No two tools appear to do the same thing.

Naming Consistency4/5

Most tools follow a 'get_<resource>_<modifier>' pattern, but a few deviate (e.g., get_seasonal_anime, get_suggested_anime) and the delete/update tools use 'myanimelist'/'mymangalist' as one word, which is inconsistent with the underscore style elsewhere. Still, the verb-noun convention is consistent and predictable.

Tool Count5/5

15 tools is appropriate for a server covering both anime and manga, including search, details, rankings, seasonal, user lists, suggestions, profile, and list management. Each tool serves a clear purpose without excessive overlap.

Completeness4/5

The set covers the main workflows: searching, retrieving details, rankings, seasonal anime, user lists, suggestions, profile, and updating/deleting user list entries. The only notable gap is the lack of an explicit 'add to list' operation, though update may implicitly cover it.

Maintenance

ActivitySlowing
ResponsivenessNo issues