keepsake-mcp 1.11.0 → 1.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.
- package/README.md +12 -8
- package/build/tools.js +115 -13
- 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 |
|
|
@@ -143,7 +143,7 @@ rather than in the chat, which disappears.
|
|
|
143
143
|
### Entries (Interactions)
|
|
144
144
|
| Tool | Description |
|
|
145
145
|
|------|-------------|
|
|
146
|
-
| `list_entries` | List interactions (calls, emails, meetings, etc.) |
|
|
146
|
+
| `list_entries` | List interactions (calls, emails, meetings, etc.) — filter by type, contact, company, page (`tag_id`), dates |
|
|
147
147
|
| `create_entry` | Log a new interaction — supports `#tag#` and `[[tag]]` syntax |
|
|
148
148
|
| `update_entry` | Update an interaction |
|
|
149
149
|
| `delete_entry` | Delete an interaction |
|
|
@@ -151,7 +151,8 @@ rather than in the chat, which disappears.
|
|
|
151
151
|
### Tasks
|
|
152
152
|
| Tool | Description |
|
|
153
153
|
|------|-------------|
|
|
154
|
-
| `list_tasks` | List tasks
|
|
154
|
+
| `list_tasks` | List tasks — filter by status, date, company, page (`tag_id`) |
|
|
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 |
|
|
@@ -164,12 +165,12 @@ rather than in the chat, which disappears.
|
|
|
164
165
|
### QuickNotes
|
|
165
166
|
| Tool | Description |
|
|
166
167
|
|------|-------------|
|
|
167
|
-
| `list_notes` | List notes
|
|
168
|
+
| `list_notes` | List notes — filter by pinned/archived, day, company, page (`tag_id`) |
|
|
168
169
|
| `get_note` | Get one note by ID with its tags, contacts, tasks and linked notes |
|
|
169
170
|
| `create_note` | Create a note — supports `#tag#` and `[[tag]]` syntax |
|
|
170
171
|
| `update_note` | Update note content |
|
|
171
172
|
| `delete_note` | Soft-delete (or permanent) |
|
|
172
|
-
| `pin_note` | Pin
|
|
173
|
+
| `pin_note` | Pin as a post-it (short reference always at hand) |
|
|
173
174
|
| `archive_note` | Archive a note |
|
|
174
175
|
| `restore_note` | Restore a deleted/archived note |
|
|
175
176
|
|
|
@@ -205,7 +206,7 @@ Material kept *alongside* a note without entering its text — an idea, a refere
|
|
|
205
206
|
| `list_tags` | List tags (lightweight — ordering arrays omitted), with optional name search (`q`) |
|
|
206
207
|
| `get_tag` | Get a tag by ID with all properties, including `tasks_order` (section markers `h:<header_id>`) |
|
|
207
208
|
| `create_tag` | Create a new tag |
|
|
208
|
-
| `update_tag` | Update a tag (name, description, color, icon,
|
|
209
|
+
| `update_tag` | Update a tag (name, description, color, icon, favorite, order of tasks and sections via `tasks_order`) |
|
|
209
210
|
| `delete_tag` | Permanently delete a tag and all its links |
|
|
210
211
|
| `get_tag_items` | Get items linked to a tag — filter by `types`/`status`, `summary` mode, task `sections` included |
|
|
211
212
|
| `link_tag` | Link any entity to a tag |
|
|
@@ -216,17 +217,20 @@ Material kept *alongside* a note without entering its text — an idea, a refere
|
|
|
216
217
|
|------|-------------|
|
|
217
218
|
| `list_task_headers` | List all task headers (section separators) |
|
|
218
219
|
| `get_task_header` | Get a task header by ID |
|
|
219
|
-
| `create_task_header` | Create a task header (section) |
|
|
220
|
+
| `create_task_header` | Create a task header (section) — insert `h:<id>` in the tag's `tasks_order` to place it |
|
|
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
|
@@ -295,21 +295,23 @@ export function registerAllTools(server, fetchApi) {
|
|
|
295
295
|
// ENTRIES (Interactions)
|
|
296
296
|
// ===========================================================================
|
|
297
297
|
server.registerTool("list_entries", {
|
|
298
|
-
description: "List interaction entries (calls, emails, meetings, events, etc.). Supports filtering by type, contact, and date range.",
|
|
298
|
+
description: "List interaction entries (calls, emails, meetings, events, etc.). Supports filtering by type, contact, company, tag (page) and date range.",
|
|
299
299
|
inputSchema: {
|
|
300
300
|
type: z
|
|
301
301
|
.enum(["call", "email", "meeting", "event", "gift", "letter", "message", "log", "other"])
|
|
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"),
|
|
306
|
+
tag_id: z.string().uuid().optional().describe("Only entries linked to this tag (page)"),
|
|
305
307
|
from: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
306
308
|
to: z.string().optional().describe("End date (YYYY-MM-DD)"),
|
|
307
309
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
308
310
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
309
311
|
},
|
|
310
312
|
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 })}`));
|
|
313
|
+
}, async ({ type, contact_id, company_id, tag_id, from, to, limit, offset }) => {
|
|
314
|
+
return toContent(await fetchApi(`/entries${qs({ type, contact_id, company_id, tag_id, from, to, limit, offset })}`));
|
|
313
315
|
});
|
|
314
316
|
server.registerTool("create_entry", {
|
|
315
317
|
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 +325,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
323
325
|
.array(z.string().uuid())
|
|
324
326
|
.optional()
|
|
325
327
|
.describe("Array of contact UUIDs to associate"),
|
|
328
|
+
company_ids: z
|
|
329
|
+
.array(z.string().uuid())
|
|
330
|
+
.optional()
|
|
331
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
326
332
|
tag_ids: z
|
|
327
333
|
.array(z.string().uuid())
|
|
328
334
|
.optional()
|
|
@@ -346,6 +352,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
346
352
|
.array(z.string().uuid())
|
|
347
353
|
.optional()
|
|
348
354
|
.describe("Replace associated contacts"),
|
|
355
|
+
company_ids: z
|
|
356
|
+
.array(z.string().uuid())
|
|
357
|
+
.optional()
|
|
358
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
349
359
|
tag_ids: z
|
|
350
360
|
.array(z.string().uuid())
|
|
351
361
|
.optional()
|
|
@@ -368,7 +378,7 @@ export function registerAllTools(server, fetchApi) {
|
|
|
368
378
|
// TASKS
|
|
369
379
|
// ===========================================================================
|
|
370
380
|
server.registerTool("list_tasks", {
|
|
371
|
-
description: "List tasks. Filter by status (pending/completed), date_type, or
|
|
381
|
+
description: "List tasks. Filter by status (pending/completed), date_type, specific date, company, or tag (page) — e.g. tag_id + status=pending lists a project's open tasks.",
|
|
372
382
|
inputSchema: {
|
|
373
383
|
status: z.enum(["pending", "completed"]).optional().describe("Filter by status"),
|
|
374
384
|
date_type: z
|
|
@@ -376,12 +386,23 @@ export function registerAllTools(server, fetchApi) {
|
|
|
376
386
|
.optional()
|
|
377
387
|
.describe("Filter by date type: specific (has a due date), asap (do as soon as possible), one_day (someday/no rush)"),
|
|
378
388
|
date: z.string().optional().describe("Filter by specific date (YYYY-MM-DD)"),
|
|
389
|
+
company_id: z.string().uuid().optional().describe("Only tasks linked directly to this company"),
|
|
390
|
+
tag_id: z.string().uuid().optional().describe("Only tasks linked to this tag (page)"),
|
|
379
391
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
380
392
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
381
393
|
},
|
|
382
394
|
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 })}`));
|
|
395
|
+
}, async ({ status, date_type, date, company_id, tag_id, limit, offset }) => {
|
|
396
|
+
return toContent(await fetchApi(`/tasks${qs({ status, date_type, date, company_id, tag_id, limit, offset })}`));
|
|
397
|
+
});
|
|
398
|
+
server.registerTool("get_task", {
|
|
399
|
+
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.",
|
|
400
|
+
inputSchema: {
|
|
401
|
+
id: z.string().uuid().describe("Task UUID"),
|
|
402
|
+
},
|
|
403
|
+
annotations: { title: "Get task", readOnlyHint: true, openWorldHint: false },
|
|
404
|
+
}, async ({ id }) => {
|
|
405
|
+
return toContent(await fetchApi(`/tasks/${id}`));
|
|
385
406
|
});
|
|
386
407
|
server.registerTool("create_task", {
|
|
387
408
|
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 +441,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
420
441
|
.array(z.string().uuid())
|
|
421
442
|
.optional()
|
|
422
443
|
.describe("Array of contact UUIDs to associate"),
|
|
444
|
+
company_ids: z
|
|
445
|
+
.array(z.string().uuid())
|
|
446
|
+
.optional()
|
|
447
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
423
448
|
tag_ids: z
|
|
424
449
|
.array(z.string().uuid())
|
|
425
450
|
.optional()
|
|
@@ -459,6 +484,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
459
484
|
.array(z.string().uuid())
|
|
460
485
|
.optional()
|
|
461
486
|
.describe("Replace associated contacts"),
|
|
487
|
+
company_ids: z
|
|
488
|
+
.array(z.string().uuid())
|
|
489
|
+
.optional()
|
|
490
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
462
491
|
tag_ids: z
|
|
463
492
|
.array(z.string().uuid())
|
|
464
493
|
.optional()
|
|
@@ -513,19 +542,21 @@ export function registerAllTools(server, fetchApi) {
|
|
|
513
542
|
// QUICK NOTES
|
|
514
543
|
// ===========================================================================
|
|
515
544
|
server.registerTool("list_notes", {
|
|
516
|
-
description: "List notes. QuickNotes (inbox, not yet archived) and Notes (archived, permanent). Filter by pinned or archived status, or by the day(s) a note is linked to (`date`, or `date_from`/`date_to`) — e.g. \"what did I note for tomorrow?\". Each note carries `dates`, the days it is linked to.",
|
|
545
|
+
description: "List notes. QuickNotes (inbox, not yet archived) and Notes (archived, permanent). Filter by pinned or archived status, by tag (page) with `tag_id`, or by the day(s) a note is linked to (`date`, or `date_from`/`date_to`) — e.g. \"what did I note for tomorrow?\". Each note carries `dates`, the days it is linked to.",
|
|
517
546
|
inputSchema: {
|
|
518
547
|
pinned: z.boolean().optional().describe("Filter pinned notes only"),
|
|
519
548
|
archived: z.boolean().optional().describe("Filter by status: true = Notes (archived/permanent), false = QuickNotes (inbox)"),
|
|
520
549
|
date: z.string().optional().describe("Only notes linked to this day (YYYY-MM-DD)"),
|
|
521
550
|
date_from: z.string().optional().describe("Only notes linked to a day on or after this date (YYYY-MM-DD)"),
|
|
522
551
|
date_to: z.string().optional().describe("Only notes linked to a day on or before this date (YYYY-MM-DD)"),
|
|
552
|
+
company_id: z.string().uuid().optional().describe("Only notes linked directly to this company"),
|
|
553
|
+
tag_id: z.string().uuid().optional().describe("Only notes linked to this tag (page)"),
|
|
523
554
|
limit: z.number().int().positive().optional().describe("Max results (default 20)"),
|
|
524
555
|
offset: z.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
525
556
|
},
|
|
526
557
|
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 })}`));
|
|
558
|
+
}, async ({ pinned, archived, date, date_from, date_to, company_id, tag_id, limit, offset }) => {
|
|
559
|
+
return toContent(await fetchApi(`/notes${qs({ pinned, archived, date, date_from, date_to, company_id, tag_id, limit, offset })}`));
|
|
529
560
|
});
|
|
530
561
|
server.registerTool("get_note", {
|
|
531
562
|
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 +576,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
545
576
|
.array(z.string().uuid())
|
|
546
577
|
.optional()
|
|
547
578
|
.describe("Array of contact UUIDs to associate"),
|
|
579
|
+
company_ids: z
|
|
580
|
+
.array(z.string().uuid())
|
|
581
|
+
.optional()
|
|
582
|
+
.describe("Array of company UUIDs to associate (companies are separate from contacts)"),
|
|
548
583
|
dates: z
|
|
549
584
|
.array(z.string())
|
|
550
585
|
.optional()
|
|
@@ -563,6 +598,10 @@ export function registerAllTools(server, fetchApi) {
|
|
|
563
598
|
.array(z.string().uuid())
|
|
564
599
|
.optional()
|
|
565
600
|
.describe("Replace associated contacts"),
|
|
601
|
+
company_ids: z
|
|
602
|
+
.array(z.string().uuid())
|
|
603
|
+
.optional()
|
|
604
|
+
.describe("Replace associated companies (send [] to unlink all). Contacts are unaffected."),
|
|
566
605
|
tag_ids: z
|
|
567
606
|
.array(z.string().uuid())
|
|
568
607
|
.optional()
|
|
@@ -588,7 +627,7 @@ export function registerAllTools(server, fetchApi) {
|
|
|
588
627
|
return toContent(await fetchApi(`/notes/${id}${query}`, "DELETE"));
|
|
589
628
|
});
|
|
590
629
|
server.registerTool("pin_note", {
|
|
591
|
-
description: "Pin a QuickNote or Note so it
|
|
630
|
+
description: "Pin a QuickNote or Note so it stays in view. A pin is a POST-IT: a short reference the user wants always at hand (gate code, hotel room number, Wi-Fi password). Do not pin a note just because it is important — meeting prep is linked to its day, project material to a tag, actions become tasks. Pin only when the user asks or the note is clearly such a post-it.",
|
|
592
631
|
inputSchema: {
|
|
593
632
|
id: z.string().uuid().describe("Note UUID"),
|
|
594
633
|
},
|
|
@@ -773,14 +812,17 @@ export function registerAllTools(server, fetchApi) {
|
|
|
773
812
|
return toContent(await fetchApi("/tags", "POST", body));
|
|
774
813
|
});
|
|
775
814
|
server.registerTool("update_tag", {
|
|
776
|
-
description: "Update an existing tag. Only send the fields you want to change. Supports name, description, color, icon,
|
|
815
|
+
description: "Update an existing tag. Only send the fields you want to change. Supports name, description, color, icon, favorite status, and the order of the page's tasks and sections (tasks_order).",
|
|
777
816
|
inputSchema: {
|
|
778
817
|
id: z.string().uuid().describe("Tag UUID"),
|
|
779
818
|
name: z.string().optional().describe("Tag name"),
|
|
780
819
|
description: z.string().optional().describe("Tag description"),
|
|
781
820
|
color: z.string().optional().describe("Tag color (e.g. 'blue', 'red', 'green')"),
|
|
782
821
|
icon: z.string().optional().describe("Tag icon (emoji or icon name)"),
|
|
783
|
-
|
|
822
|
+
tasks_order: z
|
|
823
|
+
.array(z.string())
|
|
824
|
+
.optional()
|
|
825
|
+
.describe("Full display order of the page's tasks: task ids and \"h:<header_id>\" entries for sections, top to bottom. Read the current one with get_tag, insert or move entries, send the whole array back. Tasks listed after a section belong to it."),
|
|
784
826
|
is_favorite: z.boolean().optional().describe("Whether the tag is a favorite"),
|
|
785
827
|
},
|
|
786
828
|
annotations: { title: "Update tag", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
@@ -845,7 +887,7 @@ export function registerAllTools(server, fetchApi) {
|
|
|
845
887
|
return toContent(await fetchApi(`/task-headers/${id}`));
|
|
846
888
|
});
|
|
847
889
|
server.registerTool("create_task_header", {
|
|
848
|
-
description: "Create a new task header (section separator).
|
|
890
|
+
description: "Create a new task header (section separator). To show it on a tag page, insert \"h:<header_id>\" into that tag's tasks_order (get_tag, then update_tag) where the section should start: the tasks listed after it belong to that section.",
|
|
849
891
|
inputSchema: {
|
|
850
892
|
name: z.string().describe("Header name"),
|
|
851
893
|
description: z.string().optional().describe("Optional description below the header"),
|
|
@@ -939,6 +981,66 @@ export function registerAllTools(server, fetchApi) {
|
|
|
939
981
|
}, async ({ task_id, contact_id }) => {
|
|
940
982
|
return toContent(await fetchApi(`/tasks/${task_id}/contacts/${contact_id}`, "DELETE"));
|
|
941
983
|
});
|
|
984
|
+
server.registerTool("link_entry_company", {
|
|
985
|
+
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.",
|
|
986
|
+
inputSchema: {
|
|
987
|
+
entry_id: z.string().uuid().describe("Entry UUID"),
|
|
988
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
989
|
+
},
|
|
990
|
+
annotations: { title: "Link entry company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
991
|
+
}, async ({ entry_id, company_id }) => {
|
|
992
|
+
return toContent(await fetchApi(`/entries/${entry_id}/companies/${company_id}`, "POST"));
|
|
993
|
+
});
|
|
994
|
+
server.registerTool("unlink_entry_company", {
|
|
995
|
+
description: "Remove the link between a company and an entry.",
|
|
996
|
+
inputSchema: {
|
|
997
|
+
entry_id: z.string().uuid().describe("Entry UUID"),
|
|
998
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
999
|
+
},
|
|
1000
|
+
annotations: { title: "Unlink entry company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
1001
|
+
}, async ({ entry_id, company_id }) => {
|
|
1002
|
+
return toContent(await fetchApi(`/entries/${entry_id}/companies/${company_id}`, "DELETE"));
|
|
1003
|
+
});
|
|
1004
|
+
server.registerTool("link_task_company", {
|
|
1005
|
+
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.",
|
|
1006
|
+
inputSchema: {
|
|
1007
|
+
task_id: z.string().uuid().describe("Task UUID"),
|
|
1008
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1009
|
+
},
|
|
1010
|
+
annotations: { title: "Link task company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1011
|
+
}, async ({ task_id, company_id }) => {
|
|
1012
|
+
return toContent(await fetchApi(`/tasks/${task_id}/companies/${company_id}`, "POST"));
|
|
1013
|
+
});
|
|
1014
|
+
server.registerTool("unlink_task_company", {
|
|
1015
|
+
description: "Remove the link between a company and a task.",
|
|
1016
|
+
inputSchema: {
|
|
1017
|
+
task_id: z.string().uuid().describe("Task UUID"),
|
|
1018
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1019
|
+
},
|
|
1020
|
+
annotations: { title: "Unlink task company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
1021
|
+
}, async ({ task_id, company_id }) => {
|
|
1022
|
+
return toContent(await fetchApi(`/tasks/${task_id}/companies/${company_id}`, "DELETE"));
|
|
1023
|
+
});
|
|
1024
|
+
server.registerTool("link_note_company", {
|
|
1025
|
+
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.",
|
|
1026
|
+
inputSchema: {
|
|
1027
|
+
note_id: z.string().uuid().describe("Note UUID"),
|
|
1028
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1029
|
+
},
|
|
1030
|
+
annotations: { title: "Link note company", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1031
|
+
}, async ({ note_id, company_id }) => {
|
|
1032
|
+
return toContent(await fetchApi(`/notes/${note_id}/companies/${company_id}`, "POST"));
|
|
1033
|
+
});
|
|
1034
|
+
server.registerTool("unlink_note_company", {
|
|
1035
|
+
description: "Remove the link between a company and a note.",
|
|
1036
|
+
inputSchema: {
|
|
1037
|
+
note_id: z.string().uuid().describe("Note UUID"),
|
|
1038
|
+
company_id: z.string().uuid().describe("Company UUID"),
|
|
1039
|
+
},
|
|
1040
|
+
annotations: { title: "Unlink note company", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
1041
|
+
}, async ({ note_id, company_id }) => {
|
|
1042
|
+
return toContent(await fetchApi(`/notes/${note_id}/companies/${company_id}`, "DELETE"));
|
|
1043
|
+
});
|
|
942
1044
|
server.registerTool("link_task_note", {
|
|
943
1045
|
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
1046
|
inputSchema: {
|