Clanki - Claude's Anki Integration

Permet aux assistants IA d'interagir avec les paquets de flashcards Anki via le plugin AnkiConnect.

Documentation

MseeP.ai Security Assessment Badge License: MIT

Clanki - Claude's Anki Integration

An MCP server that enables AI assistants like Claude to interact with Anki flashcard decks through the Model Context Protocol (MCP).

Features

  • Create and manage Anki decks
  • Create basic notes with front/back content
  • Create cloze notes
  • Create many notes at once in a single request
  • Attach images and audio from URLs - automatically downloaded and embedded
  • HTML formatting support in note fields
  • Update existing notes and cloze deletions
  • Add and manage tags
  • Search for notes with Anki's query syntax
  • Delete notes permanently
  • View deck contents and note information
  • Full integration with AnkiConnect

Prerequisites

  • Anki installed and running
  • AnkiConnect plugin installed in Anki
  • Node.js 16 or higher

Installation

  1. Clone this repository:
git clone https://github.com/yourusername/clanki.git
cd clanki
  1. Install dependencies:
npm install
  1. Build the project:
npm run build

Setup

  1. Make sure Anki is running and the AnkiConnect plugin is installed and enabled.

  2. Note the absolute path to build/index.js in your clanki checkout. Every client below needs it, and none of them accept a relative path — they do not run from your project directory, so ./build/index.js will not resolve.

    # from the clanki directory
    node -e "console.log(require('path').resolve('build/index.js'))"
    

    On Windows this prints backslashes. They are fine as-is for the two CLI commands below, but must be doubled or swapped for forward slashes if you paste the path into a JSON config — see the Claude Desktop note.

  3. Register the server with your client, using one of the sections below.

  4. Verify the server can reach Anki. With Anki running:

curl -X POST http://127.0.0.1:8765 -d "{\"action\":\"version\",\"version\":6}"

A working setup replies {"result": 6, "error": null}. If it does not, see docs/troubleshooting.md — connection failures are by far the most common problem, and AnkiConnect's default configuration needs no changes.

Claude Desktop

Edit claude_desktop_config.json:

PlatformLocation
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "clanki": {
      "command": "node",
      "args": ["/absolute/path/to/clanki/build/index.js"]
    }
  }
}

Replace /absolute/path/to/clanki with the actual path to your clanki installation. On Windows, write the path with either forward slashes or escaped backslashes (C:\\Users\\you\\clanki\\build\\index.js) — a single backslash is an escape character in JSON and will not parse.

Restart Claude Desktop afterwards; it reads the config only at startup.

Claude Code

claude mcp add clanki -- node /absolute/path/to/clanki/build/index.js

The -- is required. It marks the end of claude mcp add's own options, so everything after it is treated as the command to launch. Without it the arguments are parsed as options to claude mcp add itself and you get a broken entry rather than an error.

By default this registers the server for you in the current project only (--scope local). Two other scopes are available:

ScopeWhat it does
--scope localYou, in this project only. The default.
--scope userYou, in every project on this machine.
--scope projectWritten to .mcp.json in the repo root, for committing so teammates get it too.

Check it worked:

claude mcp list

clanki should be listed as connected. If it is listed as failed to connect, claude mcp get clanki shows the error.

You can also write .mcp.json by hand instead, using the same shape as the Claude Desktop config above. Claude Code reads it at session start, so restart the session after editing it.

Codex

codex mcp add clanki -- node /absolute/path/to/clanki/build/index.js

As with Claude Code, the -- separates Codex's own options from the command that launches the server, and is required.

This writes to ~/.codex/config.toml. Codex uses TOML rather than JSON, so if you prefer to edit the file directly the entry looks like this:

[mcp_servers.clanki]
command = "node"
args = ["/absolute/path/to/clanki/build/index.js"]

Note that the TOML table is mcp_servers with an underscore, not mcpServers as in the JSON configs above.

List the configured servers with:

codex mcp list

Configuration

Clanki needs no configuration in a normal setup. Every variable below is optional.

Using Anki in a language other than English

Anki translates the names of its built-in note types, and their fields, when a collection is created — a German collection has Einfach with the fields Vorderseite and Rückseite, not Basic with Front and Back. Clanki finds them by their structure rather than their names, so this works with no setup whatever language you use.

If your collection contains several note types that look alike, Clanki cannot tell which you meant. It stops and lists the candidates rather than guessing, because guessing wrong would write your text into a field that does not exist, and Anki discards it without an error. Name the one you want:

VariableWhat it does
CLANKI_BASIC_NOTE_TYPENote type for ordinary two-sided notes, e.g. Einfach
CLANKI_CLOZE_NOTE_TYPENote type for cloze notes, e.g. Lückentext
CLANKI_BASIC_FIELDSIts two fields, front first, e.g. Vorderseite,Rückseite
CLANKI_CLOZE_FIELDSIts two fields, text first, e.g. Text,Extra

Naming the note type is usually enough — Clanki reads its fields from your collection in order. The _FIELDS variables are only needed for a note type whose fields are not in front-then-back order. Both are checked against your collection at startup, so a typo is reported rather than silently losing content.

Connecting to AnkiConnect elsewhere

VariableDefault
CLANKI_ANKI_CONNECT_URLhttp://127.0.0.1:8765

Set this only if you changed AnkiConnect's port or reach Anki on another machine.

Where the variables go depends on your client.

In the JSON configs (Claude Desktop, and .mcp.json for Claude Code), they go in an env block alongside command and args:

{
  "mcpServers": {
    "clanki": {
      "command": "node",
      "args": ["/path/to/clanki/build/index.js"],
      "env": {
        "CLANKI_BASIC_NOTE_TYPE": "Einfach"
      }
    }
  }
}

In ~/.codex/config.toml, they go in an env sub-table under the server:

[mcp_servers.clanki]
command = "node"
args = ["/path/to/clanki/build/index.js"]

[mcp_servers.clanki.env]
CLANKI_BASIC_NOTE_TYPE = "Einfach"

Both CLIs can set them when you register the server, with --env repeated once per variable:

claude mcp add clanki --env CLANKI_BASIC_NOTE_TYPE=Einfach -- node /path/to/clanki/build/index.js
codex mcp add clanki --env CLANKI_BASIC_NOTE_TYPE=Einfach -- node /path/to/clanki/build/index.js

Restart the server after changing them.

Available Tools

create-deck

Creates a new Anki deck

  • Parameters:
    • name: Name for the new deck

create-card

Creates a new note in a specified deck. Supports HTML formatting and media attachments.

  • Parameters:
    • deckName: Name of the deck to add the note to
    • front: Front side content of the note (supports HTML)
    • back: Back side content of the note (supports HTML)
    • tags: (Optional) Array of tags for the note
    • frontImages: (Optional) Array of image URLs for the front
    • backImages: (Optional) Array of image URLs for the back
    • frontAudio: (Optional) Array of audio URLs for the front
    • backAudio: (Optional) Array of audio URLs for the back

create-cloze-card

Creates a new cloze note in a specified deck. Supports HTML formatting and media attachments.

  • Parameters:
    • deckName: Name of the deck to add the note to
    • text: Text containing cloze deletions using {{c1::text}} syntax (supports HTML)
    • backExtra: (Optional) Extra information to show on the back of the card (supports HTML)
    • tags: (Optional) Array of tags for the note
    • textImages: (Optional) Array of image URLs for the text field
    • backImages: (Optional) Array of image URLs for the back extra field
    • textAudio: (Optional) Array of audio URLs for the text field
    • backAudio: (Optional) Array of audio URLs for the back extra field

create-cards-bulk

Creates many basic notes in one request. Prefer this over repeated create-card calls for a batch: it sends a single request to Anki regardless of size. Does not support media — use create-card for notes that need images or audio.

  • Parameters:
    • deckName: Name of the deck to add the notes to
    • cards: Array of { front, back, tags? } objects (at least one)

Anki's addNotes is all-or-nothing — a single duplicate would otherwise fail the whole batch — so the tool asks which notes are addable first and sends only those. The response reports how many were added, and the input position and Anki's own reason for each note skipped, so you can correct and resend just those.

create-cloze-cards-bulk

Creates many cloze notes in one request. Same trade-offs as create-cards-bulk; use create-cloze-card when you need media.

  • Parameters:
    • deckName: Name of the deck to add the notes to
    • cards: Array of { text, backExtra?, tags? } objects (at least one)

Cloze syntax is validated for the whole batch before anything is sent, so a malformed entry fails the call rather than leaving a partial batch in the deck.

update-card

Updates an existing note

  • Parameters:
    • noteId: ID of the note to update
    • front: (Optional) New front side content
    • back: (Optional) New back side content
    • tags: (Optional) New tags for the note

update-cloze-card

Updates an existing cloze note

  • Parameters:
    • noteId: ID of the note to update
    • text: (Optional) New text with cloze deletions
    • backExtra: (Optional) New extra information for the back
    • tags: (Optional) New tags for the note

find-cards

Searches for notes with Anki's query syntax and returns their note IDs, note type, tags, and a short excerpt of each field. Use it to obtain the noteId that update-card, update-cloze-card and delete-card need.

Field content is truncated and the number of results is capped, so narrow the query if the note you want is not listed — the reply always reports how many notes matched in total.

  • Parameters:
    • query: Anki search query, e.g. deck:Spanish, tag:vocab, deck:Spanish tag:verbs

delete-card

Permanently deletes notes. This cannot be undone — there is no trash to recover them from, and every card generated from a deleted note goes with it.

Note IDs must be listed explicitly; there is no delete-by-query. Use find-cards first to obtain them and to check you have the right notes. The reply reports which IDs were actually deleted and which did not exist, because Anki reports success either way.

  • Parameters:
    • noteIds: IDs of the notes to delete, at most 50 per call
    • confirm: Must be true

Resources

Besides the tools above, decks are exposed as a readable resource.

anki://deck/<name>

Reads one deck and returns every note in it — note ID, front, back and tags. Unlike find-cards, the content is returned in full rather than truncated.

Usage Examples

Basic card with text only

"Create a flashcard in my Spanish deck with 'Hola' on the front and 'Hello' on the back"

Card with images

"Create a flashcard about the Eiffel Tower with an image from https://example.com/eiffel.jpg on the front"

Card with audio

"Create a pronunciation card with audio from https://example.com/pronunciation.mp3"

Card with multiple media

"Create a card with images on both sides and audio on the back for studying animals"

Cloze card with media

"Create a cloze card: 'The capital of {{c1::France}} is {{c2::Paris}}' with an image of the Eiffel Tower"

Note: Media files are automatically downloaded from URLs and embedded into the cards. Ensure URLs are accessible and point to valid media files. A URL that cannot be used is reported back in the tool's response; the note is still created without that attachment.

Media placement: Attachments are appended to the end of the field they belong to, after any text. You cannot position an image inline with HTML, because the filename is generated at upload time and is not known in advance. HTML formatting and media attachments therefore do not compose: use HTML to format your text, and the media parameters to attach files after it.

Known Issue: Missing Back Extra on Older Cloze Cards

Earlier versions wrote the backExtra value to a field named Back. Anki's built-in Cloze note type has no such field — its fields are Text and Back Extra — and AnkiConnect silently discards values sent to a field that does not exist.

As a result, cloze cards created before this fix have no extra content stored, even though the card was reported as created successfully. The text was never written to Anki, so it cannot be recovered automatically; re-entering it on the affected cards is the only fix.

Cloze cards created from this version onward store backExtra correctly.

Development

To modify or extend the server:

  1. Make changes to src/index.ts
  2. Rebuild with npm run build
  3. Debug with npx @modelcontextprotocol/inspector node build/index.js

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments