anki-mcp-http 0.3.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 (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +591 -0
  3. package/bin/ankimcp.js +2 -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 +74 -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 +7 -0
  14. package/dist/cli.js +68 -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 +27 -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 +30 -0
  35. package/dist/mcp/primitives/essential/index.js +125 -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/resources/system-info.resource.d.ts +21 -0
  41. package/dist/mcp/primitives/essential/resources/system-info.resource.js +115 -0
  42. package/dist/mcp/primitives/essential/resources/system-info.resource.js.map +1 -0
  43. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +93 -0
  44. package/dist/mcp/primitives/essential/tools/add-note.tool.js +188 -0
  45. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -0
  46. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +83 -0
  47. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +120 -0
  48. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +1 -0
  49. package/dist/mcp/primitives/essential/tools/create-model.tool.d.ts +88 -0
  50. package/dist/mcp/primitives/essential/tools/create-model.tool.js +142 -0
  51. package/dist/mcp/primitives/essential/tools/create-model.tool.js.map +1 -0
  52. package/dist/mcp/primitives/essential/tools/delete-notes.tool.d.ts +84 -0
  53. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js +120 -0
  54. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js.map +1 -0
  55. package/dist/mcp/primitives/essential/tools/find-notes.tool.d.ts +83 -0
  56. package/dist/mcp/primitives/essential/tools/find-notes.tool.js +106 -0
  57. package/dist/mcp/primitives/essential/tools/find-notes.tool.js.map +1 -0
  58. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.d.ts +84 -0
  59. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js +106 -0
  60. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js.map +1 -0
  61. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +83 -0
  62. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +117 -0
  63. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +1 -0
  64. package/dist/mcp/primitives/essential/tools/model-field-names.tool.d.ts +83 -0
  65. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +116 -0
  66. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -0
  67. package/dist/mcp/primitives/essential/tools/model-names.tool.d.ts +81 -0
  68. package/dist/mcp/primitives/essential/tools/model-names.tool.js +78 -0
  69. package/dist/mcp/primitives/essential/tools/model-names.tool.js.map +1 -0
  70. package/dist/mcp/primitives/essential/tools/model-styling.tool.d.ts +83 -0
  71. package/dist/mcp/primitives/essential/tools/model-styling.tool.js +93 -0
  72. package/dist/mcp/primitives/essential/tools/model-styling.tool.js.map +1 -0
  73. package/dist/mcp/primitives/essential/tools/notes-info.tool.d.ts +83 -0
  74. package/dist/mcp/primitives/essential/tools/notes-info.tool.js +111 -0
  75. package/dist/mcp/primitives/essential/tools/notes-info.tool.js.map +1 -0
  76. package/dist/mcp/primitives/essential/tools/present-card.tool.d.ts +84 -0
  77. package/dist/mcp/primitives/essential/tools/present-card.tool.js +100 -0
  78. package/dist/mcp/primitives/essential/tools/present-card.tool.js.map +1 -0
  79. package/dist/mcp/primitives/essential/tools/rate-card.tool.d.ts +84 -0
  80. package/dist/mcp/primitives/essential/tools/rate-card.tool.js +96 -0
  81. package/dist/mcp/primitives/essential/tools/rate-card.tool.js.map +1 -0
  82. package/dist/mcp/primitives/essential/tools/sync.tool.d.ts +81 -0
  83. package/dist/mcp/primitives/essential/tools/sync.tool.js +61 -0
  84. package/dist/mcp/primitives/essential/tools/sync.tool.js.map +1 -0
  85. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.d.ts +84 -0
  86. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js +119 -0
  87. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js.map +1 -0
  88. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.d.ts +96 -0
  89. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js +154 -0
  90. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js.map +1 -0
  91. package/dist/mcp/primitives/gui/index.d.ts +4 -0
  92. package/dist/mcp/primitives/gui/index.js +26 -0
  93. package/dist/mcp/primitives/gui/index.js.map +1 -0
  94. package/dist/mcp/types/anki.types.d.ts +152 -0
  95. package/dist/mcp/types/anki.types.js +18 -0
  96. package/dist/mcp/types/anki.types.js.map +1 -0
  97. package/dist/mcp/utils/anki.utils.d.ts +19 -0
  98. package/dist/mcp/utils/anki.utils.js +153 -0
  99. package/dist/mcp/utils/anki.utils.js.map +1 -0
  100. package/dist/mcp/utils/mcpb-workarounds.d.ts +1 -0
  101. package/dist/mcp/utils/mcpb-workarounds.js +13 -0
  102. package/dist/mcp/utils/mcpb-workarounds.js.map +1 -0
  103. package/dist/test-fixtures/mock-data.d.ts +126 -0
  104. package/dist/test-fixtures/mock-data.js +112 -0
  105. package/dist/test-fixtures/mock-data.js.map +1 -0
  106. package/dist/test-fixtures/test-helpers.d.ts +12 -0
  107. package/dist/test-fixtures/test-helpers.js +24 -0
  108. package/dist/test-fixtures/test-helpers.js.map +1 -0
  109. package/dist/tsconfig.build.tsbuildinfo +1 -0
  110. package/package.json +153 -0
@@ -0,0 +1,126 @@
1
+ export declare const mockNotes: {
2
+ spanish: {
3
+ noteId: number;
4
+ modelName: string;
5
+ fields: {
6
+ Front: {
7
+ value: string;
8
+ order: number;
9
+ };
10
+ Back: {
11
+ value: string;
12
+ order: number;
13
+ };
14
+ };
15
+ tags: string[];
16
+ cards: number[];
17
+ mod: number;
18
+ };
19
+ japanese: {
20
+ noteId: number;
21
+ modelName: string;
22
+ fields: {
23
+ Front: {
24
+ value: string;
25
+ order: number;
26
+ };
27
+ Back: {
28
+ value: string;
29
+ order: number;
30
+ };
31
+ };
32
+ tags: string[];
33
+ cards: number[];
34
+ mod: number;
35
+ };
36
+ withHtml: {
37
+ noteId: number;
38
+ modelName: string;
39
+ fields: {
40
+ Front: {
41
+ value: string;
42
+ order: number;
43
+ };
44
+ Back: {
45
+ value: string;
46
+ order: number;
47
+ };
48
+ };
49
+ tags: string[];
50
+ cards: number[];
51
+ mod: number;
52
+ };
53
+ };
54
+ export declare const mockDecks: {
55
+ withStats: {
56
+ '1651445861967': {
57
+ deck_id: number;
58
+ name: string;
59
+ new_count: number;
60
+ learn_count: number;
61
+ review_count: number;
62
+ total_in_deck: number;
63
+ };
64
+ '1651445861968': {
65
+ deck_id: number;
66
+ name: string;
67
+ new_count: number;
68
+ learn_count: number;
69
+ review_count: number;
70
+ total_in_deck: number;
71
+ };
72
+ };
73
+ names: string[];
74
+ };
75
+ export declare const mockCards: {
76
+ dueCard: {
77
+ cardId: number;
78
+ noteId: number;
79
+ deckName: string;
80
+ question: string;
81
+ answer: string;
82
+ due: number;
83
+ interval: number;
84
+ factor: number;
85
+ reviews: number;
86
+ lapses: number;
87
+ type: number;
88
+ queue: number;
89
+ modelName: string;
90
+ };
91
+ newCard: {
92
+ cardId: number;
93
+ noteId: number;
94
+ deckName: string;
95
+ question: string;
96
+ answer: string;
97
+ due: number;
98
+ interval: number;
99
+ factor: number;
100
+ reviews: number;
101
+ lapses: number;
102
+ type: number;
103
+ queue: number;
104
+ modelName: string;
105
+ };
106
+ };
107
+ export declare const mockQueries: {
108
+ valid: {
109
+ allDue: string;
110
+ deckSpecific: string;
111
+ withTag: string;
112
+ combined: string;
113
+ frontSearch: string;
114
+ };
115
+ invalid: {
116
+ malformed: string;
117
+ unknownOperator: string;
118
+ };
119
+ };
120
+ export declare const mockErrors: {
121
+ networkError: Error;
122
+ permissionError: Error;
123
+ notFoundError: Error;
124
+ ankiNotRunning: Error;
125
+ invalidQuery: Error;
126
+ };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mockErrors = exports.mockQueries = exports.mockCards = exports.mockDecks = exports.mockNotes = void 0;
4
+ exports.mockNotes = {
5
+ spanish: {
6
+ noteId: 1502298033753,
7
+ modelName: 'Basic',
8
+ fields: {
9
+ 'Front': { value: '¿Cómo estás?', order: 0 },
10
+ 'Back': { value: 'How are you?', order: 1 }
11
+ },
12
+ tags: ['spanish', 'greetings'],
13
+ cards: [1502298033754],
14
+ mod: 1234567890
15
+ },
16
+ japanese: {
17
+ noteId: 1502298033757,
18
+ modelName: 'Basic (and reversed card)',
19
+ fields: {
20
+ 'Front': { value: 'こんにちは', order: 0 },
21
+ 'Back': { value: 'Hello', order: 1 }
22
+ },
23
+ tags: ['japanese', 'greetings'],
24
+ cards: [1502298033758, 1502298033759],
25
+ mod: 1234567890
26
+ },
27
+ withHtml: {
28
+ noteId: 1502298033760,
29
+ modelName: 'Basic',
30
+ fields: {
31
+ 'Front': { value: '<b>Bold text</b> and <i>italic</i>', order: 0 },
32
+ 'Back': { value: '<ul><li>Item 1</li><li>Item 2</li></ul>', order: 1 }
33
+ },
34
+ tags: ['test', 'html'],
35
+ cards: [1502298033761],
36
+ mod: 1234567890
37
+ }
38
+ };
39
+ exports.mockDecks = {
40
+ withStats: {
41
+ '1651445861967': {
42
+ deck_id: 1651445861967,
43
+ name: 'Spanish',
44
+ new_count: 20,
45
+ learn_count: 5,
46
+ review_count: 10,
47
+ total_in_deck: 150
48
+ },
49
+ '1651445861968': {
50
+ deck_id: 1651445861968,
51
+ name: 'Japanese::JLPT N5',
52
+ new_count: 50,
53
+ learn_count: 10,
54
+ review_count: 25,
55
+ total_in_deck: 500
56
+ }
57
+ },
58
+ names: ['Default', 'Spanish', 'Japanese::JLPT N5', 'French::Beginner']
59
+ };
60
+ exports.mockCards = {
61
+ dueCard: {
62
+ cardId: 1502298033754,
63
+ noteId: 1502298033753,
64
+ deckName: 'Spanish',
65
+ question: '¿Cómo estás?',
66
+ answer: 'How are you?',
67
+ due: 1,
68
+ interval: 1,
69
+ factor: 2500,
70
+ reviews: 3,
71
+ lapses: 0,
72
+ type: 2,
73
+ queue: 2,
74
+ modelName: 'Basic'
75
+ },
76
+ newCard: {
77
+ cardId: 1502298033758,
78
+ noteId: 1502298033757,
79
+ deckName: 'Japanese::JLPT N5',
80
+ question: 'こんにちは',
81
+ answer: 'Hello',
82
+ due: 0,
83
+ interval: 0,
84
+ factor: 2500,
85
+ reviews: 0,
86
+ lapses: 0,
87
+ type: 0,
88
+ queue: 0,
89
+ modelName: 'Basic (and reversed card)'
90
+ }
91
+ };
92
+ exports.mockQueries = {
93
+ valid: {
94
+ allDue: 'is:due',
95
+ deckSpecific: 'deck:Spanish',
96
+ withTag: 'tag:greetings',
97
+ combined: 'deck:Spanish tag:spanish',
98
+ frontSearch: 'front:Cómo'
99
+ },
100
+ invalid: {
101
+ malformed: 'deck:',
102
+ unknownOperator: 'invalid:query'
103
+ }
104
+ };
105
+ exports.mockErrors = {
106
+ networkError: new Error('fetch failed'),
107
+ permissionError: new Error('Permission denied'),
108
+ notFoundError: new Error('Note not found'),
109
+ ankiNotRunning: new Error('Cannot connect to Anki. Please ensure Anki is running and AnkiConnect plugin is installed.'),
110
+ invalidQuery: new Error('Invalid query syntax')
111
+ };
112
+ //# sourceMappingURL=mock-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-data.js","sourceRoot":"","sources":["../../src/test-fixtures/mock-data.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare function parseToolResult(result: any): any;
2
+ export declare function createMockContext(): {
3
+ reportProgress: jest.Mock<any, any, any>;
4
+ log: {
5
+ debug: jest.Mock<any, any, any>;
6
+ error: jest.Mock<any, any, any>;
7
+ info: jest.Mock<any, any, any>;
8
+ warn: jest.Mock<any, any, any>;
9
+ };
10
+ mcpServer: any;
11
+ mcpRequest: any;
12
+ };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseToolResult = parseToolResult;
4
+ exports.createMockContext = createMockContext;
5
+ function parseToolResult(result) {
6
+ if (result?.content?.[0]?.text) {
7
+ return JSON.parse(result.content[0].text);
8
+ }
9
+ return result;
10
+ }
11
+ function createMockContext() {
12
+ return {
13
+ reportProgress: jest.fn().mockResolvedValue(undefined),
14
+ log: {
15
+ debug: jest.fn(),
16
+ error: jest.fn(),
17
+ info: jest.fn(),
18
+ warn: jest.fn(),
19
+ },
20
+ mcpServer: {},
21
+ mcpRequest: {},
22
+ };
23
+ }
24
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/test-fixtures/test-helpers.ts"],"names":[],"mappings":";;AAQA,0CAKC;AAKD,8CAYC;AAtBD,SAAgB,eAAe,CAAC,MAAW;IACzC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAKD,SAAgB,iBAAiB;IAC/B,OAAO;QACL,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QACtD,GAAG,EAAE;YACH,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YAChB,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YAChB,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;YACf,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;SAChB;QACD,SAAS,EAAE,EAAS;QACpB,UAAU,EAAE,EAAS;KACtB,CAAC;AACJ,CAAC"}