Skip to main content
Glama
54334-bit
by 54334-bit
README.md
# Anki MCP Server

[![Tests](https://github.com/ankimcp/anki-mcp-server/actions/workflows/test.yml/badge.svg)](https://github.com/ankimcp/anki-mcp-server/actions/workflows/test.yml)
[![npm version](https://badge.fury.io/js/@ankimcp%2Fanki-mcp-server.svg)](https://www.npmjs.com/package/@ankimcp/anki-mcp-server)

<div align="center">
  <img src="./docs/images/ankimcp.png" alt="Anki + MCP Integration" width="600" />

  <p><strong>Seamlessly integrate <a href="https://apps.ankiweb.net">Anki</a> with AI assistants through the <a href="https://modelcontextprotocol.io">Model Context Protocol</a></strong></p>
</div>

**Beta** - This project is in active development. APIs and features may change.

A Model Context Protocol (MCP) server that enables AI assistants to interact with Anki, the spaced repetition flashcard application.

Transform your Anki experience with natural language interaction - like having a private tutor. The AI assistant doesn't just present questions and answers; it can explain concepts, make the learning process more engaging and human-like, provide context, and adapt to your learning style. It can create and edit notes on the fly, turning your study sessions into dynamic conversations. More features coming soon!

## Examples and Tutorials

For comprehensive guides, real-world examples, and step-by-step tutorials on using this MCP server with Claude Desktop, visit:

**[ankimcp.ai](https://ankimcp.ai)** - Complete documentation with practical examples and use cases

See [`docs/`](./docs/README.md) for supplementary documentation, including the [reviewer setup guide](./docs/reviewer-setup.md) and the sample Anki deck.

## Example Use Cases

Three representative prompts showing the tool flows this server enables:

1. **"Help me review my Spanish deck."** — The assistant syncs with AnkiWeb (`sync`), fetches due cards (`get_due_cards` with deck filter), presents each card (`present_card`), and records your rating (`rate_card`). Natural study conversation with explanations tailored to you.

2. **"Create 10 Arabic vocab cards with RTL styling."** — The assistant lists note types (`modelNames`), creates a custom RTL model if needed (`createModel` + `updateModelStyling` for right-to-left CSS), then batch-creates the cards (`addNotes`).

3. **"Import this image from my Downloads folder into the front of the selected note."** — The assistant uploads the local file (`storeMediaFile` with a file path), reads the currently-selected note from the browser (`guiSelectedNotes` + `notesInfo`), and updates the front field with an `<img>` tag (`updateNoteFields`).

## Available Tools

The server exposes **42 MCP tools** — 31 essential tools for everyday Anki operations and 11 GUI tools that drive the Anki desktop interface for note editing/creation workflows.

### Essential Tools

#### Review & Study
- `sync` - Sync with AnkiWeb to pull latest data and push changes
- `get_due_cards` - Get cards that are due for review, optionally filtered by deck
- `get_cards` - Get cards with flexible filtering by state (due, new, learning, suspended, buried) and deck
- `present_card` - Show a card for review with its question/front side
- `rate_card` - Rate card performance (Again, Hard, Good, Easy) and schedule the next review

#### Deck Management
- `listDecks` - List all decks, optionally with per-deck card-count statistics
- `deckStats` - Get comprehensive statistics for a single deck (counts, ease/interval distributions)
- `createDeck` - Create a new empty deck (supports `Parent::Child`, max 2 levels)
- `changeDeck` - Move cards to a different deck (created if it doesn't exist)

#### Note Management
- `addNote` - Create a single note with specified fields and tags
- `addNotes` - Batch-create up to 100 notes sharing a deck and model (partial success supported)
- `findNotes` - Search for notes using Anki query syntax (`deck:`, `tag:`, `is:due`, etc.)
- `notesInfo` - Get detailed information about notes (fields, tags, CSS styling)
- `updateNoteFields` - Update existing note fields (CSS-aware, supports HTML content)
- `deleteNotes` - Delete notes and all associated cards (destructive, requires confirmation)

#### Tag Management
- `getTags` - Get all tags in the collection (use first to avoid duplication)
- `addTags` - Add space-separated tags to specified notes
- `removeTags` - Remove space-separated tags from specified notes
- `replaceTags` - Rename a tag across specified notes
- `clearUnusedTags` - Remove orphaned tags not used by any notes (destructive)

#### Media Management
- `getMediaFilesNames` - List media files in `collection.media`, optionally filtered by pattern
- `retrieveMediaFile` - Download a media file as base64 content
- `storeMediaFile` - Upload media from base64 data, an absolute file path, or a URL
- `deleteMediaFile` - Remove a media file from `collection.media` (destructive)

**💡 Best Practice for Images:**
- ✅ **Use file paths** (e.g., `/Users/you/image.png`) - Fast and efficient
- ✅ **Use URLs** (e.g., `https://example.com/image.jpg`) - Direct download
- ❌ **Avoid base64** - Extremely slow and token-inefficient

Just tell Claude where the image is, and it will handle the upload automatically using the most efficient method.

#### Model/Template Management
- `modelNames` - List all available note types/models
- `modelFieldNames` - Get field names for a specific note type
- `modelStyling` - Get CSS styling information for a note type
- `modelTemplates` - Get the card templates (Front and Back HTML) for a note type
- `createModel` - Create a new note type with custom fields, card templates, and CSS (e.g., RTL models)
- `updateModelStyling` - Update the CSS styling for an existing note type (applies to all its cards)
- `updateModelTemplates` - Update the card templates (Front and Back HTML) for an existing note type (applies to all its cards)
- `addModelField` - Add a new field to an existing note type (appended at the end or inserted at a specific position)
- `removeModelField` - Remove a field from an existing note type (deletes its content from all notes; requires explicit confirmation)
- `renameModelField` - Rename a field in an existing note type (card templates referencing the old name must be updated separately)
- `repositionModelField` - Change the position of a field within an existing note type

#### Statistics
- `collection_stats` - Aggregated statistics across all decks with per-deck breakdown
- `review_stats` - Review history analysis (temporal patterns, retention metrics, study streaks)

### GUI Tools

Tools that drive the Anki desktop interface. Intended for note editing/creation and deck-management workflows, **not** for review sessions.

- `guiBrowse` - Open the Card Browser and search for cards
- `guiSelectCard` - Select a specific card in the Card Browser
- `guiSelectedNotes` - Get IDs of notes currently selected in the Card Browser
- `guiAddCards` - Open the Add Cards dialog with preset note details
- `guiEditNote` - Open the note editor for a specific note
- `guiDeckOverview` - Open the Deck Overview dialog for a specific deck
- `guiDeckBrowser` - Open the Deck Browser dialog
- `guiCurrentCard` - Get info about the current card in review mode
- `guiShowQuestion` - Show the question side of the current card
- `guiShowAnswer` - Show the answer side of the current card
- `guiUndo` - Undo the last action in Anki

## Prerequisites

- [Anki](https://apps.ankiweb.net/) with [AnkiConnect](https://github.com/FooSoft/anki-connect) plugin installed
- Node.js 22.12.0+

## Installation

There are a few ways to get the server onto your machine. Once it's installed, head to [Connecting an AI Client](#connecting-an-ai-client) to wire it up to your AI assistant — locally or remotely.

### npm (global or npx)

The general-purpose way to install the server, suitable for any MCP client that launches it directly.

Install it globally for clients that run the `ankimcp` command:

```bash
npm install -g @ankimcp/anki-mcp-server
```

Or run it on demand with no install required:

```bash
npx @ankimcp/anki-mcp-server
```

### MCPB Bundle (Recommended for Claude Desktop)

The easiest way to install this MCP server for Claude Desktop:

1. Download the latest `.mcpb` bundle from the [Releases](https://github.com/ankimcp/anki-mcp-server/releases) page
2. In Claude Desktop, install the extension:
    - **Method 1**: Go to Settings → Extensions, then drag and drop the `.mcpb` file
    - **Method 2**: Go to Settings → Developer → Extensions → Install Extension, then select the `.mcpb` file
3. Configure AnkiConnect URL if needed (defaults to `http://localhost:8765`)
4. Restart Claude Desktop

That's it! The bundle includes everything needed to run the server locally.

> **For Anthropic MCP Directory reviewers:** a zero-to-integration walkthrough with a pre-populated sample deck lives in [`docs/reviewer-setup.md`](./docs/reviewer-setup.md).

### Install from Source (for development)

For development or advanced usage:

```bash
npm install
npm run build
```

## Connecting an AI Client

There are two ways an AI assistant can reach this server, depending on where the assistant runs:

- **[Local](#local)** — the server runs on the same machine as the AI client (Claude Desktop, Cursor, Cline, Zed, or a local browser session). Use **STDIO** for desktop MCP clients, **HTTP** for local web-based tools.
- **[Remote](#remote)** — a hosted/remote AI (e.g. ChatGPT or Claude.ai in the cloud) needs to reach the Anki running on your local machine. Use the managed **Tunnel** (✅ recommended — authenticated) or, as a lighter-weight unauthenticated alternative, **ngrok**.

### Local

The server runs on the same computer as your AI client and talks to AnkiConnect on `localhost`.

#### STDIO (primary local integration)

STDIO is the standard transport for local desktop MCP clients — **Claude Desktop**, **Cursor IDE**, **Cline**, **Zed Editor**, and others. The client launches the server as a subprocess and communicates over standard input/output.

**Supported Clients:**
- [Claude Desktop](https://claude.ai/download)
- [Cursor IDE](https://www.cursor.com/) - AI-powered code editor
- [Cline](https://github.com/cline/cline) - VS Code extension for AI assistance
- [Zed Editor](https://zed.dev/) - Fast, modern code editor
- Other MCP clients that support STDIO transport

For Claude Desktop, the [MCPB bundle](#mcpb-bundle-recommended-for-claude-desktop) is the easiest path. For other clients, configure the npm package with the `--stdio` flag.

**Configuration - Choose one method:**

**Method 1: Using npx (recommended - no installation needed)**

```json
{
  "mcpServers": {
    "anki-mcp": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio"],
      "env": {
        "ANKI_CONNECT_URL": "http://localhost:8765"
      }
    }
  }
}
```

**Method 2: Using global installation**

First, install globally:
```bash
npm install -g @ankimcp/anki-mcp-server
```

Then configure:
```json
{
  "mcpServers": {
    "anki-mcp": {
      "command": "ankimcp",
      "args": ["--stdio"],
      "env": {
        "ANKI_CONNECT_URL": "http://localhost:8765"
      }
    }
  }
}
```

**Configuration file locations:**
- **Cursor IDE**: `~/.cursor/mcp.json` (macOS/Linux) or `%USERPROFILE%\.cursor\mcp.json` (Windows)
- **Cline**: Accessible via settings UI in VS Code
- **Zed Editor**: Install as MCP extension through extension marketplace

For client-specific features and troubleshooting, consult your MCP client's documentation. See also [Connect to Claude Desktop](#connect-to-claude-desktop-local-mode) for a config that points directly at a built `dist/main-stdio.js`.

#### HTTP (local web-based AI)

HTTP mode runs the server as a local web server speaking the MCP Streamable HTTP protocol. It's the transport a web-based AI tool talks to when pointed at your machine, and it's also what the [Remote](#remote) options expose to the outside world. On its own, HTTP mode binds to `localhost` only.

**Setup - Choose one method:**

**Method 1: Using npx (recommended - no installation needed)**

```bash
# Quick start
npx @ankimcp/anki-mcp-server

# With custom options
npx @ankimcp/anki-mcp-server --port 8080 --host 0.0.0.0
npx @ankimcp/anki-mcp-server --anki-connect http://localhost:8765
```

**Method 2: Using global installation**

```bash
# Install once
npm install -g @ankimcp/anki-mcp-server

# Run the server
ankimcp

# With custom options
ankimcp --port 8080 --host 0.0.0.0
ankimcp --anki-connect http://localhost:8765
```

**Method 3: Install from source (for development)**

```bash
npm install
npm run build
npm run start:prod:http
```

To make a local HTTP server reachable by a cloud-hosted AI, use one of the [Remote](#remote) options below.

### Remote

A hosted/remote AI (such as ChatGPT or Claude.ai running in the cloud) can't reach `localhost` directly. These options expose your **local** Anki to the internet so a remote assistant can talk to it.

#### Tunnel (✅ Recommended)

> **Recommended remote path — authenticated & secure.** Unlike a raw public port, tunnel mode requires you to log in (OAuth 2.0 device flow), so the endpoint isn't open to anyone who guesses the URL.

Tunnel mode lets web-based AI assistants reach your **local** Anki without running your own tunnel. The server connects out to the managed AnkiMCP tunnel service (`wss://tunnel.ankimcp.ai`) over a WebSocket and is assigned a public URL. Authentication is built in — no ngrok account or separate tunnel process required, and you log in once.

**Log in (OAuth device flow):**

Tunnel mode uses the OAuth 2.0 Device Authorization Grant. Logging in opens your browser automatically to an approval page with the code already embedded in the URL — nothing to type, just approve. (If the browser can't open, the terminal prints a verification URL and code to enter manually as a fallback.) On success, credentials are saved to `~/.ankimcp/credentials.json` (file permissions `0600`).

```bash
# Pre-authenticate (optional — --tunnel will trigger this automatically if needed)
ankimcp --login
npx @ankimcp/anki-mcp-server --login

# Clear saved credentials
ankimcp --logout
```

**Start the tunnel:**

```bash
# Connect to the managed tunnel service (wss://tunnel.ankimcp.ai)
ankimcp --tunnel
npx @ankimcp/anki-mcp-server --tunnel

# Override the tunnel server URL (must be ws:// or wss://) — e.g. for self-hosting
ankimcp --tunnel wss://my-tunnel.example.com
```

If no credentials exist, `--tunnel` automatically starts the login flow first, then continues to the tunnel. This auto-login requires an interactive terminal — when stdout is not a TTY (systemd, headless Docker, CI), the server fast-fails and asks you to run `ankimcp --login` first. Once connected, the public tunnel URL is printed; press Ctrl+C to disconnect. Share that URL with your AI assistant.

**Tunnel-mode environment variables:**

| Variable | Description | Default |
|----------|-------------|---------|
| `TUNNEL_SERVER_URL` | Tunnel server WebSocket URL (the `--tunnel`/`--login` flag value overrides this) | `wss://tunnel.ankimcp.ai` |
| `TUNNEL_AUTH_CLIENT_ID` | OAuth client ID for the device flow. Advanced — only needed when pointing at a self-hosted tunnel/auth service. | (built-in) |

The device-flow auth endpoints (`/auth/device`, `/auth/token`) are derived from `TUNNEL_SERVER_URL`, so pointing `--tunnel` (or `TUNNEL_SERVER_URL`) at a different host also moves authentication to that host.

**How it works:** Tunnel mode runs the MCP server in-process behind an in-memory transport (`McpModule` is started with no built-in transport). `TunnelMcpService` connects that in-memory transport to the MCP server, and `TunnelClient` bridges it to the remote tunnel service over a WebSocket — relaying MCP requests in and responses out. AnkiConnect is still only ever reached on your local machine.

#### ngrok (unauthenticated alternative)

If you'd rather expose [local HTTP mode](#http-local-web-based-ai) publicly without an account on the managed tunnel, the built-in `--ngrok` flag launches an [ngrok](https://ngrok.com/) subprocess (`src/services/ngrok.service.ts`) and prints the public URL in the startup banner:

```bash
# One-time ngrok setup, then:
ankimcp --ngrok
```

This route is **unauthenticated** — anyone with the URL can reach your Anki, so it's less secure than [Tunnel](#tunnel--recommended). Prefer Tunnel unless you have a specific reason to manage your own ngrok endpoint. (Requires a global ngrok install and authtoken; the manual two-terminal `ngrok http 3000` setup works too.)

### CLI Options (all modes)

```bash
ankimcp [options]

Options:
  --stdio                        Run in STDIO mode (for MCP clients)
  --tunnel [url]                 Connect via the managed tunnel (authenticated)
  --login                        Authenticate for tunnel mode (OAuth device flow)
  --logout                       Clear saved tunnel credentials
  -p, --port <port>              Port to listen on (HTTP mode, default: 3000)
  -h, --host <host>              Host to bind to (HTTP mode, default: 127.0.0.1)
  -a, --anki-connect <url>       AnkiConnect URL (default: http://localhost:8765)
  --ngrok                        Start ngrok tunnel (requires global ngrok installation)
  --read-only                    Run in read-only mode (blocks all write operations)
  --help                         Show help message

Usage with npx (no installation needed):
  npx @ankimcp/anki-mcp-server                        # HTTP mode
  npx @ankimcp/anki-mcp-server --port 8080            # Custom port
  npx @ankimcp/anki-mcp-server --stdio                # STDIO mode
  npx @ankimcp/anki-mcp-server --tunnel               # Managed tunnel mode
  npx @ankimcp/anki-mcp-server --ngrok                # HTTP mode with ngrok tunnel
  npx @ankimcp/anki-mcp-server --read-only            # Read-only mode

Usage with global installation:
  npm install -g @ankimcp/anki-mcp-server             # Install once
  ankimcp                                             # HTTP mode
  ankimcp --port 8080                                 # Custom port
  ankimcp --stdio                                     # STDIO mode
  ankimcp --tunnel                                    # Managed tunnel mode
  ankimcp --ngrok                                     # HTTP mode with ngrok tunnel
  ankimcp --read-only                                 # Read-only mode
```

### Read-Only Mode (all modes)

The `--read-only` flag prevents any modifications to your Anki collection. When enabled:
- All read operations work normally (browsing decks, viewing cards, searching notes)
- Review operations are allowed (sync, answerCards, suspend/unsuspend)
- Content modifications are blocked (addNote, deleteNotes, createDeck, updateNoteFields, etc.)
- Useful for safely exploring Anki data without risk of accidental changes

```bash
# HTTP mode with read-only
ankimcp --read-only

# STDIO mode with read-only
ankimcp --stdio --read-only

# Can combine with other flags
ankimcp --ngrok --read-only
```

You can also enable read-only mode via environment variable:
```bash
READ_ONLY=true ankimcp
```

Or in MCP client configuration:
```json
{
  "mcpServers": {
    "anki-mcp": {
      "command": "npx",
      "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio", "--read-only"],
      "env": {
        "ANKI_CONNECT_URL": "http://localhost:8765"
      }
    }
  }
}
```

## Connect to Claude Desktop (Local Mode)

You can configure the server in Claude Desktop by either:
- Going to: Settings → Developer → Edit Config
- Or manually editing the config file

### Configuration

Add the following to your Claude Desktop config:

```json
{
  "mcpServers": {
    "anki-mcp": {
      "command": "node",
      "args": ["/path/to/anki-mcp-server/dist/main-stdio.js"],
      "env": {
        "ANKI_CONNECT_URL": "http://localhost:8765"
      }
    }
  }
}
```

Replace `/path/to/anki-mcp-server` with your actual project path.

### Config File Locations

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux**: `~/.config/Claude/claude_desktop_config.json`

For more details, see the [official MCP documentation](https://modelcontextprotocol.io/docs/develop/connect-local-servers).

## Environment Variables (Optional)

| Variable | Description | Default |
|----------|-------------|---------|
| `ANKI_CONNECT_URL` | AnkiConnect URL | `http://localhost:8765` |
| `ANKI_CONNECT_API_VERSION` | API version | `6` |
| `ANKI_CONNECT_API_KEY` | API key if configured in AnkiConnect | - |
| `ANKI_CONNECT_TIMEOUT` | Request timeout in ms | `5000` |
| `READ_ONLY` | Enable read-only mode (`true` or `1`) | `false` |
| `TUNNEL_SERVER_URL` | Tunnel server WebSocket URL (tunnel mode only) | `wss://tunnel.ankimcp.ai` |
| `MEDIA_ALLOWED_TYPES` | Extra MIME types to allow for file path imports (comma-separated, e.g., `application/pdf`) | - |
| `MEDIA_IMPORT_DIR` | Restrict file path imports to this directory | - |
| `MEDIA_ALLOWED_HOSTS` | Allow specific private network hosts for URL imports (comma-separated, e.g., `192.168.1.50,my-nas`) | - |

## Usage Examples

### Searching and Updating Notes

```
# Search for notes in a specific deck
findNotes(query: "deck:Spanish")

# Get detailed information about notes
notesInfo(notes: [1234567890, 1234567891])

# Update a note's fields (HTML content supported)
updateNoteFields(note: {
  id: 1234567890,
  fields: {
    "Front": "<b>¿Cómo estás?</b>",
    "Back": "How are you?"
  }
})

# Delete notes (requires confirmation)
deleteNotes(notes: [1234567890], confirmDeletion: true)
```

### Anki Query Syntax Examples

The `findNotes` tool supports Anki's powerful query syntax:

- `"deck:DeckName"` - All notes in a specific deck
- `"tag:important"` - Notes with the "important" tag
- `"is:due"` - Cards that are due for review
- `"is:new"` - New cards that haven't been studied
- `"added:7"` - Notes added in the last 7 days
- `"front:hello"` - Notes with "hello" in the front field
- `"flag:1"` - Notes with red flag
- `"prop:due<=2"` - Cards due within 2 days
- `"deck:Spanish tag:verb"` - Spanish deck notes with verb tag (AND)
- `"deck:Spanish OR deck:French"` - Notes from either deck

### Important Notes

#### CSS and HTML Handling
- The `notesInfo` tool returns CSS styling information for proper rendering awareness
- The `updateNoteFields` tool supports HTML content in fields and preserves CSS styling
- Each note model has its own CSS styling - use `modelStyling` to get model-specific CSS

#### Update Warning
⚠️ **IMPORTANT**: When using `updateNoteFields`, do NOT view the note in Anki's browser while updating, or the fields will not update properly. Close the browser or switch to a different note before updating. See [Known Issues](#known-issues) for more details.

#### Deletion Safety
The `deleteNotes` tool requires explicit confirmation (`confirmDeletion: true`) to prevent accidental deletions. Deleting a note removes ALL associated cards permanently.

## Security

### Media File Path and URL Validation

The media tools (`storeMediaFile`, `retrieveMediaFile`, `deleteMediaFile`) and `updateNoteFields` audio/picture fields include security validation to prevent misuse via prompt injection:

- **File path imports** are restricted to media file types only (images, audio, video). Non-media files (e.g., SSH keys, credentials, shell configs) are rejected based on MIME type. Configure `MEDIA_ALLOWED_TYPES` to allow additional file types, or `MEDIA_IMPORT_DIR` to restrict imports to a specific directory.
- **URL imports** are validated against SSRF attacks. Requests to private networks (10.x, 172.16.x, 192.168.x), loopback (127.x), link-local (169.254.x), and non-HTTP(S) schemes are blocked. Configure `MEDIA_ALLOWED_HOSTS` to allow specific private network hosts.
- **Filenames** are sanitized to prevent path traversal (e.g., `../../` sequences are stripped).

These protections apply to `storeMediaFile`, `retrieveMediaFile`, `deleteMediaFile`, and `updateNoteFields` audio/picture fields.

> Path traversal vulnerability reported by [Hideaki Takahashi](https://github.com/Koukyosyumei).

## Privacy Policy

This MCP server runs locally on your machine and collects no telemetry, analytics, or usage data.

Full policy: **[https://ankimcp.ai/privacy/](https://ankimcp.ai/privacy/)**

- **Data collection**: The server collects nothing. It proxies requests between your AI assistant and your local AnkiConnect plugin.
- **Usage / storage**: No server-side storage. All flashcard data stays in your Anki installation on your own device.
- **Third-party sharing**: None. The server only talks to the AnkiConnect URL you configure (default: localhost). If you enable Anki's built-in AnkiWeb sync, that happens between your Anki install and AnkiWeb directly — outside this server's scope.
- **Retention**: Not applicable — no data is retained server-side.
- **Contact**: support@ankimcp.ai

## Known Issues

For a comprehensive list of known issues and limitations, please visit our documentation:

**[Known Issues Documentation](https://ankimcp.ai/docs/known-issues/)**

### Critical Limitations

#### Note Updates Fail When Viewed in Browser
⚠️ **IMPORTANT**: When updating notes using `updateNoteFields`, the update will silently fail if the note is currently being viewed in Anki's browser window. This is an upstream AnkiConnect limitation.

**Workaround**: Always close the browser or navigate to a different note before updating.

For more details and other known issues, see the [full documentation](https://ankimcp.ai/docs/known-issues/).

## Troubleshooting

### ERR_REQUIRE_ESM Error

If you see an error like:
```
Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
```

This means your Node.js version is not supported. The server requires **Node.js 22.12.0+**.

> **Note:** The minimum supported runtime is Node.js 22.12.0. Node.js 20 (Iron) reached end-of-life on 2026-04-30 and is no longer supported.

**Check your version:**
```bash
node --version
```

**Solution:** Update Node.js to version 22.12.0+. You can download it from [nodejs.org](https://nodejs.org/) or use a version manager like [nvm](https://github.com/nvm-sh/nvm).

### `'node' is not recognized` (Windows)

If `npm run start:prod:stdio` or any `npm run` script fails with:
```
'node' is not recognized as an internal or external command
```

Node.js is installed but its directory is **not in the system PATH**.

**Solutions (pick one):**

1. **Add Node.js to PATH** (recommended) — add your Node.js install directory (e.g. `D:\...\node-v22.x-win-x64`) to the `PATH` environment variable, then restart your terminal.

2. **Use the launcher script** (no PATH needed) — run `scripts\start-stdio.cmd` from the project root. It auto-detects `node.exe` in common locations. You can also set `ANKIMCP_NODE_EXE` to point directly at your `node.exe`.

3. **Use the full path in your MCP client config** — point the `command` field at the absolute path of `node.exe` (see `trae-mcp-config.json` for an example).

### Path with spaces breaks the server

If you see `Cannot find module '...mcp'` (path truncated at a space), your project or Node.js path contains a space (e.g. `C:\My Projects\anki-mcp-server`). MCP clients that don't properly quote args will truncate at the space.

**Solutions:**
- Move the project to a path without spaces, **or**
- Ensure your MCP client passes `args` as a proper JSON array (each element is one argv entry). The included `trae-mcp-config.json` is correct.

### AnkiConnect not reachable

If the server starts but tool calls fail with `fetch failed` or `ECONNREFUSED`:

1. **Start the Anki desktop app** (not just the headless collection).
2. **Install the AnkiConnect add-on** — code `2055492159` (Tools → Add-ons → Get Add-ons).
3. **Verify port 8765** is open: `curl http://localhost:8765 -X POST -d '{"action":"version","version":6}'`

### Running the health check

A bundled diagnostic script checks Node version, build output, dependencies, AnkiConnect, and the MCP handshake in one pass:

```bash
node scripts/health-check.mjs
```

All five checks should pass. If any fail, the script prints a targeted hint.

### Trae MCP configuration

This repo includes [`trae-mcp-config.json`](./trae-mcp-config.json) as a ready-to-use config for the Trae IDE. To use it:

1. Open Trae → Settings → MCP Servers.
2. Import or paste the contents of `trae-mcp-config.json`.
3. Adjust the `command` path to point at **your** `node.exe` if Node.js is not in PATH.
4. Ensure Anki desktop is running with the AnkiConnect add-on.

## Development

### Transport Modes

This server supports three MCP transport modes via **separate entry points**:

#### STDIO Mode (Default)
- For local MCP clients like Claude Desktop
- Uses standard input/output for communication
- **Entry point**: `dist/main-stdio.js`
- **Run**: `npm run start:prod:stdio` or `node dist/main-stdio.js`
- **MCPB bundle**: Uses STDIO mode

#### HTTP Mode (Streamable HTTP)
- For remote MCP clients and web-based integrations
- Uses MCP Streamable HTTP protocol
- **Entry point**: `dist/main-http.js`
- **Run**: `npm run start:prod:http` or `node dist/main-http.js`
- **Default port**: 3000 (configurable via `PORT` env var)
- **Default host**: `127.0.0.1` (configurable via `HOST` env var)
- **MCP endpoint**: `http://127.0.0.1:3000/` (root path)

#### Tunnel Mode (Managed WebSocket Tunnel)
- For web-based AI assistants via the managed AnkiMCP tunnel service, with built-in authentication
- The MCP server runs in-process behind an in-memory transport; `TunnelMcpService` wires it to the MCP server and `TunnelClient` bridges it to the tunnel service over a WebSocket
- **Entry point**: `dist/main-tunnel.js`
- **Run**: `node dist/main-tunnel.js --tunnel` (or `ankimcp --tunnel`)
- **Auth**: `ankimcp --login` / `ankimcp --logout`; credentials stored at `~/.ankimcp/credentials.json` (`0600`)
- **Dev**: `npm run start:dev:tunnel` (watch mode, runs `--tunnel --debug`)

#### Building

```bash
npm run build  # Builds once, creates dist/ with all three entry points
```

`main-stdio.js`, `main-http.js`, and `main-tunnel.js` are all built into the same `dist/` directory. Choose which to run based on your needs.

#### HTTP Mode Configuration

**Environment Variables:**
- `PORT` - HTTP server port (default: 3000)
- `HOST` - Bind address (default: 127.0.0.1 for localhost-only)
- `ALLOWED_ORIGINS` - Comma-separated list of allowed origins for CORS (default: localhost)
- `LOG_LEVEL` - Logging level (default: info)

**Security:**
- Origin header validation (prevents DNS rebinding attacks)
- Binds to localhost (127.0.0.1) by default
- No authentication in current version (OAuth support planned)

**Example: Running Modes**
```bash
# Development - STDIO mode (watch mode with auto-rebuild)
npm run start:dev:stdio

# Development - HTTP mode (watch mode with auto-rebuild)
npm run start:dev:http

# Production - STDIO mode
npm run start:prod:stdio
# or
node dist/main-stdio.js

# Production - HTTP mode
npm run start:prod:http
# or
PORT=8080 HOST=0.0.0.0 node dist/main-http.js
```

### Building an MCPB Bundle

To create a distributable MCPB bundle:

```bash
npm run mcpb:bundle
```

This command will:
1. Sync version from `package.json` to `manifest.json`
2. Remove old `.mcpb` files
3. Build the TypeScript project
4. Package `dist/` and `node_modules/` into an `.mcpb` file
5. Run `mcpb clean` to remove devDependencies (optimizes bundle from ~47MB to ~10MB)

The output file will be named `anki-mcp-server-X.X.X.mcpb` and can be distributed for one-click installation.

#### What Gets Bundled

The MCPB bundle includes:
- Compiled JavaScript (`dist/` directory - includes all three entry points)
- Production dependencies only (`node_modules/` - devDependencies removed by `mcpb clean`)
- Package metadata (`package.json`)
- Manifest configuration (`manifest.json` - configured to use `main-stdio.js`)
- Icon (`icon.png`)

Source files, tests, and development configs are automatically excluded via `.mcpbignore`.

### Logging in Claude Desktop

When running as an MCPB extension in Claude Desktop, logs are written to:

**Log Location**: `~/Library/Logs/Claude/` (macOS)

The logs are split across multiple files:
- **main.log** - General Claude Desktop application logs
- **mcp-server-Anki MCP Server.log** - MCP protocol messages for this extension
- **mcp.log** - Combined MCP logs from all servers

**Note**: The pino logger output (INFO, ERROR, WARN messages from the server code) goes to stderr and appears in the MCP-specific log files. Claude Desktop determines which log file receives which messages, but generally:
- Application startup and MCP protocol communication → MCP-specific log
- Server internal logging (pino) → Both MCP-specific log and sometimes main.log

To view logs in real-time:
```bash
tail -f ~/Library/Logs/Claude/mcp-server-Anki\ MCP\ Server.log
```

### Debugging the MCP Server

You can debug the MCP server using the MCP Inspector and attaching a debugger from your IDE (WebStorm, VS Code, etc.).

**Note for HTTP Mode:** When testing HTTP mode (Streamable HTTP) with MCP Inspector, use "Connection Type: Via Proxy" to avoid CORS errors.

#### Step 1: Configure Debug Server in MCP Inspector

The `mcp-inspector-config.json` already includes a debug server configuration:

```json
{
  "mcpServers": {
    "stdio-server-debug": {
      "type": "stdio",
      "command": "node",
      "args": ["--inspect-brk=9229", "dist/main-stdio.js"],
      "env": {
        "MCP_SERVER_NAME": "anki-mcp-stdio-debug",
        "MCP_SERVER_VERSION": "1.0.0",
        "LOG_LEVEL": "debug"
      },
      "note": "Anki MCP server with debugging enabled on port 9229"
    }
  }
}
```

#### Step 2: Start the Debug Server

Run the MCP Inspector with the debug server:

```bash
npm run inspector:debug
```

This will start the server with Node.js debugging enabled on port 9229 and pause execution at the first line.

#### Step 3: Attach Debugger from Your IDE

##### WebStorm
1. Go to **Run → Edit Configurations**
2. Add a new **Attach to Node.js/Chrome** configuration
3. Set the port to `9229`
4. Click **Debug** to attach

##### VS Code
1. Open the Debug panel (Ctrl+Shift+D / Cmd+Shift+D)
2. Select **Debug MCP Server (Attach)** configuration
3. Press F5 to attach

#### Step 4: Set Breakpoints and Debug

Once attached, you can:
- Set breakpoints in your TypeScript source files
- Step through code execution
- Inspect variables and call stack
- Use the debug console for evaluating expressions

The debugger will work with source maps, allowing you to debug the original TypeScript code rather than the compiled JavaScript.

### Debugging with Claude Desktop

You can also debug the MCP server while it runs inside Claude Desktop by enabling the Node.js debugger and attaching your IDE.

#### Step 1: Configure Claude Desktop for Debugging

Update your Claude Desktop config to enable debugging:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
**Linux**: `~/.config/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "anki-mcp": {
      "command": "node",
      "args": [
        "--inspect=9229",
        "<path_to_project>/anki-mcp-server/dist/main-stdio.js"
      ],
      "env": {
        "ANKI_CONNECT_URL": "http://localhost:8765"
      }
    }
  }
}
```

**Key change**: Add `--inspect=9229` before the path to `dist/main-stdio.js`

**Debug options**:
- `--inspect=9229` - Start debugger immediately, doesn't block (recommended)
- `--inspect-brk=9229` - Pause execution until debugger attaches (for debugging startup issues)

#### Step 2: Restart Claude Desktop

After saving the config, restart Claude Desktop. The MCP server will now run with debugging enabled on port 9229.

#### Step 3: Attach Debugger from Your IDE

##### WebStorm

1. Go to **Run → Edit Configurations**
2. Click the **+** button and select **Attach to Node.js/Chrome**
3. Configure:
    - **Name**: `Attach to Anki MCP (Claude Desktop)`
    - **Host**: `localhost`
    - **Port**: `9229`
    - **Attach to**: `Node.js < 8` or `Chrome or Node.js > 6.3` (depending on WebStorm version)
4. Click **OK**
5. Click **Debug** (Shift+F9) to attach

##### VS Code

1. Add to `.vscode/launch.json`:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Anki MCP (Claude Desktop)",
      "port": 9229,
      "skipFiles": ["<node_internals>/**"],
      "sourceMaps": true,
      "outFiles": ["${workspaceFolder}/dist/**/*.js"]
    }
  ]
}
```

2. Open the Debug panel (Ctrl+Shift+D / Cmd+Shift+D)
3. Select **Attach to Anki MCP (Claude Desktop)**
4. Press F5 to attach

#### Step 4: Debug in Real-Time

Once attached, you can:
- Set breakpoints in your TypeScript source files (e.g., `src/mcp/primitives/essential/tools/create-model.tool.ts`)
- Use Claude Desktop normally - breakpoints will hit when tools are invoked
- Step through code execution
- Inspect variables and call stack
- Use the debug console

**Example**: Set a breakpoint in `create-model.tool.ts` at line 119, then ask Claude to create a new model. The debugger will pause at your breakpoint!

**Note**: The debugger stays attached as long as Claude Desktop is running. You can detach/reattach anytime without restarting Claude Desktop.

### Build Commands

```bash
npm run build              # Build the project (compile TypeScript to JavaScript)
npm run start:dev:stdio    # STDIO mode with watch (auto-rebuild)
npm run start:dev:http     # HTTP mode with watch (auto-rebuild)
npm run type-check         # Run TypeScript type checking
npm run lint               # Run ESLint
npm run mcpb:bundle        # Sync version, clean, build, and create MCPB bundle
```

### NPM Package Testing (Local)

Test the npm package locally before publishing:

```bash
# 1. Create local package
npm run pack:local         # Builds and creates @ankimcp/anki-mcp-server-*.tgz

# 2. Install globally from local package
npm run install:local      # Installs from ./@ankimcp/anki-mcp-server-*.tgz

# 3. Test the command
ankimcp                    # Runs HTTP server on port 3000

# 4. Uninstall when done testing
npm run uninstall:local    # Removes global installation
```

**How it works:**
- `npm pack` creates a `.tgz` file identical to what npm publish would create
- Installing from `.tgz` simulates what users get from `npm install -g ankimcp`
- This lets you test the full user experience before publishing to npm

### Testing Commands

```bash
npm test              # Run all tests
npm run test:unit     # Run unit tests only
npm run test:tools    # Run tool-specific tests
npm run test:workflows # Run workflow integration tests
npm run test:e2e      # Run end-to-end tests
npm run test:cov      # Run tests with coverage report
npm run test:watch    # Run tests in watch mode
npm run test:debug    # Run tests with debugger
npm run test:ci       # Run tests for CI (silent, with coverage)
```

### Test Coverage

The project maintains 70% minimum coverage thresholds for:
- Branches
- Functions
- Lines
- Statements

Coverage reports are generated in the `coverage/` directory.

## Versioning

This project follows [Semantic Versioning](https://semver.org/) with a pre-1.0 development approach:

- **0.x.x** - Beta/Development versions (current phase)
    - **0.1.x** - Bug fixes and patches
    - **0.2.0+** - New features or minor improvements
    - **Breaking changes** are acceptable in 0.x versions

- **1.0.0** - First stable release
    - Will be released when the API is stable and tested
    - Breaking changes will require major version bumps (2.0.0, etc.)

**Current Status**: `0.20.0` - Active beta development. Recent features include model field management (`addModelField`, `removeModelField`, `renameModelField`, `repositionModelField`), batch note creation (`addNotes`), integrated ngrok tunneling (`--ngrok` flag), media file management, model/template management, and comprehensive deck statistics. APIs may change based on feedback and testing.

### MCPB spec evolution

This project targets Anthropic's MCPB bundle specification, which is still evolving. We track the spec at [https://github.com/modelcontextprotocol/mcpb](https://github.com/modelcontextprotocol/mcpb) and may introduce breaking changes to stay compliant. Breaking changes are permitted under the 0.x.x versioning scheme.

## Fork 来源与本地增强(Fork Origin & Local Enhancements)

> 本节为 fork 仓库特有的补充说明,用以明确上游来源、本仓库相对上游的改动,以及已验证的本地运行环境。

### 1. 上游框架(Upstream Framework)

本仓库是 [`ankimcp/anki-mcp-server`](https://github.com/ankimcp/anki-mcp-server)(作者 Anatoly Tarnavsky,MIT 许可)的派生(fork),上游版本基线为 `0.18.4`。上游项目本身并非从零实现,而是构建于下列开源框架之上:

| 层级 | 框架 / 组件 | 作用 |
|------|-------------|------|
| 应用框架 | [NestJS](https://nestjs.com/) | 提供依赖注入、模块化架构与生命周期管理 |
| MCP 集成层 | [@rekog/mcp-nest](https://github.com/rekogsh/mcp-nest) | 将 MCP 协议接入 NestJS 的工具/资源/提示自动发现机制 |
| MCP 协议 SDK | [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) | MCP 官方 TypeScript SDK,提供传输与协议原语 |
| Anki 通信层 | [AnkiConnect](https://github.com/FooSoft/anki-connect) | Anki 桌面端 HTTP 插件(add-on 代码 `2055492159`),本服务经其 `http://localhost:8765` 与 Anki 交互 |

即:**原框架为 `ankimcp/anki-mcp-server`,本仓库在此之上进行安全加固与工程化增强**。

### 2. 本 fork 的改动(Changes in This Fork)

相较上游 `0.18.4` 基线,本 fork 在 `0.20.1` 版本中引入以下改动(完整记录见 [`CHANGELOG.md`](./CHANGELOG.md)):

- **破坏性操作两步确认**:`deleteNotes`、`deleteMediaFile`、`clearUnusedTags` 等不可逆操作须经 `ConfirmationService` 配合 `confirmAction` 工具显式二次确认后方可执行。
- **HTTP 传输 API Key 鉴权**:新增 `ApiKeyGuard`,支持 `Authorization: Bearer`、`X-API-Key` 及查询参数 `?api_key=` 三种传递方式。
- **审计日志**:所有破坏性操作写入 `~/.anki-mcp-server/audit.log`,便于事后追溯。
- **幂等性支持**:在 note 创建路径引入幂等机制,防止客户端重试导致的重复创建。
- **HTTP 速率限制**:新增速率限制守卫,缓解滥用与暴力调用。
- **缺陷修复**:修正 `app.module.ts` 中配置字段名映射(`url` → `ankiConnectUrl`),该缺陷曾导致 AnkiConnect URL 被解析为 `undefined`。
- **工具链增强**:新增 `scripts/health-check.mjs` 环境诊断脚本与 `scripts/start-stdio.cmd` Windows 启动器(无需将 Node.js 加入 `PATH` 即可运行)。
- **开源治理**:补充 `CONTRIBUTING.md`、`CODE_OF_CONDUCT.md`、`SECURITY.md`、GitHub issue/PR 模板与 `dependabot.yml`,使其符合开源协作规范。
- **配置同步**:`server.json` 版本同步(`0.18.4` → `0.20.1`);`trae-mcp-config.json` 精简为可移植的 Trae IDE 配置模板。

### 3. 环境限制与本地测试声明(Environmental Constraints & Local Test Statement)

本服务存在以下潜在环境限制:

- **运行时**:Node.js ≥ `22.12.0`(Node.js 20 已于 2026-04-30 EOL,不再受支持)。
- **Anki 侧**:须运行 Anki 桌面端并安装 AnkiConnect 插件(add-on 代码 `2055492159`),默认监听 `http://localhost:8765`。
- **路径限制**:项目路径或 Node.js 安装路径若含空格,部分 MCP 客户端可能因参数截断导致启动失败;此时应使用 `trae-mcp-config.json` 中以 JSON 数组形式给出的 `args`,或改用 `scripts/start-stdio.cmd` 启动器。
- **PATH 限制**:若 `node` 不在系统 `PATH`,需在 MCP 客户端配置中将 `command` 指向 `node.exe` 的绝对路径。
- **平台**:`manifest.json` 声明支持 `darwin` / `linux` / `win32`。

**本地测试声明**:本 fork 已在维护者的本地环境通过 `scripts/health-check.mjs` 全部五项检查(Node 版本、构建产物、依赖完整性、AnkiConnect 连通性、MCP 握手),结果如下:

| 检查项 | 结果 |
|--------|------|
| Node.js 版本 | `v22.22.3`(win-x64,满足 ≥ 22.12.0) |
| 构建产物 | `dist/main-stdio.js` 存在 |
| 依赖完整性 | `node_modules/` 已填充 |
| AnkiConnect | `http://localhost:8765` 可达,API `v6` |
| MCP 握手 | 服务端响应正常,注册 56 项工具 |

本地环境配置摘要:

| 项 | 值 |
|---|---|
| 操作系统 | Windows 11 Home China |
| Node.js | `v22.22.3`,路径 `D:\dd\exe origin\nodejs\node-v22.22.3-win-x64\node.exe`(不在 `PATH`,路径含空格) |
| Anki | 桌面端运行中,AnkiConnect 插件已启用 |
| 项目路径 | `D:\dd\projects\project1_cad_mcp_server_and_geminiapi\mcp servers\anki-mcp-server-fork`(路径含空格) |
| 验证命令 | `node scripts/health-check.mjs`(5 passed, 0 failed) |

> 注:因本地 `node` 不在 `PATH` 且路径含空格,实际通过 `node.exe` 绝对路径执行;该情形已被 `scripts/start-stdio.cmd` 启动器与 `trae-mcp-config.json` 模板覆盖。

## Similar Projects

If you're exploring Anki MCP integrations, here are other projects in this space:

### [scorzeth/anki-mcp-server](https://github.com/scorzeth/anki-mcp-server)
- **Status**: Appears to be abandoned (no recent updates)
- Early implementation of Anki MCP integration

### [nailuoGG/anki-mcp-server](https://github.com/nailuoGG/anki-mcp-server)
- **Approach**: Lightweight, single-file implementation
- **Architecture**: Procedural code structure with all tools in one file
- **Good for**: Simple use cases, minimal dependencies

**Why this project differs:**
- **Enterprise-grade architecture**: Built on NestJS with dependency injection
- **Modular design**: Each tool is a separate class with clear separation of concerns
- **Maintainability**: Easy to extend with new features without touching existing code
- **Testing**: Comprehensive test suite with 70% coverage requirement
- **Type safety**: Strict TypeScript with Zod validation
- **Error handling**: Robust error handling with helpful user feedback
- **Production-ready**: Proper logging, progress reporting, and MCPB bundle support
- **Scalability**: Can easily grow from basic tools to complex workflows

**Use case**: If you need a solid foundation for building advanced Anki integrations or plan to extend functionality significantly, this project's architectural approach makes it easier to maintain and scale over time.

## Useful Links

- [Model Context Protocol Documentation](https://modelcontextprotocol.io/docs)
- [AnkiConnect API Documentation](https://git.sr.ht/~foosoft/anki-connect)
- [Claude Desktop Download](https://claude.ai/download)
- [Building Desktop Extensions (Anthropic Blog)](https://www.anthropic.com/engineering/desktop-extensions)
- [MCP Servers Repository](https://github.com/modelcontextprotocol/servers)
- [NestJS Documentation](https://docs.nestjs.com)
- [Anki Official Website](https://apps.ankiweb.net/)

## License & Attribution

This project is licensed under the MIT License — see [LICENSE](LICENSE) for the full text.

Copyright © 2026 Anatoly Tarnavsky.

### Third-Party Attributions

- **Anki®** is a registered trademark of Ankitects Pty Ltd. This project is an unofficial third-party tool and is not affiliated with, endorsed by, or sponsored by Ankitects Pty Ltd. The Anki logo is used under the alternative license for referencing Anki with a link to [https://apps.ankiweb.net](https://apps.ankiweb.net). For the official Anki application, visit [https://apps.ankiweb.net](https://apps.ankiweb.net).

- **Model Context Protocol (MCP)** is an open standard by Anthropic. The MCP logo is from the official [MCP documentation repository](https://github.com/modelcontextprotocol/docs) and is used under the MIT License. For more information about MCP, visit [https://modelcontextprotocol.io](https://modelcontextprotocol.io).

- This is an independent project that bridges Anki and MCP technologies. All trademarks, service marks, trade names, product names, and logos are the property of their respective owners.