UNPKG

@ankimcp/anki-mcp-server

Version:

Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards

128 lines • 6.56 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var GuiAddCardsTool_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.GuiAddCardsTool = void 0; const common_1 = require("@nestjs/common"); const microservices_1 = require("@nestjs/microservices"); const mcp_nest_1 = require("@rekog/mcp-nest"); const zod_1 = require("zod"); const anki_connect_client_1 = require("../../../clients/anki-connect.client.js"); const anki_utils_1 = require("../../../utils/anki.utils.js"); let GuiAddCardsTool = GuiAddCardsTool_1 = class GuiAddCardsTool { ankiClient; logger = new common_1.Logger(GuiAddCardsTool_1.name); constructor(ankiClient) { this.ankiClient = ankiClient; } async guiAddCards({ note, }) { try { this.logger.log(`Opening Add Cards dialog for deck "${note.deckName}"`); const emptyFields = Object.entries(note.fields).filter(([_, value]) => !value || value.trim() === ""); if (emptyFields.length > 0) { return (0, anki_utils_1.createErrorResponse)(new Error(`Fields cannot be empty: ${emptyFields.map(([key]) => key).join(", ")}`), { deckName: note.deckName, modelName: note.modelName, emptyFields: emptyFields.map(([key]) => key), }); } const noteId = await this.ankiClient.invoke("guiAddCards", { note }); this.logger.log(`Add Cards dialog opened, potential note ID: ${noteId}`); return { success: true, noteId, deckName: note.deckName, modelName: note.modelName, message: `Add Cards dialog opened with preset details for deck "${note.deckName}"`, hint: "The user can now review and finalize the note in the Anki GUI. The note will be created when they click Add.", }; } catch (error) { this.logger.error("Failed to open Add Cards dialog", error); if (error instanceof Error) { const errorMessage = error.message.toLowerCase(); if (errorMessage.includes("field")) { return (0, anki_utils_1.createErrorResponse)(error, { modelName: note.modelName, providedFields: Object.keys(note.fields), hint: "Field mismatch. modelFieldNames lists the required fields.", }); } if (errorMessage.includes("model")) { return (0, anki_utils_1.createErrorResponse)(error, { modelName: note.modelName, hint: "Model not found. modelNames lists the available models.", }); } if (errorMessage.includes("deck")) { return (0, anki_utils_1.createErrorResponse)(error, { deckName: note.deckName, hint: "Deck not found. listDecks lists the available decks.", }); } } return (0, anki_utils_1.createErrorResponse)(error, { deckName: note.deckName, modelName: note.modelName, hint: "This can happen when Anki is not running or the deck/model names are wrong", }); } } }; exports.GuiAddCardsTool = GuiAddCardsTool; __decorate([ (0, mcp_nest_1.Tool)({ name: "guiAddCards", description: "Opens the Add Cards dialog in the Anki desktop app on the user's screen, pre-filled with deck, note type, fields and tags (replacing an Add Cards dialog that is already open), and makes that deck and note type Anki's current ones. " + "Nothing is saved until the user clicks Add, so the returned noteId does not refer to a saved note. " + "For when the user wants to review and finish a note by hand in Anki; addNote creates notes directly.", parameters: zod_1.z.object({ note: zod_1.z.object({ deckName: zod_1.z.string().min(1).describe("Deck to add the note to"), modelName: zod_1.z .string() .min(1) .describe('Note type/model (e.g., "Basic", "Cloze")'), fields: zod_1.z .record(zod_1.z.string(), zod_1.z.string()) .describe('Field values to pre-fill (e.g., {"Front": "question", "Back": "answer"})'), tags: zod_1.z.array(zod_1.z.string()).optional().describe("Optional tags to add"), }), }), outputSchema: zod_1.z.object({ success: zod_1.z.boolean(), noteId: zod_1.z.number().nullable(), deckName: zod_1.z.string(), modelName: zod_1.z.string(), message: zod_1.z.string(), hint: zod_1.z.string(), }), annotations: { title: "Open Add Cards Dialog", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }), __param(0, (0, microservices_1.Payload)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], GuiAddCardsTool.prototype, "guiAddCards", null); exports.GuiAddCardsTool = GuiAddCardsTool = GuiAddCardsTool_1 = __decorate([ (0, mcp_nest_1.McpController)(), __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient]) ], GuiAddCardsTool); //# sourceMappingURL=gui-add-cards.tool.js.map