# Anki MCP Server
[](https://github.com/ankimcp/anki-mcp-server/actions/workflows/test.yml)
[](https://www.npmjs.com/package/@ankimcp/anki-mcp-server)
**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 `
` 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
- `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)
#### 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 to listen on (HTTP mode, default: 3000)
-h, --host Host to bind to (HTTP mode, default: 127.0.0.1)
-a, --anki-connect 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": "ยฟCรณmo estรกs?",
"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).
## 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",
"/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": ["/**"],
"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.19.0` - Active beta development. Recent features include 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.
## 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.