@ankimcp/anki-mcp-server 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +756 -0
  3. package/bin/ankimcp.js +12 -0
  4. package/dist/anki-config.service.d.ts +10 -0
  5. package/dist/anki-config.service.js +42 -0
  6. package/dist/anki-config.service.js.map +1 -0
  7. package/dist/app.module.d.ts +5 -0
  8. package/dist/app.module.js +84 -0
  9. package/dist/app.module.js.map +1 -0
  10. package/dist/bootstrap.d.ts +3 -0
  11. package/dist/bootstrap.js +39 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/cli.d.ts +9 -0
  14. package/dist/cli.js +114 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/http/guards/origin-validation.guard.d.ts +7 -0
  17. package/dist/http/guards/origin-validation.guard.js +52 -0
  18. package/dist/http/guards/origin-validation.guard.js.map +1 -0
  19. package/dist/main-http.d.ts +1 -0
  20. package/dist/main-http.js +42 -0
  21. package/dist/main-http.js.map +1 -0
  22. package/dist/main-stdio.d.ts +1 -0
  23. package/dist/main-stdio.js +20 -0
  24. package/dist/main-stdio.js.map +1 -0
  25. package/dist/mcp/clients/__mocks__/anki-connect.client.d.ts +6 -0
  26. package/dist/mcp/clients/__mocks__/anki-connect.client.js +18 -0
  27. package/dist/mcp/clients/__mocks__/anki-connect.client.js.map +1 -0
  28. package/dist/mcp/clients/anki-connect.client.d.ts +15 -0
  29. package/dist/mcp/clients/anki-connect.client.js +145 -0
  30. package/dist/mcp/clients/anki-connect.client.js.map +1 -0
  31. package/dist/mcp/config/anki-config.interface.d.ts +7 -0
  32. package/dist/mcp/config/anki-config.interface.js +5 -0
  33. package/dist/mcp/config/anki-config.interface.js.map +1 -0
  34. package/dist/mcp/primitives/essential/index.d.ts +32 -0
  35. package/dist/mcp/primitives/essential/index.js +130 -0
  36. package/dist/mcp/primitives/essential/index.js.map +1 -0
  37. package/dist/mcp/primitives/essential/prompts/review-session.prompt.d.ts +12 -0
  38. package/dist/mcp/primitives/essential/prompts/review-session.prompt.js +113 -0
  39. package/dist/mcp/primitives/essential/prompts/review-session.prompt.js.map +1 -0
  40. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/content.md +195 -0
  41. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.d.ts +12 -0
  42. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.js +89 -0
  43. package/dist/mcp/primitives/essential/prompts/twenty-rules.prompt/index.js.map +1 -0
  44. package/dist/mcp/primitives/essential/resources/system-info.resource.d.ts +21 -0
  45. package/dist/mcp/primitives/essential/resources/system-info.resource.js +115 -0
  46. package/dist/mcp/primitives/essential/resources/system-info.resource.js.map +1 -0
  47. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +93 -0
  48. package/dist/mcp/primitives/essential/tools/add-note.tool.js +185 -0
  49. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -0
  50. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +83 -0
  51. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +121 -0
  52. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +1 -0
  53. package/dist/mcp/primitives/essential/tools/create-model.tool.d.ts +88 -0
  54. package/dist/mcp/primitives/essential/tools/create-model.tool.js +144 -0
  55. package/dist/mcp/primitives/essential/tools/create-model.tool.js.map +1 -0
  56. package/dist/mcp/primitives/essential/tools/delete-notes.tool.d.ts +84 -0
  57. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js +120 -0
  58. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js.map +1 -0
  59. package/dist/mcp/primitives/essential/tools/find-notes.tool.d.ts +83 -0
  60. package/dist/mcp/primitives/essential/tools/find-notes.tool.js +106 -0
  61. package/dist/mcp/primitives/essential/tools/find-notes.tool.js.map +1 -0
  62. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.d.ts +84 -0
  63. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js +108 -0
  64. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js.map +1 -0
  65. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +83 -0
  66. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +117 -0
  67. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +1 -0
  68. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.d.ts +10 -0
  69. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.js +18 -0
  70. package/dist/mcp/primitives/essential/tools/mediaActions/actions/deleteMediaFile.action.js.map +1 -0
  71. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.d.ts +12 -0
  72. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.js +22 -0
  73. package/dist/mcp/primitives/essential/tools/mediaActions/actions/getMediaFilesNames.action.js.map +1 -0
  74. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.d.ts +12 -0
  75. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.js +29 -0
  76. package/dist/mcp/primitives/essential/tools/mediaActions/actions/retrieveMediaFile.action.js.map +1 -0
  77. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.d.ts +15 -0
  78. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.js +41 -0
  79. package/dist/mcp/primitives/essential/tools/mediaActions/actions/storeMediaFile.action.js.map +1 -0
  80. package/dist/mcp/primitives/essential/tools/mediaActions/index.d.ts +5 -0
  81. package/dist/mcp/primitives/essential/tools/mediaActions/index.js +6 -0
  82. package/dist/mcp/primitives/essential/tools/mediaActions/index.js.map +1 -0
  83. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.d.ts +89 -0
  84. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.js +141 -0
  85. package/dist/mcp/primitives/essential/tools/mediaActions/mediaActions.tool.js.map +1 -0
  86. package/dist/mcp/primitives/essential/tools/model-field-names.tool.d.ts +83 -0
  87. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +119 -0
  88. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -0
  89. package/dist/mcp/primitives/essential/tools/model-names.tool.d.ts +81 -0
  90. package/dist/mcp/primitives/essential/tools/model-names.tool.js +80 -0
  91. package/dist/mcp/primitives/essential/tools/model-names.tool.js.map +1 -0
  92. package/dist/mcp/primitives/essential/tools/model-styling.tool.d.ts +83 -0
  93. package/dist/mcp/primitives/essential/tools/model-styling.tool.js +93 -0
  94. package/dist/mcp/primitives/essential/tools/model-styling.tool.js.map +1 -0
  95. package/dist/mcp/primitives/essential/tools/notes-info.tool.d.ts +83 -0
  96. package/dist/mcp/primitives/essential/tools/notes-info.tool.js +111 -0
  97. package/dist/mcp/primitives/essential/tools/notes-info.tool.js.map +1 -0
  98. package/dist/mcp/primitives/essential/tools/present-card.tool.d.ts +84 -0
  99. package/dist/mcp/primitives/essential/tools/present-card.tool.js +100 -0
  100. package/dist/mcp/primitives/essential/tools/present-card.tool.js.map +1 -0
  101. package/dist/mcp/primitives/essential/tools/rate-card.tool.d.ts +84 -0
  102. package/dist/mcp/primitives/essential/tools/rate-card.tool.js +101 -0
  103. package/dist/mcp/primitives/essential/tools/rate-card.tool.js.map +1 -0
  104. package/dist/mcp/primitives/essential/tools/sync.tool.d.ts +81 -0
  105. package/dist/mcp/primitives/essential/tools/sync.tool.js +61 -0
  106. package/dist/mcp/primitives/essential/tools/sync.tool.js.map +1 -0
  107. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.d.ts +84 -0
  108. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js +119 -0
  109. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js.map +1 -0
  110. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.d.ts +96 -0
  111. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js +154 -0
  112. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js.map +1 -0
  113. package/dist/mcp/primitives/gui/index.d.ts +23 -0
  114. package/dist/mcp/primitives/gui/index.js +94 -0
  115. package/dist/mcp/primitives/gui/index.js.map +1 -0
  116. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.d.ts +88 -0
  117. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js +111 -0
  118. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js.map +1 -0
  119. package/dist/mcp/primitives/gui/tools/gui-browse.tool.d.ts +87 -0
  120. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js +99 -0
  121. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js.map +1 -0
  122. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.d.ts +81 -0
  123. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js +76 -0
  124. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js.map +1 -0
  125. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.d.ts +81 -0
  126. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js +64 -0
  127. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js.map +1 -0
  128. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.d.ts +83 -0
  129. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js +88 -0
  130. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js.map +1 -0
  131. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.d.ts +83 -0
  132. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js +80 -0
  133. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js.map +1 -0
  134. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.d.ts +83 -0
  135. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js +90 -0
  136. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js.map +1 -0
  137. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.d.ts +81 -0
  138. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js +83 -0
  139. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js.map +1 -0
  140. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.d.ts +81 -0
  141. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js +74 -0
  142. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js.map +1 -0
  143. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.d.ts +81 -0
  144. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js +74 -0
  145. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js.map +1 -0
  146. package/dist/mcp/primitives/gui/tools/gui-undo.tool.d.ts +81 -0
  147. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js +74 -0
  148. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js.map +1 -0
  149. package/dist/mcp/types/anki.types.d.ts +180 -0
  150. package/dist/mcp/types/anki.types.js +18 -0
  151. package/dist/mcp/types/anki.types.js.map +1 -0
  152. package/dist/mcp/utils/anki.utils.d.ts +19 -0
  153. package/dist/mcp/utils/anki.utils.js +157 -0
  154. package/dist/mcp/utils/anki.utils.js.map +1 -0
  155. package/dist/mcp/utils/markdown.utils.d.ts +4 -0
  156. package/dist/mcp/utils/markdown.utils.js +60 -0
  157. package/dist/mcp/utils/markdown.utils.js.map +1 -0
  158. package/dist/mcp/utils/mcpb-workarounds.d.ts +1 -0
  159. package/dist/mcp/utils/mcpb-workarounds.js +13 -0
  160. package/dist/mcp/utils/mcpb-workarounds.js.map +1 -0
  161. package/dist/services/ngrok.service.d.ts +15 -0
  162. package/dist/services/ngrok.service.js +120 -0
  163. package/dist/services/ngrok.service.js.map +1 -0
  164. package/dist/test-fixtures/mock-data.d.ts +126 -0
  165. package/dist/test-fixtures/mock-data.js +112 -0
  166. package/dist/test-fixtures/mock-data.js.map +1 -0
  167. package/dist/test-fixtures/test-helpers.d.ts +12 -0
  168. package/dist/test-fixtures/test-helpers.js +24 -0
  169. package/dist/test-fixtures/test-helpers.js.map +1 -0
  170. package/dist/tsconfig.build.tsbuildinfo +1 -0
  171. package/package.json +168 -0
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var AddNoteTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AddNoteTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let AddNoteTool = AddNoteTool_1 = class AddNoteTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(AddNoteTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async addNote({ deckName, modelName, fields, tags, allowDuplicate, duplicateScope, duplicateScopeOptions, }, context) {
26
+ try {
27
+ const emptyFields = Object.entries(fields).filter(([_, value]) => !value || value.trim() === "");
28
+ if (emptyFields.length > 0) {
29
+ return (0, anki_utils_1.createErrorResponse)(new Error(`Fields cannot be empty: ${emptyFields.map(([key]) => key).join(", ")}`), {
30
+ deckName,
31
+ modelName,
32
+ emptyFields: emptyFields.map(([key]) => key),
33
+ });
34
+ }
35
+ this.logger.log(`Adding note to deck "${deckName}" with model "${modelName}"`);
36
+ await context.reportProgress({ progress: 25, total: 100 });
37
+ const noteParams = {
38
+ deckName: deckName,
39
+ modelName: modelName,
40
+ fields: fields,
41
+ };
42
+ if (tags && tags.length > 0) {
43
+ noteParams.tags = tags;
44
+ }
45
+ const options = {};
46
+ let hasOptions = false;
47
+ if (allowDuplicate !== undefined) {
48
+ options.allowDuplicate = allowDuplicate;
49
+ hasOptions = true;
50
+ }
51
+ if (duplicateScope !== undefined) {
52
+ options.duplicateScope = duplicateScope;
53
+ hasOptions = true;
54
+ }
55
+ if (duplicateScopeOptions !== undefined) {
56
+ options.duplicateScopeOptions = duplicateScopeOptions;
57
+ hasOptions = true;
58
+ }
59
+ if (hasOptions) {
60
+ noteParams.options = options;
61
+ }
62
+ await context.reportProgress({ progress: 50, total: 100 });
63
+ const noteId = await this.ankiClient.invoke("addNote", {
64
+ note: noteParams,
65
+ });
66
+ await context.reportProgress({ progress: 75, total: 100 });
67
+ if (!noteId) {
68
+ this.logger.warn("Note creation failed - possibly a duplicate");
69
+ await context.reportProgress({ progress: 100, total: 100 });
70
+ return (0, anki_utils_1.createErrorResponse)(new Error("Failed to create note - it may be a duplicate"), {
71
+ deckName,
72
+ modelName,
73
+ hint: allowDuplicate
74
+ ? "The note could not be created. Check if the model and deck names are correct."
75
+ : "The note appears to be a duplicate. Set allowDuplicate to true if you want to add it anyway.",
76
+ });
77
+ }
78
+ await context.reportProgress({ progress: 100, total: 100 });
79
+ this.logger.log(`Successfully created note with ID: ${noteId}`);
80
+ const fieldCount = Object.keys(fields).length;
81
+ const tagCount = tags ? tags.length : 0;
82
+ return (0, anki_utils_1.createSuccessResponse)({
83
+ success: true,
84
+ noteId: noteId,
85
+ deckName: deckName,
86
+ modelName: modelName,
87
+ message: `Successfully created note in deck "${deckName}"`,
88
+ details: {
89
+ fieldsAdded: fieldCount,
90
+ tagsAdded: tagCount,
91
+ duplicateCheckScope: duplicateScope || "default",
92
+ },
93
+ });
94
+ }
95
+ catch (error) {
96
+ this.logger.error("Failed to add note", error);
97
+ if (error instanceof Error) {
98
+ if (error.message.includes("model")) {
99
+ return (0, anki_utils_1.createErrorResponse)(error, {
100
+ deckName,
101
+ modelName,
102
+ hint: "Model not found. Use modelNames tool to see available models.",
103
+ });
104
+ }
105
+ if (error.message.includes("deck")) {
106
+ return (0, anki_utils_1.createErrorResponse)(error, {
107
+ deckName,
108
+ modelName,
109
+ hint: "Deck not found. Use list_decks tool to see available decks or createDeck to create a new one.",
110
+ });
111
+ }
112
+ if (error.message.includes("field")) {
113
+ return (0, anki_utils_1.createErrorResponse)(error, {
114
+ deckName,
115
+ modelName,
116
+ providedFields: Object.keys(fields),
117
+ hint: "Field mismatch. Use modelFieldNames tool to see required fields for this model.",
118
+ });
119
+ }
120
+ }
121
+ return (0, anki_utils_1.createErrorResponse)(error, {
122
+ deckName,
123
+ modelName,
124
+ hint: "Make sure Anki is running and the deck/model names are correct",
125
+ });
126
+ }
127
+ }
128
+ };
129
+ exports.AddNoteTool = AddNoteTool;
130
+ __decorate([
131
+ (0, mcp_nest_1.Tool)({
132
+ name: "addNote",
133
+ description: "Add a new note to Anki. Use modelNames to see available note types and modelFieldNames to see required fields. Returns the note ID on success. IMPORTANT: Only create notes that were explicitly requested by the user.",
134
+ parameters: zod_1.z.object({
135
+ deckName: zod_1.z.string().min(1).describe("The deck to add the note to"),
136
+ modelName: zod_1.z
137
+ .string()
138
+ .min(1)
139
+ .describe('The note type/model to use (e.g., "Basic", "Cloze")'),
140
+ fields: zod_1.z
141
+ .record(zod_1.z.string())
142
+ .describe('Field values as key-value pairs (e.g., {"Front": "question", "Back": "answer"})'),
143
+ tags: zod_1.z
144
+ .array(zod_1.z.string())
145
+ .optional()
146
+ .describe("Optional tags to add to the note"),
147
+ allowDuplicate: zod_1.z
148
+ .boolean()
149
+ .optional()
150
+ .default(false)
151
+ .describe("Whether to allow adding duplicate notes"),
152
+ duplicateScope: zod_1.z
153
+ .enum(["deck", "collection"])
154
+ .optional()
155
+ .describe("Scope for duplicate checking"),
156
+ duplicateScopeOptions: zod_1.z
157
+ .object({
158
+ deckName: zod_1.z
159
+ .string()
160
+ .optional()
161
+ .describe("Specific deck to check for duplicates"),
162
+ checkChildren: zod_1.z
163
+ .boolean()
164
+ .optional()
165
+ .default(false)
166
+ .describe("Check child decks for duplicates"),
167
+ checkAllModels: zod_1.z
168
+ .boolean()
169
+ .optional()
170
+ .default(false)
171
+ .describe("Check across all note types"),
172
+ })
173
+ .optional()
174
+ .describe("Advanced duplicate checking options"),
175
+ }),
176
+ }),
177
+ __metadata("design:type", Function),
178
+ __metadata("design:paramtypes", [Object, Object]),
179
+ __metadata("design:returntype", Promise)
180
+ ], AddNoteTool.prototype, "addNote", null);
181
+ exports.AddNoteTool = AddNoteTool = AddNoteTool_1 = __decorate([
182
+ (0, common_1.Injectable)(),
183
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
184
+ ], AddNoteTool);
185
+ //# sourceMappingURL=add-note.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-note.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/add-note.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import type { Context } from "@rekog/mcp-nest";
2
+ import { AnkiConnectClient } from "@/mcp/clients/anki-connect.client";
3
+ export declare class CreateDeckTool {
4
+ private readonly ankiClient;
5
+ private readonly logger;
6
+ constructor(ankiClient: AnkiConnectClient);
7
+ createDeck({ deck_name }: {
8
+ deck_name: string;
9
+ }, context: Context): Promise<{
10
+ [x: string]: unknown;
11
+ content: ({
12
+ [x: string]: unknown;
13
+ type: "text";
14
+ text: string;
15
+ _meta?: {
16
+ [x: string]: unknown;
17
+ } | undefined;
18
+ } | {
19
+ [x: string]: unknown;
20
+ type: "image";
21
+ data: string;
22
+ mimeType: string;
23
+ _meta?: {
24
+ [x: string]: unknown;
25
+ } | undefined;
26
+ } | {
27
+ [x: string]: unknown;
28
+ type: "audio";
29
+ data: string;
30
+ mimeType: string;
31
+ _meta?: {
32
+ [x: string]: unknown;
33
+ } | undefined;
34
+ } | {
35
+ [x: string]: unknown;
36
+ type: "resource_link";
37
+ name: string;
38
+ uri: string;
39
+ _meta?: {
40
+ [x: string]: unknown;
41
+ } | undefined;
42
+ mimeType?: string | undefined;
43
+ title?: string | undefined;
44
+ description?: string | undefined;
45
+ icons?: {
46
+ [x: string]: unknown;
47
+ src: string;
48
+ mimeType?: string | undefined;
49
+ sizes?: string[] | undefined;
50
+ }[] | undefined;
51
+ } | {
52
+ [x: string]: unknown;
53
+ type: "resource";
54
+ resource: {
55
+ [x: string]: unknown;
56
+ text: string;
57
+ uri: string;
58
+ _meta?: {
59
+ [x: string]: unknown;
60
+ } | undefined;
61
+ mimeType?: string | undefined;
62
+ } | {
63
+ [x: string]: unknown;
64
+ uri: string;
65
+ blob: string;
66
+ _meta?: {
67
+ [x: string]: unknown;
68
+ } | undefined;
69
+ mimeType?: string | undefined;
70
+ };
71
+ _meta?: {
72
+ [x: string]: unknown;
73
+ } | undefined;
74
+ })[];
75
+ _meta?: {
76
+ [x: string]: unknown;
77
+ } | undefined;
78
+ structuredContent?: {
79
+ [x: string]: unknown;
80
+ } | undefined;
81
+ isError?: boolean | undefined;
82
+ }>;
83
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var CreateDeckTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.CreateDeckTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let CreateDeckTool = CreateDeckTool_1 = class CreateDeckTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(CreateDeckTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async createDeck({ deck_name }, context) {
26
+ try {
27
+ const parts = deck_name.split("::");
28
+ if (parts.length > 2) {
29
+ return (0, anki_utils_1.createErrorResponse)(new Error("Deck name can have maximum 2 levels (parent::child)"), {
30
+ deckName: deck_name,
31
+ levels: parts.length,
32
+ maxLevels: 2,
33
+ });
34
+ }
35
+ if (parts.some((part) => part.trim() === "")) {
36
+ return (0, anki_utils_1.createErrorResponse)(new Error("Deck name parts cannot be empty"), { deckName: deck_name });
37
+ }
38
+ this.logger.log(`Creating deck: ${deck_name}`);
39
+ await context.reportProgress({ progress: 25, total: 100 });
40
+ const deckId = await this.ankiClient.invoke("createDeck", {
41
+ deck: deck_name,
42
+ });
43
+ await context.reportProgress({ progress: 75, total: 100 });
44
+ if (!deckId) {
45
+ this.logger.warn(`Deck may already exist: ${deck_name}`);
46
+ const existingDecks = await this.ankiClient.invoke("deckNames");
47
+ const deckExists = existingDecks.includes(deck_name);
48
+ await context.reportProgress({ progress: 100, total: 100 });
49
+ if (deckExists) {
50
+ return (0, anki_utils_1.createSuccessResponse)({
51
+ success: true,
52
+ message: `Deck "${deck_name}" already exists`,
53
+ deckName: deck_name,
54
+ created: false,
55
+ exists: true,
56
+ });
57
+ }
58
+ return (0, anki_utils_1.createErrorResponse)(new Error("Failed to create deck - unknown error"), { deckName: deck_name });
59
+ }
60
+ await context.reportProgress({ progress: 100, total: 100 });
61
+ this.logger.log(`Successfully created deck: ${deck_name} with ID: ${deckId}`);
62
+ const response = {
63
+ success: true,
64
+ deckId: deckId,
65
+ deckName: deck_name,
66
+ message: `Successfully created deck "${deck_name}"`,
67
+ created: true,
68
+ };
69
+ if (parts.length === 2) {
70
+ response.parentDeck = parts[0];
71
+ response.childDeck = parts[1];
72
+ response.message = `Successfully created parent deck "${parts[0]}" and child deck "${parts[1]}"`;
73
+ }
74
+ return (0, anki_utils_1.createSuccessResponse)(response);
75
+ }
76
+ catch (error) {
77
+ this.logger.error(`Failed to create deck ${deck_name}`, error);
78
+ if (error instanceof Error && error.message.includes("already exists")) {
79
+ return (0, anki_utils_1.createSuccessResponse)({
80
+ success: true,
81
+ message: `Deck "${deck_name}" already exists`,
82
+ deckName: deck_name,
83
+ created: false,
84
+ exists: true,
85
+ });
86
+ }
87
+ return (0, anki_utils_1.createErrorResponse)(error, {
88
+ deckName: deck_name,
89
+ hint: "Make sure Anki is running and the deck name is valid",
90
+ });
91
+ }
92
+ }
93
+ };
94
+ exports.CreateDeckTool = CreateDeckTool;
95
+ __decorate([
96
+ (0, mcp_nest_1.Tool)({
97
+ name: "create_deck",
98
+ description: 'Create a new empty Anki deck. Supports parent::child structure (e.g., "Japanese::Tokyo" creates parent deck "Japanese" and child deck "Tokyo"). Maximum 2 levels of nesting allowed. Will not overwrite existing decks. ' +
99
+ "IMPORTANT: This tool ONLY creates an empty deck. DO NOT add cards or notes after creating a deck unless the user EXPLICITLY asks to add them. Wait for user instructions before adding any content.",
100
+ parameters: zod_1.z.object({
101
+ deck_name: zod_1.z
102
+ .string()
103
+ .min(1)
104
+ .describe('The name of the deck to create. Use "::" for parent::child structure (max 2 levels)')
105
+ .refine((name) => {
106
+ const parts = name.split("::");
107
+ return parts.length <= 2;
108
+ }, {
109
+ message: "Deck name can have maximum 2 levels (parent::child). More than 2 levels not permitted.",
110
+ }),
111
+ }),
112
+ }),
113
+ __metadata("design:type", Function),
114
+ __metadata("design:paramtypes", [Object, Object]),
115
+ __metadata("design:returntype", Promise)
116
+ ], CreateDeckTool.prototype, "createDeck", null);
117
+ exports.CreateDeckTool = CreateDeckTool = CreateDeckTool_1 = __decorate([
118
+ (0, common_1.Injectable)(),
119
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
120
+ ], CreateDeckTool);
121
+ //# sourceMappingURL=create-deck.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-deck.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/create-deck.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,8CAAuC;AAEvC,6BAAwB;AACxB,8EAAsE;AACtE,0DAGgC;AAMzB,IAAM,cAAc,sBAApB,MAAM,cAAc;IAGI;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,gBAAc,CAAC,IAAI,CAAC,CAAC;IAE1D,YAA6B,UAA6B;QAA7B,eAAU,GAAV,UAAU,CAAmB;IAAG,CAAC;IA0BxD,AAAN,KAAK,CAAC,UAAU,CAAC,EAAE,SAAS,EAAyB,EAAE,OAAgB;QACrE,IAAI,CAAC;YAEH,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,OAAO,IAAA,gCAAmB,EACxB,IAAI,KAAK,CAAC,qDAAqD,CAAC,EAChE;oBACE,QAAQ,EAAE,SAAS;oBACnB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,SAAS,EAAE,CAAC;iBACb,CACF,CAAC;YACJ,CAAC;YAGD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBAC7C,OAAO,IAAA,gCAAmB,EACxB,IAAI,KAAK,CAAC,iCAAiC,CAAC,EAC5C,EAAE,QAAQ,EAAE,SAAS,EAAE,CACxB,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,SAAS,EAAE,CAAC,CAAC;YAC/C,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAG3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAS,YAAY,EAAE;gBAChE,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;YAEH,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAE3D,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,SAAS,EAAE,CAAC,CAAC;gBAGzD,MAAM,aAAa,GACjB,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAW,WAAW,CAAC,CAAC;gBACtD,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAErD,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;gBAE5D,IAAI,UAAU,EAAE,CAAC;oBACf,OAAO,IAAA,kCAAqB,EAAC;wBAC3B,OAAO,EAAE,IAAI;wBACb,OAAO,EAAE,SAAS,SAAS,kBAAkB;wBAC7C,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,KAAK;wBACd,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC;gBACL,CAAC;gBAED,OAAO,IAAA,gCAAmB,EACxB,IAAI,KAAK,CAAC,uCAAuC,CAAC,EAClD,EAAE,QAAQ,EAAE,SAAS,EAAE,CACxB,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5D,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,8BAA8B,SAAS,aAAa,MAAM,EAAE,CAC7D,CAAC;YAEF,MAAM,QAAQ,GAAQ;gBACpB,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,MAAM;gBACd,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,8BAA8B,SAAS,GAAG;gBACnD,OAAO,EAAE,IAAI;aACd,CAAC;YAGF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC/B,QAAQ,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,QAAQ,CAAC,OAAO,GAAG,qCAAqC,KAAK,CAAC,CAAC,CAAC,qBAAqB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;YACnG,CAAC;YAED,OAAO,IAAA,kCAAqB,EAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;YAG/D,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACvE,OAAO,IAAA,kCAAqB,EAAC;oBAC3B,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,SAAS,SAAS,kBAAkB;oBAC7C,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAA,gCAAmB,EAAC,KAAK,EAAE;gBAChC,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,sDAAsD;aAC7D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AAjIY,wCAAc;AA6BnB;IAxBL,IAAA,eAAI,EAAC;QACJ,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,0NAA0N;YAC1N,qMAAqM;QACvM,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,SAAS,EAAE,OAAC;iBACT,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CACP,qFAAqF,CACtF;iBACA,MAAM,CACL,CAAC,IAAI,EAAE,EAAE;gBACP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;YAC3B,CAAC,EACD;gBACE,OAAO,EACL,wFAAwF;aAC3F,CACF;SACJ,CAAC;KACH,CAAC;;;;gDAoGD;yBAhIU,cAAc;IAD1B,IAAA,mBAAU,GAAE;qCAI8B,uCAAiB;GAH/C,cAAc,CAiI1B"}
@@ -0,0 +1,88 @@
1
+ import type { Context } from "@rekog/mcp-nest";
2
+ import { AnkiConnectClient } from "@/mcp/clients/anki-connect.client";
3
+ import type { CardTemplate } from "@/mcp/types/anki.types";
4
+ export declare class CreateModelTool {
5
+ private readonly ankiClient;
6
+ private readonly logger;
7
+ constructor(ankiClient: AnkiConnectClient);
8
+ createModel({ modelName, inOrderFields, cardTemplates, css, isCloze, }: {
9
+ modelName: string;
10
+ inOrderFields: string[];
11
+ cardTemplates: CardTemplate[];
12
+ css?: string;
13
+ isCloze?: boolean;
14
+ }, context: Context): Promise<{
15
+ [x: string]: unknown;
16
+ content: ({
17
+ [x: string]: unknown;
18
+ type: "text";
19
+ text: string;
20
+ _meta?: {
21
+ [x: string]: unknown;
22
+ } | undefined;
23
+ } | {
24
+ [x: string]: unknown;
25
+ type: "image";
26
+ data: string;
27
+ mimeType: string;
28
+ _meta?: {
29
+ [x: string]: unknown;
30
+ } | undefined;
31
+ } | {
32
+ [x: string]: unknown;
33
+ type: "audio";
34
+ data: string;
35
+ mimeType: string;
36
+ _meta?: {
37
+ [x: string]: unknown;
38
+ } | undefined;
39
+ } | {
40
+ [x: string]: unknown;
41
+ type: "resource_link";
42
+ name: string;
43
+ uri: string;
44
+ _meta?: {
45
+ [x: string]: unknown;
46
+ } | undefined;
47
+ mimeType?: string | undefined;
48
+ title?: string | undefined;
49
+ description?: string | undefined;
50
+ icons?: {
51
+ [x: string]: unknown;
52
+ src: string;
53
+ mimeType?: string | undefined;
54
+ sizes?: string[] | undefined;
55
+ }[] | undefined;
56
+ } | {
57
+ [x: string]: unknown;
58
+ type: "resource";
59
+ resource: {
60
+ [x: string]: unknown;
61
+ text: string;
62
+ uri: string;
63
+ _meta?: {
64
+ [x: string]: unknown;
65
+ } | undefined;
66
+ mimeType?: string | undefined;
67
+ } | {
68
+ [x: string]: unknown;
69
+ uri: string;
70
+ blob: string;
71
+ _meta?: {
72
+ [x: string]: unknown;
73
+ } | undefined;
74
+ mimeType?: string | undefined;
75
+ };
76
+ _meta?: {
77
+ [x: string]: unknown;
78
+ } | undefined;
79
+ })[];
80
+ _meta?: {
81
+ [x: string]: unknown;
82
+ } | undefined;
83
+ structuredContent?: {
84
+ [x: string]: unknown;
85
+ } | undefined;
86
+ isError?: boolean | undefined;
87
+ }>;
88
+ }
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var CreateModelTool_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.CreateModelTool = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const mcp_nest_1 = require("@rekog/mcp-nest");
16
+ const zod_1 = require("zod");
17
+ const anki_connect_client_1 = require("../../../clients/anki-connect.client");
18
+ const anki_utils_1 = require("../../../utils/anki.utils");
19
+ let CreateModelTool = CreateModelTool_1 = class CreateModelTool {
20
+ ankiClient;
21
+ logger = new common_1.Logger(CreateModelTool_1.name);
22
+ constructor(ankiClient) {
23
+ this.ankiClient = ankiClient;
24
+ }
25
+ async createModel({ modelName, inOrderFields, cardTemplates, css, isCloze, }, context) {
26
+ try {
27
+ this.logger.log(`Creating model: ${modelName} with ${inOrderFields.length} fields`);
28
+ await context.reportProgress({ progress: 10, total: 100 });
29
+ const warnings = [];
30
+ const fieldSet = new Set(inOrderFields);
31
+ for (const template of cardTemplates) {
32
+ const templateContent = `${template.Front} ${template.Back}`;
33
+ const fieldRefs = templateContent.match(/\{\{([^}]+)\}\}/g) || [];
34
+ for (const ref of fieldRefs) {
35
+ const fieldName = ref.slice(2, -2).trim();
36
+ if (fieldName === "FrontSide" ||
37
+ fieldName === "Tags" ||
38
+ fieldName === "Type" ||
39
+ fieldName === "Deck" ||
40
+ fieldName === "Subdeck" ||
41
+ fieldName === "Card" ||
42
+ fieldName.startsWith("cloze:")) {
43
+ continue;
44
+ }
45
+ if (!fieldSet.has(fieldName)) {
46
+ warnings.push(`Template "${template.Name}" references field "{{${fieldName}}}" which is not in inOrderFields`);
47
+ }
48
+ }
49
+ }
50
+ await context.reportProgress({ progress: 30, total: 100 });
51
+ const result = await this.ankiClient.invoke("createModel", {
52
+ modelName,
53
+ inOrderFields,
54
+ cardTemplates,
55
+ css,
56
+ isCloze: isCloze ?? false,
57
+ });
58
+ await context.reportProgress({ progress: 80, total: 100 });
59
+ this.logger.log(`Successfully created model: ${modelName}`);
60
+ await context.reportProgress({ progress: 100, total: 100 });
61
+ const response = {
62
+ success: true,
63
+ modelName,
64
+ modelId: result.id || null,
65
+ fields: inOrderFields,
66
+ templateCount: cardTemplates.length,
67
+ hasCss: !!css,
68
+ isCloze: isCloze || false,
69
+ message: `Successfully created model "${modelName}" with ${inOrderFields.length} fields and ${cardTemplates.length} template(s)`,
70
+ };
71
+ if (warnings.length > 0) {
72
+ response.warnings = warnings;
73
+ response.message +=
74
+ ". Note: Some warnings were detected (see warnings field).";
75
+ }
76
+ return (0, anki_utils_1.createSuccessResponse)(response);
77
+ }
78
+ catch (error) {
79
+ this.logger.error(`Failed to create model ${modelName}`, error);
80
+ const errorMessage = error instanceof Error ? error.message : String(error);
81
+ if (errorMessage.includes("already exists") ||
82
+ errorMessage.includes("duplicate")) {
83
+ return (0, anki_utils_1.createErrorResponse)(error, {
84
+ modelName,
85
+ hint: "A model with this name already exists. Use a different name or use modelNames tool to see existing models.",
86
+ });
87
+ }
88
+ return (0, anki_utils_1.createErrorResponse)(error, {
89
+ modelName,
90
+ hint: "Make sure Anki is running and all parameters are valid.",
91
+ });
92
+ }
93
+ }
94
+ };
95
+ exports.CreateModelTool = CreateModelTool;
96
+ __decorate([
97
+ (0, mcp_nest_1.Tool)({
98
+ name: "createModel",
99
+ description: "Create a new note type (model) in Anki with custom fields, card templates, and styling. " +
100
+ "Useful for creating specialized models like RTL (Right-to-Left) language models for Hebrew, Arabic, etc. " +
101
+ "Each model defines the structure of notes and how cards are generated from them.",
102
+ parameters: zod_1.z.object({
103
+ modelName: zod_1.z
104
+ .string()
105
+ .min(1)
106
+ .describe('Unique name for the new model (e.g., "Basic RTL", "Advanced Vocabulary")'),
107
+ inOrderFields: zod_1.z
108
+ .array(zod_1.z.string().min(1))
109
+ .min(1)
110
+ .describe('Field names in order (e.g., ["Front", "Back"]). At least one field required.'),
111
+ cardTemplates: zod_1.z
112
+ .array(zod_1.z.object({
113
+ Name: zod_1.z.string().min(1).describe('Template name (e.g., "Card 1")'),
114
+ Front: zod_1.z
115
+ .string()
116
+ .min(1)
117
+ .describe('Front template HTML with field placeholders (e.g., "{{Front}}")'),
118
+ Back: zod_1.z
119
+ .string()
120
+ .min(1)
121
+ .describe('Back template HTML with field placeholders (e.g., "{{FrontSide}}<hr id=answer>{{Back}}")'),
122
+ }))
123
+ .min(1)
124
+ .describe("Card templates (at least one required). Each template generates one card per note."),
125
+ css: zod_1.z
126
+ .string()
127
+ .optional()
128
+ .describe('Optional CSS styling for cards. For RTL languages, include "direction: rtl;" in .card class.'),
129
+ isCloze: zod_1.z
130
+ .boolean()
131
+ .optional()
132
+ .default(false)
133
+ .describe("Create as cloze deletion model (default: false)"),
134
+ }),
135
+ }),
136
+ __metadata("design:type", Function),
137
+ __metadata("design:paramtypes", [Object, Object]),
138
+ __metadata("design:returntype", Promise)
139
+ ], CreateModelTool.prototype, "createModel", null);
140
+ exports.CreateModelTool = CreateModelTool = CreateModelTool_1 = __decorate([
141
+ (0, common_1.Injectable)(),
142
+ __metadata("design:paramtypes", [anki_connect_client_1.AnkiConnectClient])
143
+ ], CreateModelTool);
144
+ //# sourceMappingURL=create-model.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-model.tool.js","sourceRoot":"","sources":["../../../../../src/mcp/primitives/essential/tools/create-model.tool.ts"],"names":[],"mappings":"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"}