Skip to main content
Glama

anki_operations

Perform Anki utility operations including syncing, exporting/importing decks, and managing media files to maintain your flashcard system.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationYesAnki utility operation
deckNameNoDeck name to export
filePathNoFile path for export/import
includeSchedNoInclude scheduling in export
filenameNoMedia filename
mediaDataNoBase64 encoded media data
mediaUrlNoURL to download media from
patternNoPattern to match media files

Implementation Reference

  • 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)}`
        );
      }
    }
  • 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'),
    },
  • 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)}`
          );
        }
      }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arielbk/anki-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server