# 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)
Anki + MCP Integration

Seamlessly integrate Anki with AI assistants through the Model Context Protocol

**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.