@fredrika/mcp-mochi 1.0.5 → 1.0.6-beta.1

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.
package/README.md CHANGED
@@ -5,126 +5,149 @@ This MCP server provides integration with the Mochi flashcard system, allowing y
5
5
  ## Features
6
6
 
7
7
  - Create, update, and delete flashcards
8
+ - Create cards from templates with automatic field name-to-ID mapping
9
+ - Add attachments (images, audio) to cards
10
+ - Get cards due for review
8
11
  - List flashcards, decks, and templates
9
12
 
10
- ## Setup
13
+ ## Usage with Claude Desktop
14
+
15
+ Add the following to your `claude_desktop_config.json`:
16
+
17
+ ### NPX (recommended)
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "mochi": {
23
+ "command": "npx",
24
+ "args": ["-y", "@fredrika/mcp-mochi"],
25
+ "env": {
26
+ "MOCHI_API_KEY": "<YOUR_TOKEN>"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### Local Development
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "mochi": {
39
+ "command": "node",
40
+ "args": ["/path/to/mcp-mochi/dist/index.js"],
41
+ "env": {
42
+ "MOCHI_API_KEY": "<YOUR_TOKEN>"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Local Development Setup
11
50
 
12
- 1. Install dependencies:
51
+ 1. Clone and install dependencies:
13
52
  ```bash
53
+ git clone https://github.com/fredrika/mcp-mochi.git
54
+ cd mcp-mochi
14
55
  npm install
15
56
  ```
16
57
 
17
- 2. Configure your Mochi API token:
18
- - Copy `.env.example` to `.env`
19
- - Replace `your_mochi_api_token_here` with your actual Mochi API token
20
-
21
- 3. Build the project:
58
+ 2. Build the project:
22
59
  ```bash
23
60
  npm run build
24
61
  ```
25
62
 
26
- 4. Start the server:
63
+ 3. Test with MCP Inspector:
27
64
  ```bash
28
- npm start
65
+ MOCHI_API_KEY=<YOUR_TOKEN> npx @modelcontextprotocol/inspector node dist/index.js
29
66
  ```
30
67
 
31
68
  ## Available Tools
32
69
 
33
- ### `mochi_create_card`
70
+ ### `mochi_create_flashcard`
34
71
  Create a new flashcard in Mochi.
35
- - Parameters:
36
- - `content`: string (Markdown content of the card. Separate front and back using a horizontal rule `---`)
37
- - `deck-id`: string (ID of the deck to create the card in)
38
- - `template-id`: string (optional, template to use for the card)
39
- - `manual-tags`: string[] (optional, tags to add to the card)
40
- - `fields`: object (map of field IDs to field values, required if using a template)
41
-
42
- ### `mochi_update_card`
43
- Update or delete an existing flashcard in Mochi. To delete, set `trashed` to true.
44
- - Parameters:
45
- - `card-id`: string (ID of the card to update)
46
- - Any updatable card fields (see code for all options)
47
- - To delete: set `trashed?` to `'true'` (string)
48
-
49
- ### `mochi_list_cards`
50
- List cards (paginated).
51
- - Parameters:
52
- - `deck-id`: string (optional, filter by deck)
53
- - `limit`: number (optional, 1-100)
54
- - `bookmark`: string (optional, for pagination)
72
+ - `content`: Markdown content (separate front/back with `---`)
73
+ - `deck-id`: ID of the deck (use `mochi_list_decks` to find)
74
+ - `template-id`: (optional) Template to use
75
+ - `fields`: (optional) Map of field IDs to values (required with template)
76
+ - `manual-tags`: (optional) Array of tags
77
+
78
+ ### `mochi_create_card_from_template`
79
+ Create a flashcard using a template with field **names** (not IDs). The MCP automatically maps names to IDs.
80
+ - `template-id`: Template ID (use `mochi_list_templates` to find)
81
+ - `deck-id`: Deck ID
82
+ - `fields`: Map of field names to values (e.g., `{"Front": "Question?", "Back": "Answer"}`)
83
+ - `manual-tags`: (optional) Array of tags
84
+
85
+ ### `mochi_update_flashcard`
86
+ Update or delete a flashcard. Set `trashed?` to `true` to delete.
87
+ - `card-id`: ID of the card to update
88
+ - Any updatable card fields
89
+
90
+ ### `mochi_add_attachment`
91
+ Add an attachment (image, audio, etc.) to a card using base64 data.
92
+ - `card-id`: ID of the card
93
+ - `data`: Base64-encoded file data
94
+ - `filename`: Filename with extension (e.g., `image.png`)
95
+ - `content-type`: (optional) MIME type (inferred from filename if omitted)
96
+
97
+ ### `mochi_list_flashcards`
98
+ List flashcards (paginated).
99
+ - `deck-id`: (optional) Filter by deck
100
+ - `limit`: (optional) 1-100
101
+ - `bookmark`: (optional) Pagination token
55
102
 
56
103
  ### `mochi_list_decks`
57
104
  List all decks.
58
- - Parameters:
59
- - `bookmark`: string (optional, for pagination)
105
+ - `bookmark`: (optional) Pagination token
60
106
 
61
107
  ### `mochi_list_templates`
62
- List all templates.
63
- - Parameters:
64
- - `bookmark`: string (optional, for pagination)
65
-
66
- ## Example Usage
108
+ List all templates with their field definitions.
109
+ - `bookmark`: (optional) Pagination token
67
110
 
68
- Here's how to use the MCP server with the MCP Inspector:
69
-
70
- 1. Start the server:
71
- ```bash
72
- npm start
73
- ```
111
+ ### `mochi_get_due_cards`
112
+ Get flashcards due for review.
113
+ - `deck-id`: (optional) Filter by deck
114
+ - `date`: (optional) ISO 8601 date (defaults to today)
74
115
 
75
- 2. In another terminal, use the MCP Inspector to interact with the server:
76
- ```bash
77
- mcp-inspector
78
- ```
116
+ ## Examples
79
117
 
80
- 3. Create a new flashcard:
81
- ```json
82
- {
83
- "tool": "mochi_create_card",
84
- "params": {
85
- "content": "What is MCP?\n---\nModel Context Protocol - a protocol for providing context to LLMs",
86
- "deck-id": "<YOUR_DECK_ID>"
87
- }
88
- }
89
- ```
118
+ ### Create a simple flashcard
90
119
 
91
- 4. List all decks:
92
- ```json
93
- {
94
- "tool": "mochi_list_decks",
95
- "params": {}
96
- }
97
- ```
98
-
99
- 5. Delete a flashcard (set `trashed` to true via update):
100
- ```json
101
- {
102
- "tool": "mochi_update_card",
103
- "params": {
104
- "card-id": "<CARD_ID>",
105
- "trashed?": "true"
106
- }
107
- }
108
- ```
109
-
110
- ## Usage with Claude Desktop
111
- To use this with Claude Desktop, add the following to your `claude_desktop_config.json`:
120
+ ```json
121
+ {
122
+ "tool": "mochi_create_flashcard",
123
+ "params": {
124
+ "content": "What is MCP?\n---\nModel Context Protocol - a protocol for providing context to LLMs",
125
+ "deck-id": "<DECK_ID>"
126
+ }
127
+ }
128
+ ```
112
129
 
113
- ### NPX
130
+ ### Create a card from template
114
131
 
115
132
  ```json
116
133
  {
117
- "mcpServers": {
118
- "mochi": {
119
- "command": "npx",
120
- "args": [
121
- "-y",
122
- "@fredrika/mcp-mochi"
123
- ],
124
- "env": {
125
- "MOCHI_API_KEY": "<YOUR_TOKEN>"
126
- }
134
+ "tool": "mochi_create_card_from_template",
135
+ "params": {
136
+ "template-id": "<TEMPLATE_ID>",
137
+ "deck-id": "<DECK_ID>",
138
+ "fields": {
139
+ "Front": "What is the capital of France?",
140
+ "Back": "Paris"
127
141
  }
128
142
  }
129
143
  }
130
144
  ```
145
+
146
+ ### Get today's due cards
147
+
148
+ ```json
149
+ {
150
+ "tool": "mochi_get_due_cards",
151
+ "params": {}
152
+ }
153
+ ```
package/dist/index.d.ts CHANGED
@@ -2,102 +2,69 @@
2
2
  import { z } from "zod";
3
3
  declare const CreateCardRequestSchema: z.ZodObject<{
4
4
  content: z.ZodString;
5
- "deck-id": z.ZodString;
6
- "template-id": z.ZodDefault<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
7
- "manual-tags": z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5
+ deckId: z.ZodString;
6
+ templateId: z.ZodDefault<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
7
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
8
8
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
9
9
  id: z.ZodString;
10
10
  value: z.ZodString;
11
- }, "strip", z.ZodTypeAny, {
12
- id: string;
13
- value: string;
14
- }, {
15
- id: string;
16
- value: string;
17
- }>>>;
18
- }, "strip", z.ZodTypeAny, {
19
- content: string;
20
- "deck-id": string;
21
- "template-id": string | null;
22
- "manual-tags"?: string[] | undefined;
23
- fields?: Record<string, {
24
- id: string;
25
- value: string;
26
- }> | undefined;
27
- }, {
28
- content: string;
29
- "deck-id": string;
30
- "template-id"?: string | null | undefined;
31
- "manual-tags"?: string[] | undefined;
32
- fields?: Record<string, {
33
- id: string;
34
- value: string;
35
- }> | undefined;
36
- }>;
11
+ }, z.core.$strip>>>;
12
+ }, z.core.$strip>;
37
13
  declare const UpdateCardRequestSchema: z.ZodObject<{
38
14
  content: z.ZodOptional<z.ZodString>;
39
- "deck-id": z.ZodOptional<z.ZodString>;
40
- "template-id": z.ZodOptional<z.ZodString>;
41
- "archived?": z.ZodOptional<z.ZodBoolean>;
42
- "trashed?": z.ZodOptional<z.ZodString>;
15
+ deckId: z.ZodOptional<z.ZodString>;
16
+ templateId: z.ZodOptional<z.ZodString>;
17
+ archived: z.ZodOptional<z.ZodBoolean>;
18
+ trashed: z.ZodOptional<z.ZodBoolean>;
43
19
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
44
20
  id: z.ZodString;
45
21
  value: z.ZodString;
46
- }, "strip", z.ZodTypeAny, {
47
- id: string;
48
- value: string;
49
- }, {
50
- id: string;
51
- value: string;
52
- }>>>;
53
- }, "strip", z.ZodTypeAny, {
54
- content?: string | undefined;
55
- "deck-id"?: string | undefined;
56
- "template-id"?: string | undefined;
57
- fields?: Record<string, {
58
- id: string;
59
- value: string;
60
- }> | undefined;
61
- "archived?"?: boolean | undefined;
62
- "trashed?"?: string | undefined;
63
- }, {
64
- content?: string | undefined;
65
- "deck-id"?: string | undefined;
66
- "template-id"?: string | undefined;
67
- fields?: Record<string, {
68
- id: string;
69
- value: string;
70
- }> | undefined;
71
- "archived?"?: boolean | undefined;
72
- "trashed?"?: string | undefined;
73
- }>;
22
+ }, z.core.$strip>>>;
23
+ }, z.core.$strip>;
74
24
  declare const ListDecksParamsSchema: z.ZodObject<{
75
25
  bookmark: z.ZodOptional<z.ZodString>;
76
- }, "strip", z.ZodTypeAny, {
77
- bookmark?: string | undefined;
78
- }, {
79
- bookmark?: string | undefined;
80
- }>;
26
+ }, z.core.$strip>;
81
27
  declare const ListCardsParamsSchema: z.ZodObject<{
82
- "deck-id": z.ZodOptional<z.ZodString>;
28
+ deckId: z.ZodOptional<z.ZodString>;
83
29
  limit: z.ZodOptional<z.ZodNumber>;
84
30
  bookmark: z.ZodOptional<z.ZodString>;
85
- }, "strip", z.ZodTypeAny, {
86
- "deck-id"?: string | undefined;
87
- bookmark?: string | undefined;
88
- limit?: number | undefined;
89
- }, {
90
- "deck-id"?: string | undefined;
91
- bookmark?: string | undefined;
92
- limit?: number | undefined;
93
- }>;
31
+ }, z.core.$strip>;
94
32
  declare const ListTemplatesParamsSchema: z.ZodObject<{
95
33
  bookmark: z.ZodOptional<z.ZodString>;
96
- }, "strip", z.ZodTypeAny, {
97
- bookmark?: string | undefined;
98
- }, {
99
- bookmark?: string | undefined;
100
- }>;
34
+ }, z.core.$strip>;
35
+ declare const GetDueCardsParamsSchema: z.ZodObject<{
36
+ deckId: z.ZodOptional<z.ZodString>;
37
+ date: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>;
39
+ declare const CreateCardFromTemplateSchema: z.ZodObject<{
40
+ templateId: z.ZodString;
41
+ deckId: z.ZodString;
42
+ fields: z.ZodRecord<z.ZodString, z.ZodString>;
43
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
44
+ }, z.core.$strip>;
45
+ declare const AddAttachmentSchema: z.ZodObject<{
46
+ cardId: z.ZodString;
47
+ data: z.ZodString;
48
+ filename: z.ZodString;
49
+ contentType: z.ZodOptional<z.ZodString>;
50
+ }, z.core.$strip>;
51
+ type AddAttachmentRequest = z.infer<typeof AddAttachmentSchema>;
52
+ declare const TemplateSchema: z.ZodObject<{
53
+ id: z.ZodString;
54
+ name: z.ZodString;
55
+ content: z.ZodString;
56
+ pos: z.ZodString;
57
+ fields: z.ZodRecord<z.ZodString, z.ZodObject<{
58
+ id: z.ZodString;
59
+ name: z.ZodString;
60
+ pos: z.ZodString;
61
+ type: z.ZodNullable<z.ZodOptional<z.ZodString>>;
62
+ source: z.ZodNullable<z.ZodOptional<z.ZodString>>;
63
+ options: z.ZodOptional<z.ZodObject<{
64
+ "multi-line?": z.ZodOptional<z.ZodBoolean>;
65
+ }, z.core.$loose>>;
66
+ }, z.core.$strip>>;
67
+ }, z.core.$strip>;
101
68
  declare const ListTemplatesResponseSchema: z.ZodObject<{
102
69
  bookmark: z.ZodString;
103
70
  docs: z.ZodArray<z.ZodObject<{
@@ -109,161 +76,41 @@ declare const ListTemplatesResponseSchema: z.ZodObject<{
109
76
  id: z.ZodString;
110
77
  name: z.ZodString;
111
78
  pos: z.ZodString;
79
+ type: z.ZodNullable<z.ZodOptional<z.ZodString>>;
80
+ source: z.ZodNullable<z.ZodOptional<z.ZodString>>;
112
81
  options: z.ZodOptional<z.ZodObject<{
113
82
  "multi-line?": z.ZodOptional<z.ZodBoolean>;
114
- }, "strip", z.ZodTypeAny, {
115
- "multi-line?"?: boolean | undefined;
116
- }, {
117
- "multi-line?"?: boolean | undefined;
118
- }>>;
119
- }, "strip", z.ZodTypeAny, {
120
- name: string;
121
- id: string;
122
- pos: string;
123
- options?: {
124
- "multi-line?"?: boolean | undefined;
125
- } | undefined;
126
- }, {
127
- name: string;
128
- id: string;
129
- pos: string;
130
- options?: {
131
- "multi-line?"?: boolean | undefined;
132
- } | undefined;
133
- }>>;
134
- }, "strip", z.ZodTypeAny, {
135
- name: string;
136
- id: string;
137
- content: string;
138
- fields: Record<string, {
139
- name: string;
140
- id: string;
141
- pos: string;
142
- options?: {
143
- "multi-line?"?: boolean | undefined;
144
- } | undefined;
145
- }>;
146
- pos: string;
147
- }, {
148
- name: string;
149
- id: string;
150
- content: string;
151
- fields: Record<string, {
152
- name: string;
153
- id: string;
154
- pos: string;
155
- options?: {
156
- "multi-line?"?: boolean | undefined;
157
- } | undefined;
158
- }>;
159
- pos: string;
160
- }>, "many">;
161
- }, "strip", z.ZodTypeAny, {
162
- bookmark: string;
163
- docs: {
164
- name: string;
165
- id: string;
166
- content: string;
167
- fields: Record<string, {
168
- name: string;
169
- id: string;
170
- pos: string;
171
- options?: {
172
- "multi-line?"?: boolean | undefined;
173
- } | undefined;
174
- }>;
175
- pos: string;
176
- }[];
177
- }, {
178
- bookmark: string;
179
- docs: {
180
- name: string;
181
- id: string;
182
- content: string;
183
- fields: Record<string, {
184
- name: string;
185
- id: string;
186
- pos: string;
187
- options?: {
188
- "multi-line?"?: boolean | undefined;
189
- } | undefined;
190
- }>;
191
- pos: string;
192
- }[];
193
- }>;
83
+ }, z.core.$loose>>;
84
+ }, z.core.$strip>>;
85
+ }, z.core.$strip>>;
86
+ }, z.core.$strip>;
194
87
  type ListTemplatesParams = z.infer<typeof ListTemplatesParamsSchema>;
195
88
  type ListTemplatesResponse = z.infer<typeof ListTemplatesResponseSchema>;
196
89
  type ListCardsParams = z.infer<typeof ListCardsParamsSchema>;
197
90
  type ListDecksParams = z.infer<typeof ListDecksParamsSchema>;
198
91
  type CreateCardRequest = z.infer<typeof CreateCardRequestSchema>;
199
92
  type UpdateCardRequest = z.infer<typeof UpdateCardRequestSchema>;
93
+ type GetDueCardsParams = z.infer<typeof GetDueCardsParamsSchema>;
94
+ type CreateCardFromTemplateParams = z.infer<typeof CreateCardFromTemplateSchema>;
200
95
  declare const CreateCardResponseSchema: z.ZodObject<{
201
96
  id: z.ZodString;
202
- tags: z.ZodArray<z.ZodString, "many">;
97
+ tags: z.ZodArray<z.ZodString>;
203
98
  content: z.ZodString;
204
99
  name: z.ZodString;
205
100
  "deck-id": z.ZodString;
206
101
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
207
- }, "strip", z.ZodTypeAny, {
208
- name: string;
209
- id: string;
210
- content: string;
211
- "deck-id": string;
212
- tags: string[];
213
- fields?: Record<string, unknown> | undefined;
214
- }, {
215
- name: string;
216
- id: string;
217
- content: string;
218
- "deck-id": string;
219
- tags: string[];
220
- fields?: Record<string, unknown> | undefined;
221
- }>;
102
+ }, z.core.$strip>;
222
103
  declare const ListCardsResponseSchema: z.ZodObject<{
223
104
  bookmark: z.ZodString;
224
105
  docs: z.ZodArray<z.ZodObject<{
225
106
  id: z.ZodString;
226
- tags: z.ZodArray<z.ZodString, "many">;
107
+ tags: z.ZodArray<z.ZodString>;
227
108
  content: z.ZodString;
228
109
  name: z.ZodString;
229
110
  "deck-id": z.ZodString;
230
111
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
231
- }, "strip", z.ZodTypeAny, {
232
- name: string;
233
- id: string;
234
- content: string;
235
- "deck-id": string;
236
- tags: string[];
237
- fields?: Record<string, unknown> | undefined;
238
- }, {
239
- name: string;
240
- id: string;
241
- content: string;
242
- "deck-id": string;
243
- tags: string[];
244
- fields?: Record<string, unknown> | undefined;
245
- }>, "many">;
246
- }, "strip", z.ZodTypeAny, {
247
- bookmark: string;
248
- docs: {
249
- name: string;
250
- id: string;
251
- content: string;
252
- "deck-id": string;
253
- tags: string[];
254
- fields?: Record<string, unknown> | undefined;
255
- }[];
256
- }, {
257
- bookmark: string;
258
- docs: {
259
- name: string;
260
- id: string;
261
- content: string;
262
- "deck-id": string;
263
- tags: string[];
264
- fields?: Record<string, unknown> | undefined;
265
- }[];
266
- }>;
112
+ }, z.core.$strip>>;
113
+ }, z.core.$strip>;
267
114
  type CreateCardResponse = z.infer<typeof CreateCardResponseSchema>;
268
115
  type ListDecksResponse = z.infer<typeof ListDecksResponseSchema>["docs"];
269
116
  type ListCardsResponse = z.infer<typeof ListCardsResponseSchema>;
@@ -273,35 +120,21 @@ declare const ListDecksResponseSchema: z.ZodObject<{
273
120
  id: z.ZodString;
274
121
  sort: z.ZodNumber;
275
122
  name: z.ZodString;
276
- archived: z.ZodOptional<z.ZodBoolean>;
277
- }, "strip", z.ZodTypeAny, {
278
- sort: number;
279
- name: string;
280
- id: string;
281
- archived?: boolean | undefined;
282
- }, {
283
- sort: number;
284
- name: string;
285
- id: string;
286
- archived?: boolean | undefined;
287
- }>, "many">;
288
- }, "strip", z.ZodTypeAny, {
289
- bookmark: string;
290
- docs: {
291
- sort: number;
292
- name: string;
293
- id: string;
294
- archived?: boolean | undefined;
295
- }[];
296
- }, {
297
- bookmark: string;
298
- docs: {
299
- sort: number;
300
- name: string;
301
- id: string;
302
- archived?: boolean | undefined;
303
- }[];
304
- }>;
123
+ "archived?": z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
124
+ "trashed?": z.ZodNullable<z.ZodOptional<z.ZodObject<{
125
+ date: z.ZodString;
126
+ }, z.core.$strip>>>;
127
+ }, z.core.$strip>>;
128
+ }, z.core.$strip>;
129
+ declare const GetDueCardsResponseSchema: z.ZodObject<{
130
+ cards: z.ZodArray<z.ZodObject<{
131
+ id: z.ZodString;
132
+ content: z.ZodString;
133
+ name: z.ZodString;
134
+ "deck-id": z.ZodString;
135
+ "new?": z.ZodBoolean;
136
+ }, z.core.$loose>>;
137
+ }, z.core.$strip>;
305
138
  export declare class MochiClient {
306
139
  private api;
307
140
  private token;
@@ -311,5 +144,12 @@ export declare class MochiClient {
311
144
  listDecks(params?: ListDecksParams): Promise<ListDecksResponse>;
312
145
  listCards(params?: ListCardsParams): Promise<ListCardsResponse>;
313
146
  listTemplates(params?: ListTemplatesParams): Promise<ListTemplatesResponse>;
147
+ getDueCards(params?: GetDueCardsParams): Promise<z.infer<typeof GetDueCardsResponseSchema>>;
148
+ getTemplate(templateId: string): Promise<z.infer<typeof TemplateSchema>>;
149
+ createCardFromTemplate(request: CreateCardFromTemplateParams): Promise<CreateCardResponse>;
150
+ addAttachment(request: AddAttachmentRequest): Promise<{
151
+ filename: string;
152
+ markdown: string;
153
+ }>;
314
154
  }
315
155
  export {};