anki_operations
Perform Anki utility operations including syncing, exporting/importing decks, and managing media files to maintain your flashcard system.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | Anki utility operation | |
| deckName | No | Deck name to export | |
| filePath | No | File path for export/import | |
| includeSched | No | Include scheduling in export | |
| filename | No | Media filename | |
| mediaData | No | Base64 encoded media data | |
| mediaUrl | No | URL to download media from | |
| pattern | No | Pattern to match media files |
Implementation Reference
- src/tools/consolidated.ts:999-1164 (handler)The main handler function for the 'anki_operations' tool. It handles multiple operations including sync, version check, export/import decks, and media file operations (store, retrieve, delete, list) using AnkiConnect API.async ({ operation, deckName, filePath, includeSched, filename, mediaData, mediaUrl, pattern, }) => { try { switch (operation) { case 'sync': { await ankiClient.miscellaneous.sync(); return { content: [ { type: 'text', text: '✓ Sync initiated successfully', }, ], }; } case 'version': { const version = await ankiClient.miscellaneous.version(); return { content: [ { type: 'text', text: `AnkiConnect version: ${version}`, }, ], }; } case 'export_deck': { if (!deckName || !filePath) { throw new Error('export_deck requires deckName and filePath'); } const params: any = { deck: deckName, path: filePath }; if (includeSched !== undefined) params.includeSched = includeSched; await ankiClient.miscellaneous.exportPackage(params); return { content: [ { type: 'text', text: `✓ Exported deck "${deckName}" to ${filePath}`, }, ], }; } case 'import_package': { if (!filePath) { throw new Error('import_package requires filePath'); } await ankiClient.miscellaneous.importPackage({ path: filePath }); return { content: [ { type: 'text', text: `✓ Imported package from ${filePath}`, }, ], }; } case 'store_media': { if (!filename) { throw new Error('store_media requires filename'); } if (!mediaData && !mediaUrl) { throw new Error('store_media requires either mediaData or mediaUrl'); } const params: any = { filename }; if (mediaData) params.data = mediaData; if (mediaUrl) params.url = mediaUrl; const storedName = await ankiClient.media.storeMediaFile(params); return { content: [ { type: 'text', text: `✓ Stored media file as: ${storedName}`, }, ], }; } case 'retrieve_media': { if (!filename) { throw new Error('retrieve_media requires filename'); } const content = await ankiClient.media.retrieveMediaFile({ filename }); if (content === false) { return { content: [ { type: 'text', text: `Media file "${filename}" not found`, }, ], }; } return { content: [ { type: 'text', text: `Retrieved "${filename}" (${content.length} chars)`, }, ], }; } case 'delete_media': { if (!filename) { throw new Error('delete_media requires filename'); } await ankiClient.media.deleteMediaFile({ filename }); return { content: [ { type: 'text', text: `✓ Deleted media file: ${filename}`, }, ], }; } case 'list_media': { if (!pattern) { throw new Error('list_media requires pattern (e.g., "*.jpg", "*")'); } const files = await ankiClient.media.getMediaFilesNames({ pattern }); return { content: [ { type: 'text', text: `Media files matching "${pattern}" (${files.length}):\n${JSON.stringify(files, null, 2)}`, }, ], }; } case 'get_profiles': { const profiles = await ankiClient.miscellaneous.getProfiles(); return { content: [ { type: 'text', text: `Available profiles:\n${JSON.stringify(profiles, null, 2)}`, }, ], }; } default: throw new Error(`Unknown operation: ${operation}`); } } catch (error) { throw new Error( `anki_operations failed: ${error instanceof Error ? error.message : String(error)}` ); } }
- src/tools/consolidated.ts:973-998 (schema)Zod input schema defining the parameters for the 'anki_operations' tool, including the required 'operation' enum and optional parameters for various sub-operations.{ operation: z .enum([ 'sync', 'version', 'export_deck', 'import_package', 'store_media', 'retrieve_media', 'delete_media', 'list_media', 'get_profiles', ]) .describe('Anki utility operation'), // Export/import deckName: z.string().optional().describe('Deck name to export'), filePath: z.string().optional().describe('File path for export/import'), includeSched: z.boolean().optional().describe('Include scheduling in export'), // Media filename: z.string().optional().describe('Media filename'), mediaData: z.string().optional().describe('Base64 encoded media data'), mediaUrl: z.string().optional().describe('URL to download media from'), pattern: z.string().optional().describe('Pattern to match media files'), },
- src/tools/consolidated.ts:971-1165 (registration)Registration of the 'anki_operations' tool using server.tool(), including inline schema and handler function.server.tool( 'anki_operations', { operation: z .enum([ 'sync', 'version', 'export_deck', 'import_package', 'store_media', 'retrieve_media', 'delete_media', 'list_media', 'get_profiles', ]) .describe('Anki utility operation'), // Export/import deckName: z.string().optional().describe('Deck name to export'), filePath: z.string().optional().describe('File path for export/import'), includeSched: z.boolean().optional().describe('Include scheduling in export'), // Media filename: z.string().optional().describe('Media filename'), mediaData: z.string().optional().describe('Base64 encoded media data'), mediaUrl: z.string().optional().describe('URL to download media from'), pattern: z.string().optional().describe('Pattern to match media files'), }, async ({ operation, deckName, filePath, includeSched, filename, mediaData, mediaUrl, pattern, }) => { try { switch (operation) { case 'sync': { await ankiClient.miscellaneous.sync(); return { content: [ { type: 'text', text: '✓ Sync initiated successfully', }, ], }; } case 'version': { const version = await ankiClient.miscellaneous.version(); return { content: [ { type: 'text', text: `AnkiConnect version: ${version}`, }, ], }; } case 'export_deck': { if (!deckName || !filePath) { throw new Error('export_deck requires deckName and filePath'); } const params: any = { deck: deckName, path: filePath }; if (includeSched !== undefined) params.includeSched = includeSched; await ankiClient.miscellaneous.exportPackage(params); return { content: [ { type: 'text', text: `✓ Exported deck "${deckName}" to ${filePath}`, }, ], }; } case 'import_package': { if (!filePath) { throw new Error('import_package requires filePath'); } await ankiClient.miscellaneous.importPackage({ path: filePath }); return { content: [ { type: 'text', text: `✓ Imported package from ${filePath}`, }, ], }; } case 'store_media': { if (!filename) { throw new Error('store_media requires filename'); } if (!mediaData && !mediaUrl) { throw new Error('store_media requires either mediaData or mediaUrl'); } const params: any = { filename }; if (mediaData) params.data = mediaData; if (mediaUrl) params.url = mediaUrl; const storedName = await ankiClient.media.storeMediaFile(params); return { content: [ { type: 'text', text: `✓ Stored media file as: ${storedName}`, }, ], }; } case 'retrieve_media': { if (!filename) { throw new Error('retrieve_media requires filename'); } const content = await ankiClient.media.retrieveMediaFile({ filename }); if (content === false) { return { content: [ { type: 'text', text: `Media file "${filename}" not found`, }, ], }; } return { content: [ { type: 'text', text: `Retrieved "${filename}" (${content.length} chars)`, }, ], }; } case 'delete_media': { if (!filename) { throw new Error('delete_media requires filename'); } await ankiClient.media.deleteMediaFile({ filename }); return { content: [ { type: 'text', text: `✓ Deleted media file: ${filename}`, }, ], }; } case 'list_media': { if (!pattern) { throw new Error('list_media requires pattern (e.g., "*.jpg", "*")'); } const files = await ankiClient.media.getMediaFilesNames({ pattern }); return { content: [ { type: 'text', text: `Media files matching "${pattern}" (${files.length}):\n${JSON.stringify(files, null, 2)}`, }, ], }; } case 'get_profiles': { const profiles = await ankiClient.miscellaneous.getProfiles(); return { content: [ { type: 'text', text: `Available profiles:\n${JSON.stringify(profiles, null, 2)}`, }, ], }; } default: throw new Error(`Unknown operation: ${operation}`); } } catch (error) { throw new Error( `anki_operations failed: ${error instanceof Error ? error.message : String(error)}` ); } } );