@ankimcp/anki-mcp-server 0.12.1 → 0.13.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 (55) hide show
  1. package/README.md +53 -5
  2. package/bin/ankimcp.js +16 -0
  3. package/dist/anki-config.service.d.ts +1 -0
  4. package/dist/anki-config.service.js +4 -0
  5. package/dist/anki-config.service.js.map +1 -1
  6. package/dist/cli.d.ts +1 -0
  7. package/dist/cli.js +12 -3
  8. package/dist/cli.js.map +1 -1
  9. package/dist/main-http.js +1 -0
  10. package/dist/main-http.js.map +1 -1
  11. package/dist/main-stdio.js +28 -1
  12. package/dist/main-stdio.js.map +1 -1
  13. package/dist/mcp/clients/anki-connect.client.d.ts +5 -0
  14. package/dist/mcp/clients/anki-connect.client.js +35 -1
  15. package/dist/mcp/clients/anki-connect.client.js.map +1 -1
  16. package/dist/mcp/config/anki-config.interface.d.ts +1 -0
  17. package/dist/mcp/config/anki-config.interface.js.map +1 -1
  18. package/dist/mcp/primitives/essential/index.d.ts +4 -8
  19. package/dist/mcp/primitives/essential/index.js +6 -13
  20. package/dist/mcp/primitives/essential/index.js.map +1 -1
  21. package/dist/mcp/primitives/essential/tools/add-note.tool.js +22 -9
  22. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -1
  23. package/dist/mcp/primitives/essential/tools/deckActions/actions/changeDeck.action.d.ts +12 -0
  24. package/dist/mcp/primitives/essential/tools/deckActions/actions/changeDeck.action.js +24 -0
  25. package/dist/mcp/primitives/essential/tools/deckActions/actions/changeDeck.action.js.map +1 -0
  26. package/dist/mcp/primitives/essential/tools/deckActions/actions/createDeck.action.d.ts +15 -0
  27. package/dist/mcp/primitives/essential/tools/deckActions/actions/createDeck.action.js +44 -0
  28. package/dist/mcp/primitives/essential/tools/deckActions/actions/createDeck.action.js.map +1 -0
  29. package/dist/mcp/primitives/essential/tools/{deck-stats/deck-stats.types.d.ts → deckActions/actions/deckStats.action.d.ts} +5 -2
  30. package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js +78 -0
  31. package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js.map +1 -0
  32. package/dist/mcp/primitives/essential/tools/deckActions/actions/listDecks.action.d.ts +18 -0
  33. package/dist/mcp/primitives/essential/tools/deckActions/actions/listDecks.action.js +63 -0
  34. package/dist/mcp/primitives/essential/tools/deckActions/actions/listDecks.action.js.map +1 -0
  35. package/dist/mcp/primitives/essential/tools/{deck-stats/deck-stats.tool.d.ts → deckActions/deckActions.tool.d.ts} +8 -4
  36. package/dist/mcp/primitives/essential/tools/deckActions/deckActions.tool.js +138 -0
  37. package/dist/mcp/primitives/essential/tools/deckActions/deckActions.tool.js.map +1 -0
  38. package/dist/mcp/primitives/essential/tools/deckActions/index.d.ts +5 -0
  39. package/dist/mcp/primitives/essential/tools/deckActions/index.js +6 -0
  40. package/dist/mcp/primitives/essential/tools/deckActions/index.js.map +1 -0
  41. package/dist/tsconfig.build.tsbuildinfo +1 -1
  42. package/package.json +23 -23
  43. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +0 -105
  44. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +0 -121
  45. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +0 -1
  46. package/dist/mcp/primitives/essential/tools/deck-stats/deck-stats.tool.js +0 -165
  47. package/dist/mcp/primitives/essential/tools/deck-stats/deck-stats.tool.js.map +0 -1
  48. package/dist/mcp/primitives/essential/tools/deck-stats/deck-stats.types.js +0 -3
  49. package/dist/mcp/primitives/essential/tools/deck-stats/deck-stats.types.js.map +0 -1
  50. package/dist/mcp/primitives/essential/tools/deck-stats/index.d.ts +0 -2
  51. package/dist/mcp/primitives/essential/tools/deck-stats/index.js +0 -6
  52. package/dist/mcp/primitives/essential/tools/deck-stats/index.js.map +0 -1
  53. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +0 -105
  54. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +0 -117
  55. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +0 -1
package/README.md CHANGED
@@ -41,8 +41,11 @@ For comprehensive guides, real-world examples, and step-by-step tutorials on usi
41
41
  - `rate_card` - Rate card performance
42
42
 
43
43
  ### Deck Management
44
- - `list_decks` - Show available decks
45
- - `createDeck` - Create new decks
44
+ - `deckActions` - Unified deck operations:
45
+ - `listDecks` - List all decks with optional statistics
46
+ - `createDeck` - Create new decks (max 2 levels: "Parent::Child")
47
+ - `deckStats` - Get comprehensive deck statistics
48
+ - `changeDeck` - Move cards to a different deck
46
49
 
47
50
  ### Note Management
48
51
  - `addNote` - Create new notes
@@ -216,6 +219,7 @@ Options:
216
219
  -h, --host <host> Host to bind to (HTTP mode, default: 127.0.0.1)
217
220
  -a, --anki-connect <url> AnkiConnect URL (default: http://localhost:8765)
218
221
  --ngrok Start ngrok tunnel (requires global ngrok installation)
222
+ --read-only Run in read-only mode (blocks all write operations)
219
223
  --help Show help message
220
224
 
221
225
  Usage with npx (no installation needed):
@@ -223,6 +227,7 @@ Usage with npx (no installation needed):
223
227
  npx @ankimcp/anki-mcp-server --port 8080 # Custom port
224
228
  npx @ankimcp/anki-mcp-server --stdio # STDIO mode
225
229
  npx @ankimcp/anki-mcp-server --ngrok # HTTP mode with ngrok tunnel
230
+ npx @ankimcp/anki-mcp-server --read-only # Read-only mode
226
231
 
227
232
  Usage with global installation:
228
233
  npm install -g @ankimcp/anki-mcp-server # Install once
@@ -230,6 +235,46 @@ Usage with global installation:
230
235
  ankimcp --port 8080 # Custom port
231
236
  ankimcp --stdio # STDIO mode
232
237
  ankimcp --ngrok # HTTP mode with ngrok tunnel
238
+ ankimcp --read-only # Read-only mode
239
+ ```
240
+
241
+ **Read-Only Mode:**
242
+
243
+ The `--read-only` flag prevents any modifications to your Anki collection. When enabled:
244
+ - All read operations work normally (browsing decks, viewing cards, searching notes)
245
+ - Review operations are allowed (sync, answerCards, suspend/unsuspend)
246
+ - Content modifications are blocked (addNote, deleteNotes, createDeck, updateNoteFields, etc.)
247
+ - Useful for safely exploring Anki data without risk of accidental changes
248
+
249
+ ```bash
250
+ # HTTP mode with read-only
251
+ ankimcp --read-only
252
+
253
+ # STDIO mode with read-only
254
+ ankimcp --stdio --read-only
255
+
256
+ # Can combine with other flags
257
+ ankimcp --ngrok --read-only
258
+ ```
259
+
260
+ You can also enable read-only mode via environment variable:
261
+ ```bash
262
+ READ_ONLY=true ankimcp
263
+ ```
264
+
265
+ Or in MCP client configuration:
266
+ ```json
267
+ {
268
+ "mcpServers": {
269
+ "anki-mcp": {
270
+ "command": "npx",
271
+ "args": ["-y", "@ankimcp/anki-mcp-server", "--stdio", "--read-only"],
272
+ "env": {
273
+ "ANKI_CONNECT_URL": "http://localhost:8765"
274
+ }
275
+ }
276
+ }
277
+ }
233
278
  ```
234
279
 
235
280
  **Using with ngrok:**
@@ -321,6 +366,7 @@ For more details, see the [official MCP documentation](https://modelcontextproto
321
366
  | `ANKI_CONNECT_API_VERSION` | API version | `6` |
322
367
  | `ANKI_CONNECT_API_KEY` | API key if configured in AnkiConnect | - |
323
368
  | `ANKI_CONNECT_TIMEOUT` | Request timeout in ms | `5000` |
369
+ | `READ_ONLY` | Enable read-only mode (`true` or `1`) | `false` |
324
370
 
325
371
  ## Usage Examples
326
372
 
@@ -398,14 +444,16 @@ If you see an error like:
398
444
  Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
399
445
  ```
400
446
 
401
- This means your Node.js version is too old. The server requires **Node.js 20.19.0 or later**.
447
+ This means your Node.js version is not supported. The server requires **Node.js 20.19.0+ or 22.12.0+**.
448
+
449
+ > **Note:** Node.js 21.x is not supported. The `require(esm)` feature was added in Node 22 and backported to Node 20.17+, but was never available in Node 21. See [#16](https://github.com/ankimcp/anki-mcp-server/issues/16) for details.
402
450
 
403
451
  **Check your version:**
404
452
  ```bash
405
453
  node --version
406
454
  ```
407
455
 
408
- **Solution:** Update Node.js to version 20.19.0 or later. You can download it from [nodejs.org](https://nodejs.org/) or use a version manager like [nvm](https://github.com/nvm-sh/nvm).
456
+ **Solution:** Update Node.js to version 20.19.0+ or 22.12.0+. You can download it from [nodejs.org](https://nodejs.org/) or use a version manager like [nvm](https://github.com/nvm-sh/nvm).
409
457
 
410
458
  ## Development
411
459
 
@@ -798,4 +846,4 @@ For complete license terms, see the [LICENSE](LICENSE) file.
798
846
 
799
847
  - **Model Context Protocol (MCP)** is an open standard by Anthropic. The MCP logo is from the official [MCP documentation repository](https://github.com/modelcontextprotocol/docs) and is used under the MIT License. For more information about MCP, visit [https://modelcontextprotocol.io](https://modelcontextprotocol.io).
800
848
 
801
- - This is an independent project that bridges Anki and MCP technologies. All trademarks, service marks, trade names, product names, and logos are the property of their respective owners.
849
+ - This is an independent project that bridges Anki and MCP technologies. All trademarks, service marks, trade names, product names, and logos are the property of their respective owners.
package/bin/ankimcp.js CHANGED
@@ -1,5 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Runtime Node.js version check (require(esm) needs Node 20.19+ or 22.12+)
4
+ const [major, minor] = process.versions.node.split('.').map(Number);
5
+ if (
6
+ (major < 20) ||
7
+ (major === 21) ||
8
+ (major === 20 && minor < 19) ||
9
+ (major === 22 && minor < 12)
10
+ ) {
11
+ console.error(
12
+ `Error: Node.js ${process.versions.node} is not supported.\n` +
13
+ 'This package requires Node.js 20.19.0+ or 22.12.0+ (Node 21.x is not supported).\n' +
14
+ 'Download: https://nodejs.org/'
15
+ );
16
+ process.exit(1);
17
+ }
18
+
3
19
  // Check if --stdio flag is present
4
20
  const isStdioMode = process.argv.includes('--stdio');
5
21
 
@@ -7,4 +7,5 @@ export declare class AnkiConfigService implements IAnkiConfig {
7
7
  get ankiConnectApiVersion(): number;
8
8
  get ankiConnectApiKey(): string | undefined;
9
9
  get ankiConnectTimeout(): number;
10
+ get readOnly(): boolean;
10
11
  }
@@ -33,6 +33,10 @@ let AnkiConfigService = class AnkiConfigService {
33
33
  const timeout = this.configService.get("ANKI_CONNECT_TIMEOUT", "5000");
34
34
  return parseInt(timeout, 10);
35
35
  }
36
+ get readOnly() {
37
+ const readOnly = this.configService.get("READ_ONLY", "false");
38
+ return readOnly === "true" || readOnly === "1";
39
+ }
36
40
  };
37
41
  exports.AnkiConfigService = AnkiConfigService;
38
42
  exports.AnkiConfigService = AnkiConfigService = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"anki-config.service.js","sourceRoot":"","sources":["../src/anki-config.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,2CAA+C;AAE/C,mEAAuE;AAMhE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACR;IAApB,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAEpD,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAC3B,kBAAkB,EAClB,uBAAuB,CACxB,CAAC;IACJ,CAAC;IAED,IAAI,qBAAqB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CACpC,0BAA0B,EAC1B,GAAG,CACJ,CAAC;QACF,OAAO,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,iBAAiB;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,sBAAsB,CAAC,CAAC;QACtE,OAAO,IAAA,0CAAuB,EAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,kBAAkB;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CACpC,sBAAsB,EACtB,MAAM,CACP,CAAC;QACF,OAAO,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;CACF,CAAA;AA9BY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAEwB,sBAAa;GADrC,iBAAiB,CA8B7B"}
1
+ {"version":3,"file":"anki-config.service.js","sourceRoot":"","sources":["../src/anki-config.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,2CAA+C;AAE/C,mEAAuE;AAMhE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACR;IAApB,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAEpD,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAC3B,kBAAkB,EAClB,uBAAuB,CACxB,CAAC;IACJ,CAAC;IAED,IAAI,qBAAqB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CACpC,0BAA0B,EAC1B,GAAG,CACJ,CAAC;QACF,OAAO,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,iBAAiB;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,sBAAsB,CAAC,CAAC;QACtE,OAAO,IAAA,0CAAuB,EAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,kBAAkB;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CACpC,sBAAsB,EACtB,MAAM,CACP,CAAC;QACF,OAAO,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,QAAQ;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,EAAE,OAAO,CAAC,CAAC;QACtE,OAAO,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,GAAG,CAAC;IACjD,CAAC;CACF,CAAA;AAnCY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAEwB,sBAAa;GADrC,iBAAiB,CAmC7B"}
package/dist/cli.d.ts CHANGED
@@ -3,6 +3,7 @@ export interface CliOptions {
3
3
  host: string;
4
4
  ankiConnect: string;
5
5
  ngrok: boolean;
6
+ readOnly: boolean;
6
7
  }
7
8
  export declare function checkForUpdates(): void;
8
9
  export declare function parseCliArgs(): CliOptions;
package/dist/cli.js CHANGED
@@ -35,6 +35,7 @@ function parseCliArgs() {
35
35
  .option("-h, --host <address>", "Host to bind to (HTTP mode)", "127.0.0.1")
36
36
  .option("-a, --anki-connect <url>", "AnkiConnect URL", "http://localhost:8765")
37
37
  .option("--ngrok", "Start ngrok tunnel (requires global ngrok installation)")
38
+ .option("--read-only", "Run in read-only mode (blocks all write operations)")
38
39
  .addHelpText("after", `
39
40
  Transport Modes:
40
41
  HTTP Mode (default): For web-based AI assistants (ChatGPT, Claude.ai)
@@ -64,6 +65,10 @@ Examples - STDIO Mode:
64
65
  }
65
66
  }
66
67
 
68
+ Examples - Read-Only Mode:
69
+ $ ankimcp --read-only # HTTP mode, read-only
70
+ $ ankimcp --stdio --read-only # STDIO mode, read-only
71
+
67
72
  Ngrok Setup (one-time):
68
73
  1. Install: npm install -g ngrok
69
74
  2. Get auth token from: https://dashboard.ngrok.com/get-started/your-authtoken
@@ -77,6 +82,7 @@ Ngrok Setup (one-time):
77
82
  host: options.host,
78
83
  ankiConnect: options.ankiConnect,
79
84
  ngrok: options.ngrok || false,
85
+ readOnly: options.readOnly || false,
80
86
  };
81
87
  }
82
88
  function displayStartupBanner(options, ngrokUrl) {
@@ -84,19 +90,22 @@ function displayStartupBanner(options, ngrokUrl) {
84
90
  const title = `AnkiMCP HTTP Server v${version}`;
85
91
  const padding = Math.floor((64 - title.length) / 2);
86
92
  const paddedTitle = " ".repeat(padding) + title + " ".repeat(64 - padding - title.length);
93
+ const readOnlyWarning = options.readOnly
94
+ ? "\n\n** READ-ONLY MODE ENABLED **\nContent modifications (addNote, deleteNotes, createDeck, etc.) are blocked.\nReview operations (sync, answerCards, suspend) remain available."
95
+ : "";
87
96
  console.log(`
88
97
  ╔════════════════════════════════════════════════════════════════╗
89
98
  ║${paddedTitle}║
90
- ╚════════════════════════════════════════════════════════════════╝
99
+ ╚════════════════════════════════════════════════════════════════╝${readOnlyWarning}
91
100
 
92
101
  🚀 Server running on: http://${options.host}:${options.port}
93
- 🔌 AnkiConnect URL: ${options.ankiConnect}${ngrokUrl ? `\n🌐 Ngrok tunnel: ${ngrokUrl}` : ""}
102
+ 🔌 AnkiConnect URL: ${options.ankiConnect}${ngrokUrl ? `\n🌐 Ngrok tunnel: ${ngrokUrl}` : ""}${options.readOnly ? "\n🔒 Mode: Read-only" : ""}
94
103
 
95
104
  Configuration:
96
105
  • Port: ${options.port} (override: --port 8080)
97
106
  • Host: ${options.host} (override: --host 0.0.0.0)
98
107
  • AnkiConnect: ${options.ankiConnect}
99
- (override: --anki-connect http://localhost:8765)${ngrokUrl ? `\n • Ngrok tunnel: ${ngrokUrl}\n • Ngrok dashboard: http://localhost:4040` : ""}
108
+ (override: --anki-connect http://localhost:8765)${options.readOnly ? "\n • Read-only: Yes (write operations blocked)" : ""}${ngrokUrl ? `\n • Ngrok tunnel: ${ngrokUrl}\n • Ngrok dashboard: http://localhost:4040` : ""}
100
109
  ${!ngrokUrl
101
110
  ? `
102
111
  Usage with ngrok:
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;AA0BA,0CAEC;AAED,oCAuEC;AAED,oDAsCC;AA7ID,yCAAoC;AACpC,2BAAkC;AAClC,+BAA4B;AAC5B,sEAA6C;AAS7C,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CACf,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,cAAc,EAAE,CAAC,OAAO,CAAC;AAClC,CAAC;AAED,SAAgB,eAAe;IAC7B,IAAA,yBAAc,EAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AACrD,CAAC;AAED,SAAgB,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,SAAS,CAAC;SACf,WAAW,CAAC,yDAAyD,CAAC;SACtE,OAAO,CAAC,UAAU,EAAE,CAAC;SACrB,MAAM,CACL,SAAS,EACT,6DAA6D,CAC9D;SACA,MAAM,CAAC,qBAAqB,EAAE,+BAA+B,EAAE,MAAM,CAAC;SACtE,MAAM,CAAC,sBAAsB,EAAE,6BAA6B,EAAE,WAAW,CAAC;SAC1E,MAAM,CACL,0BAA0B,EAC1B,iBAAiB,EACjB,uBAAuB,CACxB;SACA,MAAM,CACL,SAAS,EACT,yDAAyD,CAC1D;SACA,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCL,CACI,CAAC;IAEJ,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC3C,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;KAC9B,CAAC;AACJ,CAAC;AAED,SAAgB,oBAAoB,CAClC,OAAmB,EACnB,QAAiB;IAEjB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,wBAAwB,OAAO,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,MAAM,WAAW,GACf,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAExE,OAAO,CAAC,GAAG,CAAC;;GAEX,WAAW;;;+BAGiB,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;wBACnC,OAAO,CAAC,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;;;0BAGzE,OAAO,CAAC,IAAI;0BACZ,OAAO,CAAC,IAAI;0BACZ,OAAO,CAAC,WAAW;0EAC6B,QAAQ,CAAC,CAAC,CAAC,6BAA6B,QAAQ,iDAAiD,CAAC,CAAC,CAAC,EAAE;EAE9K,CAAC,QAAQ;QACP,CAAC,CAAC;;;;;CAKL;QACG,CAAC,CAAC;;IAEF,QAAQ;CAEZ;;CAEC,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/main-http.js CHANGED
@@ -12,6 +12,7 @@ async function bootstrap() {
12
12
  process.env.PORT = options.port.toString();
13
13
  process.env.HOST = options.host;
14
14
  process.env.ANKI_CONNECT_URL = options.ankiConnect;
15
+ process.env.READ_ONLY = options.readOnly ? "true" : "false";
15
16
  const pinoLogger = (0, bootstrap_1.createPinoLogger)(1);
16
17
  const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
17
18
  const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(), {
@@ -1 +1 @@
1
- {"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AACpE,mFAA8E;AAC9E,+BAA4E;AAC5E,4DAAwD;AAExD,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAGnD,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,OAAO,EAAE,EAAE;QACxD,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,IAAI,+CAAqB,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7C,IAAI,QAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAGD,IAAA,0BAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AACpE,mFAA8E;AAC9E,+BAA4E;AAC5E,4DAAwD;AAExD,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAG5D,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,OAAO,EAAE,EAAE;QACxD,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,IAAI,+CAAqB,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7C,IAAI,QAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAGD,IAAA,0BAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -3,14 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@nestjs/core");
4
4
  const app_module_1 = require("./app.module");
5
5
  const bootstrap_1 = require("./bootstrap");
6
+ function parseStdioArgs() {
7
+ const args = process.argv.slice(2);
8
+ let readOnly = false;
9
+ let ankiConnect;
10
+ for (let i = 0; i < args.length; i++) {
11
+ if (args[i] === "--read-only") {
12
+ readOnly = true;
13
+ }
14
+ else if (args[i] === "--anki-connect" || args[i] === "-a") {
15
+ ankiConnect = args[i + 1];
16
+ i++;
17
+ }
18
+ }
19
+ return { readOnly, ankiConnect };
20
+ }
6
21
  async function bootstrap() {
22
+ const cliOptions = parseStdioArgs();
23
+ if (cliOptions.readOnly) {
24
+ process.env.READ_ONLY = "true";
25
+ }
26
+ if (cliOptions.ankiConnect) {
27
+ process.env.ANKI_CONNECT_URL = cliOptions.ankiConnect;
28
+ }
7
29
  const pinoLogger = (0, bootstrap_1.createPinoLogger)(2);
8
30
  const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
9
31
  await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forStdio(), {
10
32
  logger: loggerService,
11
33
  bufferLogs: true,
12
34
  });
13
- pinoLogger.info("MCP STDIO server started successfully");
35
+ if (cliOptions.readOnly) {
36
+ pinoLogger.info("MCP STDIO server started in READ-ONLY mode");
37
+ }
38
+ else {
39
+ pinoLogger.info("MCP STDIO server started successfully");
40
+ }
14
41
  await new Promise(() => { });
15
42
  }
16
43
  bootstrap().catch((err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AAEpE,KAAK,UAAU,SAAS;IAEtB,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,kBAAW,CAAC,wBAAwB,CAAC,sBAAS,CAAC,QAAQ,EAAE,EAAE;QAC/D,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAGzD,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AAMpE,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAA+B,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC9B,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,SAAS;IAEtB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IAGpC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACjC,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,UAAU,CAAC,WAAW,CAAC;IACxD,CAAC;IAGD,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,kBAAW,CAAC,wBAAwB,CAAC,sBAAS,CAAC,QAAQ,EAAE,EAAE;QAC/D,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAGD,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -4,11 +4,16 @@ export declare class AnkiConnectError extends Error {
4
4
  readonly originalError?: string | undefined;
5
5
  constructor(message: string, action?: string | undefined, originalError?: string | undefined);
6
6
  }
7
+ export declare class ReadOnlyModeError extends Error {
8
+ readonly action: string;
9
+ constructor(action: string);
10
+ }
7
11
  export declare class AnkiConnectClient {
8
12
  private readonly config;
9
13
  private readonly client;
10
14
  private readonly apiVersion;
11
15
  private readonly apiKey?;
16
+ private readonly readOnly;
12
17
  private readonly logger;
13
18
  constructor(config: IAnkiConfig);
14
19
  invoke<T = any>(action: string, params?: Record<string, any>): Promise<T>;
@@ -46,10 +46,25 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
46
46
  };
47
47
  var AnkiConnectClient_1;
48
48
  Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.AnkiConnectClient = exports.AnkiConnectError = void 0;
49
+ exports.AnkiConnectClient = exports.ReadOnlyModeError = exports.AnkiConnectError = void 0;
50
50
  const common_1 = require("@nestjs/common");
51
51
  const ky_1 = __importStar(require("ky"));
52
52
  const anki_config_interface_1 = require("../config/anki-config.interface");
53
+ const WRITE_ACTIONS = new Set([
54
+ "addNote",
55
+ "updateNoteFields",
56
+ "deleteNotes",
57
+ "createDeck",
58
+ "changeDeck",
59
+ "addTags",
60
+ "removeTags",
61
+ "clearUnusedTags",
62
+ "replaceTags",
63
+ "storeMediaFile",
64
+ "deleteMediaFile",
65
+ "createModel",
66
+ "updateModelStyling",
67
+ ]);
53
68
  class AnkiConnectError extends Error {
54
69
  action;
55
70
  originalError;
@@ -61,16 +76,28 @@ class AnkiConnectError extends Error {
61
76
  }
62
77
  }
63
78
  exports.AnkiConnectError = AnkiConnectError;
79
+ class ReadOnlyModeError extends Error {
80
+ action;
81
+ constructor(action) {
82
+ super(`Action "${action}" is blocked: server is running in read-only mode. ` +
83
+ `Write operations are disabled. Remove the --read-only flag to enable writes.`);
84
+ this.action = action;
85
+ this.name = "ReadOnlyModeError";
86
+ }
87
+ }
88
+ exports.ReadOnlyModeError = ReadOnlyModeError;
64
89
  let AnkiConnectClient = AnkiConnectClient_1 = class AnkiConnectClient {
65
90
  config;
66
91
  client;
67
92
  apiVersion;
68
93
  apiKey;
94
+ readOnly;
69
95
  logger = new common_1.Logger(AnkiConnectClient_1.name);
70
96
  constructor(config) {
71
97
  this.config = config;
72
98
  this.apiVersion = config.ankiConnectApiVersion;
73
99
  this.apiKey = config.ankiConnectApiKey;
100
+ this.readOnly = config.readOnly ?? false;
74
101
  this.client = ky_1.default.create({
75
102
  prefixUrl: config.ankiConnectUrl,
76
103
  timeout: config.ankiConnectTimeout,
@@ -98,6 +125,10 @@ let AnkiConnectClient = AnkiConnectClient_1 = class AnkiConnectClient {
98
125
  });
99
126
  }
100
127
  async invoke(action, params) {
128
+ if (this.readOnly && WRITE_ACTIONS.has(action)) {
129
+ this.logger.warn(`Blocked write action "${action}" in read-only mode`);
130
+ throw new ReadOnlyModeError(action);
131
+ }
101
132
  const request = {
102
133
  action,
103
134
  version: this.apiVersion,
@@ -120,6 +151,9 @@ let AnkiConnectClient = AnkiConnectClient_1 = class AnkiConnectClient {
120
151
  return response.result;
121
152
  }
122
153
  catch (error) {
154
+ if (error instanceof ReadOnlyModeError) {
155
+ throw error;
156
+ }
123
157
  if (error instanceof ky_1.HTTPError) {
124
158
  if (error.response.status === 403) {
125
159
  throw new AnkiConnectError("Permission denied. Please check AnkiConnect configuration and API key.", action);
@@ -1 +1 @@
1
- {"version":3,"file":"anki-connect.client.js","sourceRoot":"","sources":["../../../src/mcp/clients/anki-connect.client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anki-connect.client.js","sourceRoot":"","sources":["../../../src/mcp/clients/anki-connect.client.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,6 @@ export interface IAnkiConfig {
3
3
  ankiConnectApiVersion: number;
4
4
  ankiConnectApiKey?: string;
5
5
  ankiConnectTimeout: number;
6
+ readOnly?: boolean;
6
7
  }
7
8
  export declare const ANKI_CONFIG: unique symbol;
@@ -1 +1 @@
1
- {"version":3,"file":"anki-config.interface.js","sourceRoot":"","sources":["../../../src/mcp/config/anki-config.interface.ts"],"names":[],"mappings":";;;AAgCa,QAAA,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC"}
1
+ {"version":3,"file":"anki-config.interface.js","sourceRoot":"","sources":["../../../src/mcp/config/anki-config.interface.ts"],"names":[],"mappings":";;;AAsCa,QAAA,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC"}
@@ -2,10 +2,8 @@ export { ANKI_CONFIG } from "../../config/anki-config.interface";
2
2
  export type { IAnkiConfig } from "../../config/anki-config.interface";
3
3
  export * from "../../types/anki.types";
4
4
  export * from "../../utils/anki.utils";
5
- export { AnkiConnectClient, AnkiConnectError, } from "../../clients/anki-connect.client";
5
+ export { AnkiConnectClient, AnkiConnectError, ReadOnlyModeError, } from "../../clients/anki-connect.client";
6
6
  export { SyncTool } from "./tools/sync.tool";
7
- export { ListDecksTool } from "./tools/list-decks.tool";
8
- export { CreateDeckTool } from "./tools/create-deck.tool";
9
7
  export { GetDueCardsTool } from "./tools/get-due-cards.tool";
10
8
  export { GetCardsTool } from "./tools/get-cards.tool";
11
9
  export { PresentCardTool } from "./tools/present-card.tool";
@@ -23,7 +21,7 @@ export { DeleteNotesTool } from "./tools/delete-notes.tool";
23
21
  export { MediaActionsTool } from "./tools/mediaActions";
24
22
  export { GetTagsTool } from "./tools/get-tags.tool";
25
23
  export { TagActionsTool } from "./tools/tagActions";
26
- export { DeckStatsTool } from "./tools/deck-stats";
24
+ export { DeckActionsTool } from "./tools/deckActions";
27
25
  export { CollectionStatsTool } from "./tools/collection-stats";
28
26
  export { ReviewStatsTool } from "./tools/review-stats";
29
27
  export { ReviewSessionPrompt } from "./prompts/review-session.prompt";
@@ -31,8 +29,6 @@ export { TwentyRulesPrompt } from "./prompts/twenty-rules.prompt";
31
29
  export { SystemInfoResource } from "./resources/system-info.resource";
32
30
  import { DynamicModule, Provider } from "@nestjs/common";
33
31
  import { SyncTool } from "./tools/sync.tool";
34
- import { ListDecksTool } from "./tools/list-decks.tool";
35
- import { CreateDeckTool } from "./tools/create-deck.tool";
36
32
  import { GetDueCardsTool } from "./tools/get-due-cards.tool";
37
33
  import { GetCardsTool } from "./tools/get-cards.tool";
38
34
  import { PresentCardTool } from "./tools/present-card.tool";
@@ -50,13 +46,13 @@ import { DeleteNotesTool } from "./tools/delete-notes.tool";
50
46
  import { MediaActionsTool } from "./tools/mediaActions";
51
47
  import { GetTagsTool } from "./tools/get-tags.tool";
52
48
  import { TagActionsTool } from "./tools/tagActions";
53
- import { DeckStatsTool } from "./tools/deck-stats";
49
+ import { DeckActionsTool } from "./tools/deckActions";
54
50
  import { CollectionStatsTool } from "./tools/collection-stats";
55
51
  import { ReviewStatsTool } from "./tools/review-stats";
56
52
  import { ReviewSessionPrompt } from "./prompts/review-session.prompt";
57
53
  import { TwentyRulesPrompt } from "./prompts/twenty-rules.prompt";
58
54
  import { SystemInfoResource } from "./resources/system-info.resource";
59
- export declare const ESSENTIAL_MCP_TOOLS: (typeof SyncTool | typeof ListDecksTool | typeof CreateDeckTool | typeof GetDueCardsTool | typeof GetCardsTool | typeof PresentCardTool | typeof RateCardTool | typeof ModelNamesTool | typeof ModelFieldNamesTool | typeof ModelStylingTool | typeof CreateModelTool | typeof UpdateModelStylingTool | typeof AddNoteTool | typeof FindNotesTool | typeof NotesInfoTool | typeof UpdateNoteFieldsTool | typeof DeleteNotesTool | typeof MediaActionsTool | typeof GetTagsTool | typeof TagActionsTool | typeof DeckStatsTool | typeof CollectionStatsTool | typeof ReviewStatsTool | typeof ReviewSessionPrompt | typeof TwentyRulesPrompt | typeof SystemInfoResource)[];
55
+ export declare const ESSENTIAL_MCP_TOOLS: (typeof SyncTool | typeof GetDueCardsTool | typeof GetCardsTool | typeof PresentCardTool | typeof RateCardTool | typeof ModelNamesTool | typeof ModelFieldNamesTool | typeof ModelStylingTool | typeof CreateModelTool | typeof UpdateModelStylingTool | typeof AddNoteTool | typeof FindNotesTool | typeof NotesInfoTool | typeof UpdateNoteFieldsTool | typeof DeleteNotesTool | typeof MediaActionsTool | typeof GetTagsTool | typeof TagActionsTool | typeof DeckActionsTool | typeof CollectionStatsTool | typeof ReviewStatsTool | typeof ReviewSessionPrompt | typeof TwentyRulesPrompt | typeof SystemInfoResource)[];
60
56
  export interface McpPrimitivesAnkiEssentialModuleOptions {
61
57
  ankiConfigProvider: Provider;
62
58
  }
@@ -21,7 +21,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  };
22
22
  var McpPrimitivesAnkiEssentialModule_1;
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.McpPrimitivesAnkiEssentialModule = exports.ESSENTIAL_MCP_TOOLS = exports.SystemInfoResource = exports.TwentyRulesPrompt = exports.ReviewSessionPrompt = exports.ReviewStatsTool = exports.CollectionStatsTool = exports.DeckStatsTool = exports.TagActionsTool = exports.GetTagsTool = exports.MediaActionsTool = exports.DeleteNotesTool = exports.UpdateNoteFieldsTool = exports.NotesInfoTool = exports.FindNotesTool = exports.AddNoteTool = exports.UpdateModelStylingTool = exports.CreateModelTool = exports.ModelStylingTool = exports.ModelFieldNamesTool = exports.ModelNamesTool = exports.RateCardTool = exports.PresentCardTool = exports.GetCardsTool = exports.GetDueCardsTool = exports.CreateDeckTool = exports.ListDecksTool = exports.SyncTool = exports.AnkiConnectError = exports.AnkiConnectClient = exports.ANKI_CONFIG = void 0;
24
+ exports.McpPrimitivesAnkiEssentialModule = exports.ESSENTIAL_MCP_TOOLS = exports.SystemInfoResource = exports.TwentyRulesPrompt = exports.ReviewSessionPrompt = exports.ReviewStatsTool = exports.CollectionStatsTool = exports.DeckActionsTool = exports.TagActionsTool = exports.GetTagsTool = exports.MediaActionsTool = exports.DeleteNotesTool = exports.UpdateNoteFieldsTool = exports.NotesInfoTool = exports.FindNotesTool = exports.AddNoteTool = exports.UpdateModelStylingTool = exports.CreateModelTool = exports.ModelStylingTool = exports.ModelFieldNamesTool = exports.ModelNamesTool = exports.RateCardTool = exports.PresentCardTool = exports.GetCardsTool = exports.GetDueCardsTool = exports.SyncTool = exports.ReadOnlyModeError = exports.AnkiConnectError = exports.AnkiConnectClient = exports.ANKI_CONFIG = void 0;
25
25
  var anki_config_interface_1 = require("../../config/anki-config.interface");
26
26
  Object.defineProperty(exports, "ANKI_CONFIG", { enumerable: true, get: function () { return anki_config_interface_1.ANKI_CONFIG; } });
27
27
  __exportStar(require("../../types/anki.types"), exports);
@@ -29,12 +29,9 @@ __exportStar(require("../../utils/anki.utils"), exports);
29
29
  var anki_connect_client_1 = require("../../clients/anki-connect.client");
30
30
  Object.defineProperty(exports, "AnkiConnectClient", { enumerable: true, get: function () { return anki_connect_client_1.AnkiConnectClient; } });
31
31
  Object.defineProperty(exports, "AnkiConnectError", { enumerable: true, get: function () { return anki_connect_client_1.AnkiConnectError; } });
32
+ Object.defineProperty(exports, "ReadOnlyModeError", { enumerable: true, get: function () { return anki_connect_client_1.ReadOnlyModeError; } });
32
33
  var sync_tool_1 = require("./tools/sync.tool");
33
34
  Object.defineProperty(exports, "SyncTool", { enumerable: true, get: function () { return sync_tool_1.SyncTool; } });
34
- var list_decks_tool_1 = require("./tools/list-decks.tool");
35
- Object.defineProperty(exports, "ListDecksTool", { enumerable: true, get: function () { return list_decks_tool_1.ListDecksTool; } });
36
- var create_deck_tool_1 = require("./tools/create-deck.tool");
37
- Object.defineProperty(exports, "CreateDeckTool", { enumerable: true, get: function () { return create_deck_tool_1.CreateDeckTool; } });
38
35
  var get_due_cards_tool_1 = require("./tools/get-due-cards.tool");
39
36
  Object.defineProperty(exports, "GetDueCardsTool", { enumerable: true, get: function () { return get_due_cards_tool_1.GetDueCardsTool; } });
40
37
  var get_cards_tool_1 = require("./tools/get-cards.tool");
@@ -69,8 +66,8 @@ var get_tags_tool_1 = require("./tools/get-tags.tool");
69
66
  Object.defineProperty(exports, "GetTagsTool", { enumerable: true, get: function () { return get_tags_tool_1.GetTagsTool; } });
70
67
  var tagActions_1 = require("./tools/tagActions");
71
68
  Object.defineProperty(exports, "TagActionsTool", { enumerable: true, get: function () { return tagActions_1.TagActionsTool; } });
72
- var deck_stats_1 = require("./tools/deck-stats");
73
- Object.defineProperty(exports, "DeckStatsTool", { enumerable: true, get: function () { return deck_stats_1.DeckStatsTool; } });
69
+ var deckActions_1 = require("./tools/deckActions");
70
+ Object.defineProperty(exports, "DeckActionsTool", { enumerable: true, get: function () { return deckActions_1.DeckActionsTool; } });
74
71
  var collection_stats_1 = require("./tools/collection-stats");
75
72
  Object.defineProperty(exports, "CollectionStatsTool", { enumerable: true, get: function () { return collection_stats_1.CollectionStatsTool; } });
76
73
  var review_stats_1 = require("./tools/review-stats");
@@ -84,8 +81,6 @@ Object.defineProperty(exports, "SystemInfoResource", { enumerable: true, get: fu
84
81
  const common_1 = require("@nestjs/common");
85
82
  const anki_connect_client_2 = require("../../clients/anki-connect.client");
86
83
  const sync_tool_2 = require("./tools/sync.tool");
87
- const list_decks_tool_2 = require("./tools/list-decks.tool");
88
- const create_deck_tool_2 = require("./tools/create-deck.tool");
89
84
  const get_due_cards_tool_2 = require("./tools/get-due-cards.tool");
90
85
  const get_cards_tool_2 = require("./tools/get-cards.tool");
91
86
  const present_card_tool_2 = require("./tools/present-card.tool");
@@ -103,7 +98,7 @@ const delete_notes_tool_2 = require("./tools/delete-notes.tool");
103
98
  const mediaActions_2 = require("./tools/mediaActions");
104
99
  const get_tags_tool_2 = require("./tools/get-tags.tool");
105
100
  const tagActions_2 = require("./tools/tagActions");
106
- const deck_stats_2 = require("./tools/deck-stats");
101
+ const deckActions_2 = require("./tools/deckActions");
107
102
  const collection_stats_2 = require("./tools/collection-stats");
108
103
  const review_stats_2 = require("./tools/review-stats");
109
104
  const review_session_prompt_2 = require("./prompts/review-session.prompt");
@@ -111,8 +106,6 @@ const twenty_rules_prompt_2 = require("./prompts/twenty-rules.prompt");
111
106
  const system_info_resource_2 = require("./resources/system-info.resource");
112
107
  exports.ESSENTIAL_MCP_TOOLS = [
113
108
  sync_tool_2.SyncTool,
114
- list_decks_tool_2.ListDecksTool,
115
- create_deck_tool_2.CreateDeckTool,
116
109
  get_due_cards_tool_2.GetDueCardsTool,
117
110
  get_cards_tool_2.GetCardsTool,
118
111
  present_card_tool_2.PresentCardTool,
@@ -130,7 +123,7 @@ exports.ESSENTIAL_MCP_TOOLS = [
130
123
  mediaActions_2.MediaActionsTool,
131
124
  get_tags_tool_2.GetTagsTool,
132
125
  tagActions_2.TagActionsTool,
133
- deck_stats_2.DeckStatsTool,
126
+ deckActions_2.DeckActionsTool,
134
127
  collection_stats_2.CollectionStatsTool,
135
128
  review_stats_2.ReviewStatsTool,
136
129
  review_session_prompt_2.ReviewSessionPrompt,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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"}
@@ -24,16 +24,29 @@ let AddNoteTool = AddNoteTool_1 = class AddNoteTool {
24
24
  }
25
25
  async addNote({ deckName, modelName, fields, tags, allowDuplicate, duplicateScope, duplicateScopeOptions, }, context) {
26
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,
27
+ this.logger.log(`Adding note to deck "${deckName}" with model "${modelName}"`);
28
+ await context.reportProgress({ progress: 20, total: 100 });
29
+ const fieldNames = await this.ankiClient.invoke("modelFieldNames", {
30
+ modelName: modelName,
31
+ });
32
+ if (!fieldNames || fieldNames.length === 0) {
33
+ return (0, anki_utils_1.createErrorResponse)(new Error(`Model "${modelName}" not found or has no fields`), {
31
34
  modelName,
32
- emptyFields: emptyFields.map(([key]) => key),
35
+ hint: "Use modelNames tool to see available models",
33
36
  });
34
37
  }
35
- this.logger.log(`Adding note to deck "${deckName}" with model "${modelName}"`);
36
- await context.reportProgress({ progress: 25, total: 100 });
38
+ await context.reportProgress({ progress: 35, total: 100 });
39
+ const sortField = fieldNames[0];
40
+ const sortFieldValue = fields[sortField];
41
+ if (!sortFieldValue || sortFieldValue.trim() === "") {
42
+ return (0, anki_utils_1.createErrorResponse)(new Error(`The first field "${sortField}" cannot be empty. Anki requires the sort field to have content.`), {
43
+ modelName,
44
+ sortField,
45
+ providedFields: Object.keys(fields),
46
+ hint: `The first field "${sortField}" is the sort field and must contain non-empty content.`,
47
+ });
48
+ }
49
+ await context.reportProgress({ progress: 50, total: 100 });
37
50
  const noteParams = {
38
51
  deckName: deckName,
39
52
  modelName: modelName,
@@ -59,11 +72,11 @@ let AddNoteTool = AddNoteTool_1 = class AddNoteTool {
59
72
  if (hasOptions) {
60
73
  noteParams.options = options;
61
74
  }
62
- await context.reportProgress({ progress: 50, total: 100 });
75
+ await context.reportProgress({ progress: 60, total: 100 });
63
76
  const noteId = await this.ankiClient.invoke("addNote", {
64
77
  note: noteParams,
65
78
  });
66
- await context.reportProgress({ progress: 75, total: 100 });
79
+ await context.reportProgress({ progress: 80, total: 100 });
67
80
  if (!noteId) {
68
81
  this.logger.warn("Note creation failed - possibly a duplicate");
69
82
  await context.reportProgress({ progress: 100, total: 100 });