
Anki
STDIOInteract with Anki flashcards through MCP, supporting card management and audio generation
Interact with Anki flashcards through MCP, supporting card management and audio generation
MCP server for Anki. This server allows interaction with Anki through the Model Context Protocol (MCP). It enables users to manage flashcards, decks, and review processes programmatically.
.env
file as AZURE_API_KEY
) and Anki Media Directory (set as ANKI_MEDIA_DIR
).Highly recommended to run locally, since AnkiConnect only works locally.
Was only tested on windows.
Clone the repository:
git clone https://github.com/nietus/anki-mcp
Install dependencies:
npm install
Build the project
npm run build
Setup for Audio Features (If you want to use audio tools):
Create a .env file in the root directory with your Azure API key and Anki media directory:
AZURE_API_KEY=your_azure_api_key_here
ANKI_MEDIA_DIR=path/to/your/anki/media/directory
For Anki media directory, use the path to your Anki collection.media folder. This is where audio files will be stored. If you have trouble, paste it directly into the code.
C:\Users\username\AppData\Roaming\Anki2\User 1\collection.media
/Users/username/Library/Application Support/Anki2/User 1/collection.media
/home/username/.local/share/Anki2/User 1/collection.media
Note: The ANKI_MEDIA_DIR is required for audio generation to work properly as Anki needs to find the audio files in its media collection.
Integrate with Cursor settings (for local execution):
To run your local build of anki-mcp with Cursor, you need to tell Cursor how to start the server. Below are example configurations which you can access on cursor settings. Replace YOUR_USERNAME and adjust the path if you cloned anki-mcp to a different location than Downloads.
Windows:
"anki": { "command": "cmd", "args": [ "/c", "node", "c:/Users/YOUR_USERNAME/Downloads/anki-mcp/build/client.js" ] }
macOS / Linux:
"anki": { "command": "bash", "args": [ "-c", "node /Users/YOUR_USERNAME/Downloads/anki-mcp/build/client.js" ] }
To debug the tools, use
npm run inspector
The server provides the following tools for interacting with Anki:
update_cards
:
cardId
(number) and ease
(number, 1-4).add_card
:
update_note_fields
with the noteId instead. Note content uses HTML.
<br>
<pre style="background-color: transparent; padding: 10px; border-radius: 5px;">
<ol>
and <li>
<strong>
<em>
fields
: (object) An object where keys are field names (e.g., "Hanzi", "Pinyin") and values are their HTML content.modelName
: (string) The name of the Anki note type (model) to use.deckName
: (optional string) The name of the deck to add the card to. Defaults to the current deck or 'Default'.tags
: (optional array of strings) A list of tags to add to the note.add_card_with_audio
:
update_card_with_audio
with the noteId instead.fields
, modelName
, deckName
, tags
: Same as add_card
.sourceField
: (string) Field name containing the text to generate audio from.audioField
: (string) Field name where the generated audio will be stored.language
: (optional string) Language code for TTS (e.g., 'en', 'es', 'fr'). Defaults to 'en'.update_card_with_audio
:
add_card_with_audio
instead.noteId
: (number) The ID of the Anki note to update.sourceField
: (string) Field name containing the text to generate audio from.audioField
: (string) Field name where the generated audio will be stored.language
: (optional string) Language code for TTS. Defaults to 'en'.get_due_cards
:
num
(number).get_new_cards
:
num
(number).get_deck_names
:
find_cards
:
query
(string, e.g., 'deck:Default -tag:test'
, or '"deck:My Deck" tag:important'
). To filter for empty fields, use '-FieldName:_*'
(e.g., '-Hanzi:_*'
).update_note_fields
:
add_card
instead.noteId
(number), fields
(object, e.g., {"Front": "New Q", "Back": "New A"}
).create_deck
:
deckName
(string).bulk_update_notes
:
add_bulk
instead. Always complete all updates in a single operation whenever possible.notes
, where each note has noteId
(number) and fields
(object).get_model_names
:
get_model_details
:
modelName
(string).get_deck_model_info
:
deckName
(string).deckName
, status
(e.g., "single_model_found", "multiple_models_found", "no_notes_found", "deck_not_found"), and conditionally modelName
(string) or modelNames
(array of strings).add_note_type_field
:
modelName
(string), fieldName
(string).remove_note_type_field
:
modelName
(string), fieldName
(string).rename_note_type_field
:
modelName
(string), oldFieldName
(string), newFieldName
(string).reposition_note_type_field
:
modelName
(string), fieldName
(string), index
(number).update_note_type_templates
:
modelName
(string), templates
(object, e.g., {"Card 1": {"Front": "html", "Back": "html"}}
).update_note_type_styling
:
modelName
(string), css
(string).create_model
:
modelName
(string), fieldNames
(array of strings), cardTemplates
(array of objects, each with Name
, Front
, Back
HTML strings), css
(optional string), isCloze
(optional boolean, defaults to false), modelType
(optional string, defaults to 'Standard').add_bulk
:
bulk_update_notes
with noteIds instead. Always complete all additions in a single operation whenever possible. Must use HTML formatting for card content.notes
, where each note object has:
fields
: (object) An object where keys are field names and values are their HTML content.modelName
: (string) The name of the Anki note type (model) to use for this note.deckName
: (optional string) The name of the deck for this note. Defaults to 'Default'.tags
: (optional array of strings) A list of tags for this note.More information can be found here Anki Integration | Smithery