keepsake-mcp 1.11.0 → 1.12.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.
- package/README.md +6 -2
- package/build/tools.js +102 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ rather than in the chat, which disappears.
|
|
|
114
114
|
|--------|-----------|-------------|
|
|
115
115
|
| `review_note` | `note_id` | Act as the editor of a note: read it, judge form and substance, leave anchored remarks in the margin, never rewrite the text |
|
|
116
116
|
|
|
117
|
-
## Available tools (
|
|
117
|
+
## Available tools (83)
|
|
118
118
|
|
|
119
119
|
### Contacts
|
|
120
120
|
| Tool | Description |
|
|
@@ -152,6 +152,7 @@ rather than in the chat, which disappears.
|
|
|
152
152
|
| Tool | Description |
|
|
153
153
|
|------|-------------|
|
|
154
154
|
| `list_tasks` | List tasks with status/date filters |
|
|
155
|
+
| `get_task` | Get a task with its tags, contacts, companies and linked notes |
|
|
155
156
|
| `create_task` | Create a task — supports `#tag#` and `[[tag]]` syntax |
|
|
156
157
|
| `update_task` | Update task fields |
|
|
157
158
|
| `delete_task` | Delete a task |
|
|
@@ -220,13 +221,16 @@ Material kept *alongside* a note without entering its text — an idea, a refere
|
|
|
220
221
|
| `update_task_header` | Update a task header (name, description, collapsed) |
|
|
221
222
|
| `delete_task_header` | Permanently delete a task header |
|
|
222
223
|
|
|
223
|
-
### Contact
|
|
224
|
+
### Contact & company links
|
|
224
225
|
| Tool | Description |
|
|
225
226
|
|------|-------------|
|
|
227
|
+
| `link_note_company` / `unlink_note_company` | Link / unlink a company to a note |
|
|
226
228
|
| `link_note_contact` | Link a contact to a note |
|
|
227
229
|
| `unlink_note_contact` | Remove a contact link from a note |
|
|
230
|
+
| `link_entry_company` / `unlink_entry_company` | Add / remove a company as participant of an entry |
|
|
228
231
|
| `link_entry_contact` | Link a contact to an entry |
|
|
229
232
|
| `unlink_entry_contact` | Remove a contact link from an entry |
|
|
233
|
+
| `link_task_company` / `unlink_task_company` | Link / unlink a company to a task |
|
|
230
234
|
| `link_task_contact` | Link a contact to a task |
|
|
231
235
|
| `unlink_task_contact` | Remove a contact link from a task |
|
|
232
236
|
| `link_task_note` | Link a note to a task (non-destructive, the note survives) |
|
package/build/tools.js
CHANGED
|
@@ -302,14 +302,15 @@ export function registerAllTools(server, fetchApi) {
|
|
|
302
302
|
.optional()
|
|
303
303
|
.describe("Filter by entry type"),
|
|
304
304
|
contact_id: z.string().uuid().optional().describe("Filter by associated contact ID"),
|
|
305
|
+
company_id: z.string().uuid().optional().describe("Only entries where this company is a participant"),
|
|
305
306
|
from: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
306
307
|
to: z.string().optional().describe("End date (YYYY-MM-DD)"),
|
|
307
308
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
308
309
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
309
310
|
},
|
|
310
311
|
annotations: { title: "List entries", readOnlyHint: true, openWorldHint: false },
|
|
311
|
-
}, async ({ type, contact_id, from, to, limit, offset }) => {
|
|
312
|
-
return toContent(await fetchApi(`/entries${qs({ type, contact_id, from, to, limit, offset })}`));
|
|
312
|
+
}, async ({ type, contact_id, company_id, from, to, limit, offset }) => {
|
|
313
|
+
return toContent(await fetchApi(`/entries${qs({ type, contact_id, company_id, from, to, limit, offset })}`));
|
|
313
314
|
});
|
|
314
315
|
server.registerTool("create_entry", {
|
|
315
316
|
description: "An ENTRY is a dated interaction log tied to contacts. Records something that happened (call, meeting, email…) on a specific date.\n\nCreate a new interaction entry. Content supports #tag# and [[tag]] syntax for automatic tag linking.",
|
|
@@ -323,6 +324,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
323
324
|
.array(z.string().uuid())
|
|
324
325
|
.optional()
|
|
325
326
|
.describe("Array of contact UUIDs to associate"),
|
|
327
|
+
company_ids: z
|
|
328
|
+
.array(z.string().uuid())
|
|
329
|
+
.optional()
|
|
330
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
326
331
|
tag_ids: z
|
|
327
332
|
.array(z.string().uuid())
|
|
328
333
|
.optional()
|
|
@@ -346,6 +351,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
346
351
|
.array(z.string().uuid())
|
|
347
352
|
.optional()
|
|
348
353
|
.describe("Replace associated contacts"),
|
|
354
|
+
company_ids: z
|
|
355
|
+
.array(z.string().uuid())
|
|
356
|
+
.optional()
|
|
357
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
349
358
|
tag_ids: z
|
|
350
359
|
.array(z.string().uuid())
|
|
351
360
|
.optional()
|
|
@@ -376,12 +385,22 @@ export function registerAllTools(server, fetchApi) {
|
|
|
376
385
|
.optional()
|
|
377
386
|
.describe("Filter by date type: specific (has a due date), asap (do as soon as possible), one_day (someday/no rush)"),
|
|
378
387
|
date: z.string().optional().describe("Filter by specific date (YYYY-MM-DD)"),
|
|
388
|
+
company_id: z.string().uuid().optional().describe("Only tasks linked directly to this company"),
|
|
379
389
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
380
390
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
381
391
|
},
|
|
382
392
|
annotations: { title: "List tasks", readOnlyHint: true, openWorldHint: false },
|
|
383
|
-
}, async ({ status, date_type, date, limit, offset }) => {
|
|
384
|
-
return toContent(await fetchApi(`/tasks${qs({ status, date_type, date, limit, offset })}`));
|
|
393
|
+
}, async ({ status, date_type, date, company_id, limit, offset }) => {
|
|
394
|
+
return toContent(await fetchApi(`/tasks${qs({ status, date_type, date, company_id, limit, offset })}`));
|
|
395
|
+
});
|
|
396
|
+
server.registerTool("get_task", {
|
|
397
|
+
description: "Get a single task by ID, with its tags, linked contacts (contact_ids), linked companies (company_ids) and linked notes (note_ids). Use it when you already know which task you need instead of listing everything.",
|
|
398
|
+
inputSchema: {
|
|
399
|
+
id: z.string().uuid().describe("Task UUID"),
|
|
400
|
+
},
|
|
401
|
+
annotations: { title: "Get task", readOnlyHint: true, openWorldHint: false },
|
|
402
|
+
}, async ({ id }) => {
|
|
403
|
+
return toContent(await fetchApi(`/tasks/${id}`));
|
|
385
404
|
});
|
|
386
405
|
server.registerTool("create_task", {
|
|
387
406
|
description: "A TASK is an action item to accomplish. Can have due date, recurrence, priority, linked to contacts and tags.\n\nCreate a new task. Title supports #tag# and [[tag]] for automatic tag linking.",
|
|
@@ -420,6 +439,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
420
439
|
.array(z.string().uuid())
|
|
421
440
|
.optional()
|
|
422
441
|
.describe("Array of contact UUIDs to associate"),
|
|
442
|
+
company_ids: z
|
|
443
|
+
.array(z.string().uuid())
|
|
444
|
+
.optional()
|
|
445
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
423
446
|
tag_ids: z
|
|
424
447
|
.array(z.string().uuid())
|
|
425
448
|
.optional()
|
|
@@ -459,6 +482,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
459
482
|
.array(z.string().uuid())
|
|
460
483
|
.optional()
|
|
461
484
|
.describe("Replace associated contacts"),
|
|
485
|
+
company_ids: z
|
|
486
|
+
.array(z.string().uuid())
|
|
487
|
+
.optional()
|
|
488
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
462
489
|
tag_ids: z
|
|
463
490
|
.array(z.string().uuid())
|
|
464
491
|
.optional()
|
|
@@ -520,12 +547,13 @@ export function registerAllTools(server, fetchApi) {
|
|
|
520
547
|
date: z.string().optional().describe("Only notes linked to this day (YYYY-MM-DD)"),
|
|
521
548
|
date_from: z.string().optional().describe("Only notes linked to a day on or after this date (YYYY-MM-DD)"),
|
|
522
549
|
date_to: z.string().optional().describe("Only notes linked to a day on or before this date (YYYY-MM-DD)"),
|
|
550
|
+
company_id: z.string().uuid().optional().describe("Only notes linked directly to this company"),
|
|
523
551
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
524
552
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
525
553
|
},
|
|
526
554
|
annotations: { title: "List notes", readOnlyHint: true, openWorldHint: false },
|
|
527
|
-
}, async ({ pinned, archived, date, date_from, date_to, limit, offset }) => {
|
|
528
|
-
return toContent(await fetchApi(`/notes${qs({ pinned, archived, date, date_from, date_to, limit, offset })}`));
|
|
555
|
+
}, async ({ pinned, archived, date, date_from, date_to, company_id, limit, offset }) => {
|
|
556
|
+
return toContent(await fetchApi(`/notes${qs({ pinned, archived, date, date_from, date_to, company_id, limit, offset })}`));
|
|
529
557
|
});
|
|
530
558
|
server.registerTool("get_note", {
|
|
531
559
|
description: "Get a single note by ID, including its tags, linked contacts, linked tasks, linked notes and the days it is linked to (`dates`). Use this when the user points you at one specific note (e.g. gives you its URL — the UUID is the last path segment) instead of listing everything.",
|
|
@@ -545,6 +573,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
545
573
|
.array(z.string().uuid())
|
|
546
574
|
.optional()
|
|
547
575
|
.describe("Array of contact UUIDs to associate"),
|
|
576
|
+
company_ids: z
|
|
577
|
+
.array(z.string().uuid())
|
|
578
|
+
.optional()
|
|
579
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
548
580
|
dates: z
|
|
549
581
|
.array(z.string())
|
|
550
582
|
.optional()
|
|
@@ -563,6 +595,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
563
595
|
.array(z.string().uuid())
|
|
564
596
|
.optional()
|
|
565
597
|
.describe("Replace associated contacts"),
|
|
598
|
+
company_ids: z
|
|
599
|
+
.array(z.string().uuid())
|
|
600
|
+
.optional()
|
|
601
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
566
602
|
tag_ids: z
|
|
567
603
|
.array(z.string().uuid())
|
|
568
604
|
.optional()
|
|
@@ -939,6 +975,66 @@ export function registerAllTools(server, fetchApi) {
|
|
|
939
975
|
}, async ({ task_id, contact_id }) => {
|
|
940
976
|
return toContent(await fetchApi(`/tasks/${task_id}/contacts/${contact_id}`, "DELETE"));
|
|
941
977
|
});
|
|
978
|
+
server.registerTool("link_entry_company", {
|
|
979
|
+
description: "Link a company to an entry (the company becomes a participant of that interaction). Idempotent. Companies are separate records from contacts: use this (or company_ids) for an organization, link_entry_contact for a person.",
|
|
980
|
+
inputSchema: {
|
|
981
|
+
entry_id: z.string().uuid().describe("Entry UUID"),
|
|
982
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
983
|
+
},
|
|
984
|
+
annotations: { title: "Link entry company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
985
|
+
}, async ({ entry_id, company_id }) => {
|
|
986
|
+
return toContent(await fetchApi(`/entries/${entry_id}/companies/${company_id}`, "POST"));
|
|
987
|
+
});
|
|
988
|
+
server.registerTool("unlink_entry_company", {
|
|
989
|
+
description: "Remove the link between a company and an entry.",
|
|
990
|
+
inputSchema: {
|
|
991
|
+
entry_id: z.string().uuid().describe("Entry UUID"),
|
|
992
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
993
|
+
},
|
|
994
|
+
annotations: { title: "Unlink entry company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
995
|
+
}, async ({ entry_id, company_id }) => {
|
|
996
|
+
return toContent(await fetchApi(`/entries/${entry_id}/companies/${company_id}`, "DELETE"));
|
|
997
|
+
});
|
|
998
|
+
server.registerTool("link_task_company", {
|
|
999
|
+
description: "Link a company to a task. Idempotent. Companies are separate records from contacts: use this (or company_ids) for an organization, link_task_contact for a person.",
|
|
1000
|
+
inputSchema: {
|
|
1001
|
+
task_id: z.string().uuid().describe("Task UUID"),
|
|
1002
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1003
|
+
},
|
|
1004
|
+
annotations: { title: "Link task company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1005
|
+
}, async ({ task_id, company_id }) => {
|
|
1006
|
+
return toContent(await fetchApi(`/tasks/${task_id}/companies/${company_id}`, "POST"));
|
|
1007
|
+
});
|
|
1008
|
+
server.registerTool("unlink_task_company", {
|
|
1009
|
+
description: "Remove the link between a company and a task.",
|
|
1010
|
+
inputSchema: {
|
|
1011
|
+
task_id: z.string().uuid().describe("Task UUID"),
|
|
1012
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1013
|
+
},
|
|
1014
|
+
annotations: { title: "Unlink task company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
1015
|
+
}, async ({ task_id, company_id }) => {
|
|
1016
|
+
return toContent(await fetchApi(`/tasks/${task_id}/companies/${company_id}`, "DELETE"));
|
|
1017
|
+
});
|
|
1018
|
+
server.registerTool("link_note_company", {
|
|
1019
|
+
description: "Link a company to a note. Idempotent. Companies are separate records from contacts: use this (or company_ids) for an organization, link_note_contact for a person.",
|
|
1020
|
+
inputSchema: {
|
|
1021
|
+
note_id: z.string().uuid().describe("Note UUID"),
|
|
1022
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1023
|
+
},
|
|
1024
|
+
annotations: { title: "Link note company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1025
|
+
}, async ({ note_id, company_id }) => {
|
|
1026
|
+
return toContent(await fetchApi(`/notes/${note_id}/companies/${company_id}`, "POST"));
|
|
1027
|
+
});
|
|
1028
|
+
server.registerTool("unlink_note_company", {
|
|
1029
|
+
description: "Remove the link between a company and a note.",
|
|
1030
|
+
inputSchema: {
|
|
1031
|
+
note_id: z.string().uuid().describe("Note UUID"),
|
|
1032
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1033
|
+
},
|
|
1034
|
+
annotations: { title: "Unlink note company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
1035
|
+
}, async ({ note_id, company_id }) => {
|
|
1036
|
+
return toContent(await fetchApi(`/notes/${note_id}/companies/${company_id}`, "DELETE"));
|
|
1037
|
+
});
|
|
942
1038
|
server.registerTool("link_task_note", {
|
|
943
1039
|
description: "Link an existing note to a task (non-destructive, N-N). The note stays in the inbox/notes list and the task keeps a live link back to it — use this instead of deleting a note after creating a task from it. The note shows its linked tasks; the task shows the source note.",
|
|
944
1040
|
inputSchema: {
|