automd-mcp 0.1.4 → 0.2.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/dist/index.js +207 -204
- package/package.json +41 -40
- package/LICENSE.md +0 -60
package/dist/index.js
CHANGED
|
@@ -40384,7 +40384,7 @@ var ApiError = class extends Error {
|
|
|
40384
40384
|
hint = "Check that all required parameters are provided and correctly formatted.";
|
|
40385
40385
|
break;
|
|
40386
40386
|
case 404:
|
|
40387
|
-
hint = "The requested resource does not exist. Use
|
|
40387
|
+
hint = "The requested resource does not exist. Use list_items to see available item IDs.";
|
|
40388
40388
|
break;
|
|
40389
40389
|
case 409:
|
|
40390
40390
|
hint = "The resource was modified by another client. Re-fetch the resource and retry your operation.";
|
|
@@ -40522,82 +40522,82 @@ function errorResponse(err) {
|
|
|
40522
40522
|
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
40523
40523
|
}
|
|
40524
40524
|
function registerTools(server2) {
|
|
40525
|
-
server2.registerTool("
|
|
40526
|
-
title: "List
|
|
40527
|
-
description: "List all items (boards, checklists, and
|
|
40525
|
+
server2.registerTool("list_items", {
|
|
40526
|
+
title: "List Items",
|
|
40527
|
+
description: "List all items (boards, checklists, pages, and knowledge bases) with their task counts. Returns array of {id, name, itemType, projectId, taskCount}."
|
|
40528
40528
|
}, async () => {
|
|
40529
40529
|
try {
|
|
40530
|
-
const
|
|
40531
|
-
return json2(
|
|
40530
|
+
const items = await api.listFiles();
|
|
40531
|
+
return json2(items);
|
|
40532
40532
|
} catch (err) {
|
|
40533
40533
|
return errorResponse(err);
|
|
40534
40534
|
}
|
|
40535
40535
|
});
|
|
40536
|
-
server2.registerTool("
|
|
40537
|
-
title: "Get
|
|
40538
|
-
description: "Get
|
|
40539
|
-
inputSchema: {
|
|
40540
|
-
}, async ({
|
|
40536
|
+
server2.registerTool("get_item", {
|
|
40537
|
+
title: "Get Item",
|
|
40538
|
+
description: "Get an item (board, checklist, page, or knowledge base) with its columns and tasks",
|
|
40539
|
+
inputSchema: { itemId: external_exports.string().describe("The item ID (obtain from list_items)") }
|
|
40540
|
+
}, async ({ itemId }) => {
|
|
40541
40541
|
try {
|
|
40542
|
-
const
|
|
40543
|
-
return json2(
|
|
40542
|
+
const item = await api.getFile(itemId);
|
|
40543
|
+
return json2(item);
|
|
40544
40544
|
} catch (err) {
|
|
40545
40545
|
return errorResponse(err);
|
|
40546
40546
|
}
|
|
40547
40547
|
});
|
|
40548
|
-
server2.registerTool("
|
|
40549
|
-
title: "Get
|
|
40550
|
-
description: "Get the raw markdown content of
|
|
40551
|
-
inputSchema: {
|
|
40552
|
-
}, async ({
|
|
40548
|
+
server2.registerTool("get_item_markdown", {
|
|
40549
|
+
title: "Get Item Markdown",
|
|
40550
|
+
description: "Get the raw markdown content of an item (board, checklist, or page)",
|
|
40551
|
+
inputSchema: { itemId: external_exports.string().describe("The item ID") }
|
|
40552
|
+
}, async ({ itemId }) => {
|
|
40553
40553
|
try {
|
|
40554
|
-
const
|
|
40555
|
-
return text(
|
|
40554
|
+
const item = await api.getFile(itemId);
|
|
40555
|
+
return text(item.markdown);
|
|
40556
40556
|
} catch (err) {
|
|
40557
40557
|
return errorResponse(err);
|
|
40558
40558
|
}
|
|
40559
40559
|
});
|
|
40560
|
-
server2.registerTool("
|
|
40561
|
-
title: "Create
|
|
40562
|
-
description: "Create a new board, checklist, or
|
|
40560
|
+
server2.registerTool("create_item", {
|
|
40561
|
+
title: "Create Item",
|
|
40562
|
+
description: "Create a new board, checklist, page, or knowledge base. Boards use # (H1) for columns and ## (H2) for tasks. Checklists use ## (H2) with [ ]/[x] prefixes. Pages are free-form markdown. Knowledge bases are structured collections of entries (## H2) without checkboxes or progress \u2014 ideal for decisions, patterns, and reference material. All support YAML frontmatter, descriptions, blockquotes (>) for acceptance criteria, and GFM checkboxes for subtasks.",
|
|
40563
40563
|
inputSchema: {
|
|
40564
|
-
name: external_exports.string().describe("Name for the new
|
|
40565
|
-
itemType: external_exports.enum(["board", "checklist", "
|
|
40566
|
-
markdown: external_exports.string().optional().describe("Initial markdown content.
|
|
40564
|
+
name: external_exports.string().describe("Name for the new item"),
|
|
40565
|
+
itemType: external_exports.enum(["board", "checklist", "page", "knowledge"]).optional().describe("Type of item to create: board (kanban columns), checklist (task list with checkboxes), page (free-form markdown), or knowledge (structured entries without checkboxes/progress). Defaults to board"),
|
|
40566
|
+
markdown: external_exports.string().optional().describe("Initial markdown content. Omit for an empty item. For boards: use # for columns, ## for tasks. For checklists: ## with [ ] prefix. For pages/knowledge: free-form markdown. All types support YAML frontmatter (board:, description:, vocabulary:)."),
|
|
40567
40567
|
projectId: external_exports.string().optional().describe("Project ID to add the item to (optional)")
|
|
40568
40568
|
}
|
|
40569
40569
|
}, async ({ name, itemType, markdown, projectId }) => {
|
|
40570
40570
|
try {
|
|
40571
|
-
const
|
|
40572
|
-
return json2(
|
|
40571
|
+
const item = await api.createFile(name, markdown, projectId, itemType);
|
|
40572
|
+
return json2(item);
|
|
40573
40573
|
} catch (err) {
|
|
40574
40574
|
return errorResponse(err);
|
|
40575
40575
|
}
|
|
40576
40576
|
});
|
|
40577
|
-
server2.registerTool("
|
|
40578
|
-
title: "Delete
|
|
40579
|
-
description: "Permanently delete
|
|
40577
|
+
server2.registerTool("delete_item", {
|
|
40578
|
+
title: "Delete Item",
|
|
40579
|
+
description: "Permanently delete an item (board, checklist, or page) and all its contents",
|
|
40580
40580
|
inputSchema: {
|
|
40581
|
-
|
|
40581
|
+
itemId: external_exports.string().describe("The item ID to delete")
|
|
40582
40582
|
}
|
|
40583
|
-
}, async ({
|
|
40583
|
+
}, async ({ itemId }) => {
|
|
40584
40584
|
try {
|
|
40585
|
-
await api.deleteFile(
|
|
40586
|
-
return text("
|
|
40585
|
+
await api.deleteFile(itemId);
|
|
40586
|
+
return text("Item deleted");
|
|
40587
40587
|
} catch (err) {
|
|
40588
40588
|
return errorResponse(err);
|
|
40589
40589
|
}
|
|
40590
40590
|
});
|
|
40591
|
-
server2.registerTool("
|
|
40592
|
-
title: "Rename
|
|
40593
|
-
description: "Rename an existing board, checklist, or
|
|
40591
|
+
server2.registerTool("rename_item", {
|
|
40592
|
+
title: "Rename Item",
|
|
40593
|
+
description: "Rename an existing item (board, checklist, or page)",
|
|
40594
40594
|
inputSchema: {
|
|
40595
|
-
|
|
40596
|
-
name: external_exports.string().describe("New name for the
|
|
40595
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40596
|
+
name: external_exports.string().describe("New name for the item")
|
|
40597
40597
|
}
|
|
40598
|
-
}, async ({
|
|
40598
|
+
}, async ({ itemId, name }) => {
|
|
40599
40599
|
try {
|
|
40600
|
-
const result = await api.updateFile(
|
|
40600
|
+
const result = await api.updateFile(itemId, { name });
|
|
40601
40601
|
return json2(result);
|
|
40602
40602
|
} catch (err) {
|
|
40603
40603
|
return errorResponse(err);
|
|
@@ -40605,17 +40605,17 @@ function registerTools(server2) {
|
|
|
40605
40605
|
});
|
|
40606
40606
|
server2.registerTool("add_task", {
|
|
40607
40607
|
title: "Add Task",
|
|
40608
|
-
description: "Add a new task (H2 heading) to a column. Content supports inline metadata
|
|
40608
|
+
description: "Add a new task (## H2 heading) to a column. Content supports inline metadata: @user #label priority:high|medium|low due:YYYY-MM-DD est:4h knowledge:true. Do not include built-by: manually \u2014 use the agentName parameter.",
|
|
40609
40609
|
inputSchema: {
|
|
40610
|
-
|
|
40611
|
-
columnId: external_exports.string().describe("The column
|
|
40610
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40611
|
+
columnId: external_exports.string().describe("The column ID (found in get_item response columns[].id)"),
|
|
40612
40612
|
content: external_exports.string().describe("Task content with optional inline metadata"),
|
|
40613
40613
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Name of the agent making this change (tagged as built-by)")
|
|
40614
40614
|
}
|
|
40615
|
-
}, async ({
|
|
40615
|
+
}, async ({ itemId, columnId, content, agentName }) => {
|
|
40616
40616
|
try {
|
|
40617
40617
|
const finalContent = agentName ? `${content} built-by:${agentName}` : content;
|
|
40618
|
-
const result = await api.addTask(
|
|
40618
|
+
const result = await api.addTask(itemId, columnId, finalContent);
|
|
40619
40619
|
return json2(result);
|
|
40620
40620
|
} catch (err) {
|
|
40621
40621
|
return errorResponse(err);
|
|
@@ -40623,20 +40623,20 @@ function registerTools(server2) {
|
|
|
40623
40623
|
});
|
|
40624
40624
|
server2.registerTool("update_task", {
|
|
40625
40625
|
title: "Update Task",
|
|
40626
|
-
description: "Update a task's content",
|
|
40626
|
+
description: "Update a task's title/content text only. For metadata use update_task_metadata, for completion use toggle_task, for position use move_task, for AC use update_acceptance_criteria, for learnings use update_learnings.",
|
|
40627
40627
|
inputSchema: {
|
|
40628
|
-
|
|
40629
|
-
taskId: external_exports.string().describe("The task ID"),
|
|
40628
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40629
|
+
taskId: external_exports.string().describe("The task ID (found in get_item response columns[].tasks[].id)"),
|
|
40630
40630
|
content: external_exports.string().optional().describe("New task content"),
|
|
40631
40631
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Name of the agent making this change (tagged as built-by)")
|
|
40632
40632
|
}
|
|
40633
|
-
}, async ({
|
|
40633
|
+
}, async ({ itemId, taskId, content, agentName }) => {
|
|
40634
40634
|
try {
|
|
40635
40635
|
let finalContent = content;
|
|
40636
40636
|
if (agentName && finalContent) {
|
|
40637
40637
|
finalContent = finalContent.replace(/\s*built-by:[\w-]+/gi, "") + ` built-by:${agentName}`;
|
|
40638
40638
|
}
|
|
40639
|
-
const result = await api.updateTask(
|
|
40639
|
+
const result = await api.updateTask(itemId, taskId, {
|
|
40640
40640
|
action: "updateContent",
|
|
40641
40641
|
content: finalContent
|
|
40642
40642
|
});
|
|
@@ -40647,14 +40647,14 @@ function registerTools(server2) {
|
|
|
40647
40647
|
});
|
|
40648
40648
|
server2.registerTool("toggle_task", {
|
|
40649
40649
|
title: "Toggle Task",
|
|
40650
|
-
description: "Toggle a task between checked and unchecked",
|
|
40650
|
+
description: "Toggle a task between checked [ ] and unchecked [x]. Only applies to tasks with checkbox prefixes. Sets completedAt on check, clears on uncheck.",
|
|
40651
40651
|
inputSchema: {
|
|
40652
|
-
|
|
40652
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40653
40653
|
taskId: external_exports.string().describe("The task ID")
|
|
40654
40654
|
}
|
|
40655
|
-
}, async ({
|
|
40655
|
+
}, async ({ itemId, taskId }) => {
|
|
40656
40656
|
try {
|
|
40657
|
-
const result = await api.updateTask(
|
|
40657
|
+
const result = await api.updateTask(itemId, taskId, { action: "toggle" });
|
|
40658
40658
|
return json2(result);
|
|
40659
40659
|
} catch (err) {
|
|
40660
40660
|
return errorResponse(err);
|
|
@@ -40664,14 +40664,14 @@ function registerTools(server2) {
|
|
|
40664
40664
|
title: "Move Task",
|
|
40665
40665
|
description: "Move a task to a different column at a specific position",
|
|
40666
40666
|
inputSchema: {
|
|
40667
|
-
|
|
40667
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40668
40668
|
taskId: external_exports.string().describe("The task ID"),
|
|
40669
40669
|
targetColumnId: external_exports.string().describe("Target column ID"),
|
|
40670
|
-
targetIndex: external_exports.number().describe("Position in
|
|
40670
|
+
targetIndex: external_exports.number().describe("Position in target column (0-based). Use 0 to place at top. To append, use the column task count from get_item.")
|
|
40671
40671
|
}
|
|
40672
|
-
}, async ({
|
|
40672
|
+
}, async ({ itemId, taskId, targetColumnId, targetIndex }) => {
|
|
40673
40673
|
try {
|
|
40674
|
-
const result = await api.updateTask(
|
|
40674
|
+
const result = await api.updateTask(itemId, taskId, {
|
|
40675
40675
|
action: "move",
|
|
40676
40676
|
targetColumnId,
|
|
40677
40677
|
targetIndex
|
|
@@ -40683,14 +40683,14 @@ function registerTools(server2) {
|
|
|
40683
40683
|
});
|
|
40684
40684
|
server2.registerTool("delete_task", {
|
|
40685
40685
|
title: "Delete Task",
|
|
40686
|
-
description: "Delete a task from
|
|
40686
|
+
description: "Delete a task from an item",
|
|
40687
40687
|
inputSchema: {
|
|
40688
|
-
|
|
40688
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40689
40689
|
taskId: external_exports.string().describe("The task ID")
|
|
40690
40690
|
}
|
|
40691
|
-
}, async ({
|
|
40691
|
+
}, async ({ itemId, taskId }) => {
|
|
40692
40692
|
try {
|
|
40693
|
-
await api.deleteTask(
|
|
40693
|
+
await api.deleteTask(itemId, taskId);
|
|
40694
40694
|
return text("Task deleted");
|
|
40695
40695
|
} catch (err) {
|
|
40696
40696
|
return errorResponse(err);
|
|
@@ -40698,20 +40698,20 @@ function registerTools(server2) {
|
|
|
40698
40698
|
});
|
|
40699
40699
|
server2.registerTool("add_column", {
|
|
40700
40700
|
title: "Add Column",
|
|
40701
|
-
description:
|
|
40701
|
+
description: 'Add a new column (# H1 heading) to a board or checklist. Columns group tasks into workflow stages like "To Do", "In Progress", "Done".',
|
|
40702
40702
|
inputSchema: {
|
|
40703
|
-
|
|
40703
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40704
40704
|
title: external_exports.string().describe("Column title")
|
|
40705
40705
|
}
|
|
40706
|
-
}, async ({
|
|
40706
|
+
}, async ({ itemId, title }) => {
|
|
40707
40707
|
try {
|
|
40708
|
-
const
|
|
40709
|
-
const newMarkdown =
|
|
40708
|
+
const item = await api.getFile(itemId);
|
|
40709
|
+
const newMarkdown = item.markdown.trimEnd() + `
|
|
40710
40710
|
|
|
40711
40711
|
# ${title}
|
|
40712
40712
|
|
|
40713
40713
|
`;
|
|
40714
|
-
const result = await api.updateFile(
|
|
40714
|
+
const result = await api.updateFile(itemId, { markdown: newMarkdown });
|
|
40715
40715
|
return json2(result);
|
|
40716
40716
|
} catch (err) {
|
|
40717
40717
|
return errorResponse(err);
|
|
@@ -40719,15 +40719,15 @@ function registerTools(server2) {
|
|
|
40719
40719
|
});
|
|
40720
40720
|
server2.registerTool("rename_column", {
|
|
40721
40721
|
title: "Rename Column",
|
|
40722
|
-
description: "Rename a column/heading on
|
|
40722
|
+
description: "Rename a column/heading on an item",
|
|
40723
40723
|
inputSchema: {
|
|
40724
|
-
|
|
40724
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40725
40725
|
columnId: external_exports.string().describe("The column ID to rename"),
|
|
40726
40726
|
title: external_exports.string().describe("New title for the column")
|
|
40727
40727
|
}
|
|
40728
|
-
}, async ({
|
|
40728
|
+
}, async ({ itemId, columnId, title }) => {
|
|
40729
40729
|
try {
|
|
40730
|
-
const result = await api.renameColumn(
|
|
40730
|
+
const result = await api.renameColumn(itemId, columnId, title);
|
|
40731
40731
|
return json2(result);
|
|
40732
40732
|
} catch (err) {
|
|
40733
40733
|
return errorResponse(err);
|
|
@@ -40735,14 +40735,14 @@ function registerTools(server2) {
|
|
|
40735
40735
|
});
|
|
40736
40736
|
server2.registerTool("delete_column", {
|
|
40737
40737
|
title: "Delete Column",
|
|
40738
|
-
description: "Delete a column and all its tasks from
|
|
40738
|
+
description: "Delete a column and all its tasks from an item",
|
|
40739
40739
|
inputSchema: {
|
|
40740
|
-
|
|
40740
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40741
40741
|
columnId: external_exports.string().describe("The column ID to delete")
|
|
40742
40742
|
}
|
|
40743
|
-
}, async ({
|
|
40743
|
+
}, async ({ itemId, columnId }) => {
|
|
40744
40744
|
try {
|
|
40745
|
-
await api.deleteColumn(
|
|
40745
|
+
await api.deleteColumn(itemId, columnId);
|
|
40746
40746
|
return text("Column deleted");
|
|
40747
40747
|
} catch (err) {
|
|
40748
40748
|
return errorResponse(err);
|
|
@@ -40752,7 +40752,7 @@ function registerTools(server2) {
|
|
|
40752
40752
|
title: "Update Task Metadata",
|
|
40753
40753
|
description: "Update a task's metadata (priority, assignees, labels, due date, estimate) without rewriting its content",
|
|
40754
40754
|
inputSchema: {
|
|
40755
|
-
|
|
40755
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40756
40756
|
taskId: external_exports.string().describe("The task ID"),
|
|
40757
40757
|
priority: external_exports.enum(["high", "medium", "low"]).nullable().optional().describe("Task priority"),
|
|
40758
40758
|
assignees: external_exports.array(external_exports.string()).optional().describe("List of assignees (without @)"),
|
|
@@ -40761,10 +40761,10 @@ function registerTools(server2) {
|
|
|
40761
40761
|
estimate: external_exports.number().nullable().optional().describe("Time estimate in hours"),
|
|
40762
40762
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Name of the agent making this change (tagged as built-by)")
|
|
40763
40763
|
}
|
|
40764
|
-
}, async ({
|
|
40764
|
+
}, async ({ itemId, taskId, priority, assignees, labels, dueDate, estimate, agentName }) => {
|
|
40765
40765
|
try {
|
|
40766
|
-
const
|
|
40767
|
-
const task =
|
|
40766
|
+
const item = await api.getFile(itemId);
|
|
40767
|
+
const task = item.columns.flatMap((c) => c.tasks).find((t) => t.id === taskId);
|
|
40768
40768
|
if (!task) return text("Task not found");
|
|
40769
40769
|
const metadata = { ...task.metadata };
|
|
40770
40770
|
if (priority !== void 0) metadata.priority = priority;
|
|
@@ -40773,7 +40773,7 @@ function registerTools(server2) {
|
|
|
40773
40773
|
if (dueDate !== void 0) metadata.dueDate = dueDate;
|
|
40774
40774
|
if (estimate !== void 0) metadata.estimate = estimate;
|
|
40775
40775
|
if (agentName) metadata.builtBy = agentName;
|
|
40776
|
-
const result = await api.updateTask(
|
|
40776
|
+
const result = await api.updateTask(itemId, taskId, {
|
|
40777
40777
|
action: "updateMetadata",
|
|
40778
40778
|
displayContent: task.displayContent,
|
|
40779
40779
|
metadata
|
|
@@ -40787,13 +40787,13 @@ function registerTools(server2) {
|
|
|
40787
40787
|
title: "Update Acceptance Criteria",
|
|
40788
40788
|
description: `Update a task's acceptance criteria (rendered as blockquotes in markdown). These are testable conditions that define "done" for a task. Each line becomes a separate blockquote line.`,
|
|
40789
40789
|
inputSchema: {
|
|
40790
|
-
|
|
40790
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40791
40791
|
taskId: external_exports.string().describe("The task ID"),
|
|
40792
40792
|
acceptanceCriteria: external_exports.string().nullable().describe("Acceptance criteria text. Each line becomes a blockquote entry. Pass null to remove AC.")
|
|
40793
40793
|
}
|
|
40794
|
-
}, async ({
|
|
40794
|
+
}, async ({ itemId, taskId, acceptanceCriteria }) => {
|
|
40795
40795
|
try {
|
|
40796
|
-
const result = await api.updateTask(
|
|
40796
|
+
const result = await api.updateTask(itemId, taskId, {
|
|
40797
40797
|
action: "updateAcceptanceCriteria",
|
|
40798
40798
|
acceptanceCriteria
|
|
40799
40799
|
});
|
|
@@ -40806,13 +40806,13 @@ function registerTools(server2) {
|
|
|
40806
40806
|
title: "Update Learnings",
|
|
40807
40807
|
description: "Update a completed task's learnings section (rendered as ### Learnings with a bullet list in markdown). Use this to record decisions, insights, and pitfalls discovered while completing a task. Supports #label tags for cross-referencing.",
|
|
40808
40808
|
inputSchema: {
|
|
40809
|
-
|
|
40809
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40810
40810
|
taskId: external_exports.string().describe("The task ID"),
|
|
40811
40811
|
learnings: external_exports.string().nullable().describe('Learnings text. Each line becomes a bullet point under ### Learnings. Use #tags for keywords (e.g. "PKCE flow required for SPA #oauth #security"). Pass null to remove.')
|
|
40812
40812
|
}
|
|
40813
|
-
}, async ({
|
|
40813
|
+
}, async ({ itemId, taskId, learnings }) => {
|
|
40814
40814
|
try {
|
|
40815
|
-
const result = await api.updateTask(
|
|
40815
|
+
const result = await api.updateTask(itemId, taskId, {
|
|
40816
40816
|
action: "updateLearnings",
|
|
40817
40817
|
learnings
|
|
40818
40818
|
});
|
|
@@ -40825,7 +40825,7 @@ function registerTools(server2) {
|
|
|
40825
40825
|
title: "Bulk Update Tasks",
|
|
40826
40826
|
description: "Update multiple tasks at once. Each update can toggle, move, update content, or update metadata.",
|
|
40827
40827
|
inputSchema: {
|
|
40828
|
-
|
|
40828
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
40829
40829
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Name of the agent making these changes (tagged as built-by)"),
|
|
40830
40830
|
updates: external_exports.array(external_exports.object({
|
|
40831
40831
|
taskId: external_exports.string().describe("The task ID"),
|
|
@@ -40834,10 +40834,12 @@ function registerTools(server2) {
|
|
|
40834
40834
|
targetColumnId: external_exports.string().optional().describe("Target column (for move)"),
|
|
40835
40835
|
targetIndex: external_exports.number().optional().describe("Target index (for move)"),
|
|
40836
40836
|
displayContent: external_exports.string().optional().describe("Display content (for updateMetadata)"),
|
|
40837
|
-
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Metadata fields (for updateMetadata)")
|
|
40837
|
+
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Metadata fields (for updateMetadata)"),
|
|
40838
|
+
acceptanceCriteria: external_exports.string().nullable().optional().describe("Acceptance criteria text (for updateAcceptanceCriteria). Pass null to remove."),
|
|
40839
|
+
learnings: external_exports.string().nullable().optional().describe("Learnings text (for updateLearnings). Pass null to remove.")
|
|
40838
40840
|
})).describe("Array of task updates to apply")
|
|
40839
40841
|
}
|
|
40840
|
-
}, async ({
|
|
40842
|
+
}, async ({ itemId, agentName, updates }) => {
|
|
40841
40843
|
const results = [];
|
|
40842
40844
|
for (const update of updates) {
|
|
40843
40845
|
try {
|
|
@@ -40850,7 +40852,7 @@ function registerTools(server2) {
|
|
|
40850
40852
|
data.metadata = { ...data.metadata, builtBy: agentName };
|
|
40851
40853
|
}
|
|
40852
40854
|
}
|
|
40853
|
-
await api.updateTask(
|
|
40855
|
+
await api.updateTask(itemId, taskId, data);
|
|
40854
40856
|
results.push({ taskId, ok: true });
|
|
40855
40857
|
} catch (err) {
|
|
40856
40858
|
results.push({
|
|
@@ -40869,7 +40871,7 @@ function registerTools(server2) {
|
|
|
40869
40871
|
});
|
|
40870
40872
|
server2.registerTool("search_tasks", {
|
|
40871
40873
|
title: "Search Tasks",
|
|
40872
|
-
description: "Search for tasks across all
|
|
40874
|
+
description: "Search for tasks across all items by text, assignee, label, or status",
|
|
40873
40875
|
inputSchema: {
|
|
40874
40876
|
query: external_exports.string().optional().describe("Text to search for in task content"),
|
|
40875
40877
|
assignee: external_exports.string().optional().describe("Filter by assignee (without @)"),
|
|
@@ -40878,12 +40880,12 @@ function registerTools(server2) {
|
|
|
40878
40880
|
}
|
|
40879
40881
|
}, async ({ query, assignee, label, checked }) => {
|
|
40880
40882
|
try {
|
|
40881
|
-
const
|
|
40883
|
+
const items = await api.listFiles();
|
|
40882
40884
|
const results = [];
|
|
40883
|
-
for (const
|
|
40885
|
+
for (const itemSummary of items) {
|
|
40884
40886
|
try {
|
|
40885
|
-
const
|
|
40886
|
-
for (const column of
|
|
40887
|
+
const item = await api.getFile(itemSummary.id);
|
|
40888
|
+
for (const column of item.columns) {
|
|
40887
40889
|
for (const task of column.tasks) {
|
|
40888
40890
|
let match = true;
|
|
40889
40891
|
if (query && !task.content.toLowerCase().includes(query.toLowerCase())) match = false;
|
|
@@ -40892,8 +40894,8 @@ function registerTools(server2) {
|
|
|
40892
40894
|
if (checked !== void 0 && task.checked !== checked) match = false;
|
|
40893
40895
|
if (match) {
|
|
40894
40896
|
results.push({
|
|
40895
|
-
|
|
40896
|
-
|
|
40897
|
+
itemId: itemSummary.id,
|
|
40898
|
+
itemName: itemSummary.name,
|
|
40897
40899
|
taskId: task.id,
|
|
40898
40900
|
content: task.content,
|
|
40899
40901
|
column: column.title,
|
|
@@ -40903,7 +40905,7 @@ function registerTools(server2) {
|
|
|
40903
40905
|
}
|
|
40904
40906
|
}
|
|
40905
40907
|
} catch (err) {
|
|
40906
|
-
console.error(`[mcp] Failed to search
|
|
40908
|
+
console.error(`[mcp] Failed to search item ${itemSummary.id}:`, err);
|
|
40907
40909
|
}
|
|
40908
40910
|
}
|
|
40909
40911
|
return json2({ count: results.length, results });
|
|
@@ -40913,7 +40915,7 @@ function registerTools(server2) {
|
|
|
40913
40915
|
});
|
|
40914
40916
|
server2.registerTool("search_context", {
|
|
40915
40917
|
title: "Search Context",
|
|
40916
|
-
description:
|
|
40918
|
+
description: "Search for contextual detail (descriptions, acceptance criteria, learnings) across all items. Returns any task with rich content \u2014 broader than find_knowledge which only returns knowledge:true items. Use this for finding implementation details, past decisions, and context before starting work.",
|
|
40917
40919
|
inputSchema: {
|
|
40918
40920
|
query: external_exports.string().optional().describe("Text to search for across descriptions, AC, learnings, and task content"),
|
|
40919
40921
|
label: external_exports.string().optional().describe("Filter by label (without #). Also matches #tags inside learnings text."),
|
|
@@ -40921,13 +40923,13 @@ function registerTools(server2) {
|
|
|
40921
40923
|
}
|
|
40922
40924
|
}, async ({ query, label, completedOnly }) => {
|
|
40923
40925
|
try {
|
|
40924
|
-
const
|
|
40926
|
+
const items = await api.listFiles();
|
|
40925
40927
|
const results = [];
|
|
40926
40928
|
const q = query?.toLowerCase();
|
|
40927
|
-
for (const
|
|
40929
|
+
for (const itemSummary of items) {
|
|
40928
40930
|
try {
|
|
40929
|
-
const
|
|
40930
|
-
for (const column of
|
|
40931
|
+
const item = await api.getFile(itemSummary.id);
|
|
40932
|
+
for (const column of item.columns) {
|
|
40931
40933
|
for (const task of column.tasks) {
|
|
40932
40934
|
if (completedOnly && !task.checked) continue;
|
|
40933
40935
|
const searchable = [
|
|
@@ -40947,8 +40949,8 @@ function registerTools(server2) {
|
|
|
40947
40949
|
if (!hasContext) match = false;
|
|
40948
40950
|
if (match) {
|
|
40949
40951
|
results.push({
|
|
40950
|
-
|
|
40951
|
-
|
|
40952
|
+
itemId: itemSummary.id,
|
|
40953
|
+
itemName: itemSummary.name,
|
|
40952
40954
|
taskId: task.id,
|
|
40953
40955
|
taskTitle: task.displayContent,
|
|
40954
40956
|
taskLabels: task.metadata.labels,
|
|
@@ -40962,7 +40964,7 @@ function registerTools(server2) {
|
|
|
40962
40964
|
}
|
|
40963
40965
|
}
|
|
40964
40966
|
} catch (err) {
|
|
40965
|
-
console.error(`[mcp] Failed to search
|
|
40967
|
+
console.error(`[mcp] Failed to search item ${itemSummary.id}:`, err);
|
|
40966
40968
|
}
|
|
40967
40969
|
}
|
|
40968
40970
|
return json2({ count: results.length, results });
|
|
@@ -40972,7 +40974,7 @@ function registerTools(server2) {
|
|
|
40972
40974
|
});
|
|
40973
40975
|
server2.registerTool("list_projects", {
|
|
40974
40976
|
title: "List Projects",
|
|
40975
|
-
description: "List all projects"
|
|
40977
|
+
description: "List all projects. Returns array of {id, name, color}. Use project id as projectId in create_item or get_project_items."
|
|
40976
40978
|
}, async () => {
|
|
40977
40979
|
try {
|
|
40978
40980
|
const projects = await api.listProjects();
|
|
@@ -40981,26 +40983,26 @@ function registerTools(server2) {
|
|
|
40981
40983
|
return errorResponse(err);
|
|
40982
40984
|
}
|
|
40983
40985
|
});
|
|
40984
|
-
server2.registerTool("
|
|
40985
|
-
title: "Get Project
|
|
40986
|
-
description: "List all items (boards, checklists,
|
|
40986
|
+
server2.registerTool("get_project_items", {
|
|
40987
|
+
title: "Get Project Items",
|
|
40988
|
+
description: "List all items (boards, checklists, pages) belonging to a project",
|
|
40987
40989
|
inputSchema: {
|
|
40988
40990
|
projectId: external_exports.string().describe("The project ID")
|
|
40989
40991
|
}
|
|
40990
40992
|
}, async ({ projectId }) => {
|
|
40991
40993
|
try {
|
|
40992
|
-
const
|
|
40993
|
-
const
|
|
40994
|
+
const allItems = await api.listFiles();
|
|
40995
|
+
const projectItems = allItems.filter(
|
|
40994
40996
|
(b) => b.projectId === projectId
|
|
40995
40997
|
);
|
|
40996
|
-
return json2(
|
|
40998
|
+
return json2(projectItems);
|
|
40997
40999
|
} catch (err) {
|
|
40998
41000
|
return errorResponse(err);
|
|
40999
41001
|
}
|
|
41000
41002
|
});
|
|
41001
41003
|
server2.registerTool("create_project", {
|
|
41002
41004
|
title: "Create Project",
|
|
41003
|
-
description: "Create a new project to organize
|
|
41005
|
+
description: "Create a new project to organize items",
|
|
41004
41006
|
inputSchema: {
|
|
41005
41007
|
name: external_exports.string().describe("Name for the new project (max 200 characters)"),
|
|
41006
41008
|
color: external_exports.string().optional().describe("Hex color for the project (default: #3b82f6)")
|
|
@@ -41015,9 +41017,9 @@ function registerTools(server2) {
|
|
|
41015
41017
|
});
|
|
41016
41018
|
server2.registerTool("add_knowledge", {
|
|
41017
41019
|
title: "Add Knowledge",
|
|
41018
|
-
description: "Add a knowledge item
|
|
41020
|
+
description: "Add a knowledge item. Knowledge items are tasks with knowledge:true \u2014 they store decisions, patterns, references, and institutional memory. They reuse the task infrastructure but skip the checkbox/completion workflow.",
|
|
41019
41021
|
inputSchema: {
|
|
41020
|
-
|
|
41022
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41021
41023
|
columnId: external_exports.string().describe("The column ID"),
|
|
41022
41024
|
content: external_exports.string().describe('Knowledge item title (e.g. "Always use parameterized queries for SQL")'),
|
|
41023
41025
|
description: external_exports.string().optional().describe("Detailed description/context for this knowledge item"),
|
|
@@ -41025,20 +41027,20 @@ function registerTools(server2) {
|
|
|
41025
41027
|
labels: external_exports.array(external_exports.string()).optional().describe('Labels for categorization (e.g. ["security", "database"])'),
|
|
41026
41028
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Agent name to tag with built-by:")
|
|
41027
41029
|
}
|
|
41028
|
-
}, async ({
|
|
41030
|
+
}, async ({ itemId, columnId, content, description, learnings, labels, agentName }) => {
|
|
41029
41031
|
try {
|
|
41030
41032
|
let taskContent = `${content} knowledge:true`;
|
|
41031
41033
|
if (labels?.length) taskContent += " " + labels.map((l) => `#${l}`).join(" ");
|
|
41032
41034
|
if (agentName) taskContent += ` built-by:${agentName}`;
|
|
41033
|
-
const result = await api.addTask(
|
|
41035
|
+
const result = await api.addTask(itemId, columnId, taskContent);
|
|
41034
41036
|
if (description && result?.taskId) {
|
|
41035
|
-
await api.updateTask(
|
|
41037
|
+
await api.updateTask(itemId, result.taskId, {
|
|
41036
41038
|
action: "updateDescription",
|
|
41037
41039
|
description
|
|
41038
41040
|
});
|
|
41039
41041
|
}
|
|
41040
41042
|
if (learnings && result?.taskId) {
|
|
41041
|
-
await api.updateTask(
|
|
41043
|
+
await api.updateTask(itemId, result.taskId, {
|
|
41042
41044
|
action: "updateLearnings",
|
|
41043
41045
|
learnings
|
|
41044
41046
|
});
|
|
@@ -41052,35 +41054,35 @@ function registerTools(server2) {
|
|
|
41052
41054
|
title: "Update Knowledge",
|
|
41053
41055
|
description: "Update an existing knowledge item's description, learnings, or labels.",
|
|
41054
41056
|
inputSchema: {
|
|
41055
|
-
|
|
41057
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41056
41058
|
taskId: external_exports.string().describe("The task/knowledge item ID"),
|
|
41057
41059
|
description: external_exports.string().optional().describe("New description (replaces existing)"),
|
|
41058
41060
|
learnings: external_exports.string().optional().describe("New learnings (replaces existing). Supports #tags."),
|
|
41059
41061
|
labels: external_exports.array(external_exports.string()).optional().describe("New labels (replaces existing)")
|
|
41060
41062
|
}
|
|
41061
|
-
}, async ({
|
|
41063
|
+
}, async ({ itemId, taskId, description, learnings, labels }) => {
|
|
41062
41064
|
try {
|
|
41063
41065
|
const results = [];
|
|
41064
41066
|
if (description !== void 0) {
|
|
41065
|
-
await api.updateTask(
|
|
41067
|
+
await api.updateTask(itemId, taskId, {
|
|
41066
41068
|
action: "updateDescription",
|
|
41067
41069
|
description
|
|
41068
41070
|
});
|
|
41069
41071
|
results.push("description updated");
|
|
41070
41072
|
}
|
|
41071
41073
|
if (learnings !== void 0) {
|
|
41072
|
-
await api.updateTask(
|
|
41074
|
+
await api.updateTask(itemId, taskId, {
|
|
41073
41075
|
action: "updateLearnings",
|
|
41074
41076
|
learnings
|
|
41075
41077
|
});
|
|
41076
41078
|
results.push("learnings updated");
|
|
41077
41079
|
}
|
|
41078
41080
|
if (labels !== void 0) {
|
|
41079
|
-
const
|
|
41080
|
-
const allTasks =
|
|
41081
|
+
const item = await api.getFile(itemId);
|
|
41082
|
+
const allTasks = item.columns.flatMap((c) => c.tasks);
|
|
41081
41083
|
const task = allTasks.find((t) => t.id === taskId);
|
|
41082
41084
|
if (task) {
|
|
41083
|
-
await api.updateTask(
|
|
41085
|
+
await api.updateTask(itemId, taskId, {
|
|
41084
41086
|
action: "updateMetadata",
|
|
41085
41087
|
displayContent: task.displayContent,
|
|
41086
41088
|
metadata: { ...task.metadata, labels }
|
|
@@ -41095,20 +41097,20 @@ function registerTools(server2) {
|
|
|
41095
41097
|
});
|
|
41096
41098
|
server2.registerTool("find_knowledge", {
|
|
41097
41099
|
title: "Find Knowledge",
|
|
41098
|
-
description: "Search for knowledge items
|
|
41100
|
+
description: "Search specifically for curated knowledge items (knowledge:true) and tasks with captured learnings. Use for institutional decisions, patterns, and reference. For broader task history including descriptions, use search_context instead.",
|
|
41099
41101
|
inputSchema: {
|
|
41100
41102
|
query: external_exports.string().optional().describe("Text to search for in knowledge items"),
|
|
41101
41103
|
label: external_exports.string().optional().describe("Filter by label (without #)")
|
|
41102
41104
|
}
|
|
41103
41105
|
}, async ({ query, label }) => {
|
|
41104
41106
|
try {
|
|
41105
|
-
const
|
|
41107
|
+
const items = await api.listFiles();
|
|
41106
41108
|
const results = [];
|
|
41107
41109
|
const q = query?.toLowerCase();
|
|
41108
|
-
for (const
|
|
41110
|
+
for (const itemSummary of items) {
|
|
41109
41111
|
try {
|
|
41110
|
-
const
|
|
41111
|
-
for (const column of
|
|
41112
|
+
const item = await api.getFile(itemSummary.id);
|
|
41113
|
+
for (const column of item.columns) {
|
|
41112
41114
|
for (const task of column.tasks) {
|
|
41113
41115
|
const isKnowledge = task.metadata?.knowledge === true;
|
|
41114
41116
|
const hasLearnings = !!task.learnings;
|
|
@@ -41128,8 +41130,8 @@ function registerTools(server2) {
|
|
|
41128
41130
|
if (!hasLabel && !hasInlineTag) continue;
|
|
41129
41131
|
}
|
|
41130
41132
|
results.push({
|
|
41131
|
-
|
|
41132
|
-
|
|
41133
|
+
itemId: itemSummary.id,
|
|
41134
|
+
itemName: itemSummary.name,
|
|
41133
41135
|
taskId: task.id,
|
|
41134
41136
|
title: task.displayContent,
|
|
41135
41137
|
labels: task.metadata?.labels ?? [],
|
|
@@ -41140,7 +41142,7 @@ function registerTools(server2) {
|
|
|
41140
41142
|
}
|
|
41141
41143
|
}
|
|
41142
41144
|
} catch (err) {
|
|
41143
|
-
console.error(`[mcp] Failed to search
|
|
41145
|
+
console.error(`[mcp] Failed to search item ${itemSummary.id}:`, err);
|
|
41144
41146
|
}
|
|
41145
41147
|
}
|
|
41146
41148
|
return json2({ count: results.length, results });
|
|
@@ -41153,7 +41155,7 @@ function registerTools(server2) {
|
|
|
41153
41155
|
description: "Gather all knowledge about a topic and return a structured summary. This collects and organizes existing knowledge items \u2014 it does NOT generate AI content. Returns a paste-ready context brief.",
|
|
41154
41156
|
inputSchema: {
|
|
41155
41157
|
topic: external_exports.string().describe('Topic to synthesize knowledge about (e.g. "authentication", "pricing", "deployment")'),
|
|
41156
|
-
labels: external_exports.string().optional().describe('Comma-separated labels to filter by (e.g. "backend,security")')
|
|
41158
|
+
labels: external_exports.string().optional().describe('Comma-separated labels to filter by (e.g. "backend,security"). Unlike label on other tools which takes a single value, this accepts multiple comma-separated.')
|
|
41157
41159
|
}
|
|
41158
41160
|
}, async ({ topic, labels }) => {
|
|
41159
41161
|
try {
|
|
@@ -41167,7 +41169,7 @@ function registerTools(server2) {
|
|
|
41167
41169
|
title: "Import Memories",
|
|
41168
41170
|
description: "Bulk import knowledge items from external sources (AI conversation logs, meeting notes, etc.). Creates knowledge:true tasks for each item.",
|
|
41169
41171
|
inputSchema: {
|
|
41170
|
-
|
|
41172
|
+
itemId: external_exports.string().describe("The item ID to import into"),
|
|
41171
41173
|
columnId: external_exports.string().describe("The column ID to add items to"),
|
|
41172
41174
|
items: external_exports.array(external_exports.object({
|
|
41173
41175
|
content: external_exports.string().describe("Knowledge item title"),
|
|
@@ -41177,7 +41179,7 @@ function registerTools(server2) {
|
|
|
41177
41179
|
})).describe("Array of knowledge items to import"),
|
|
41178
41180
|
agentName: external_exports.string().regex(/^[\w-]+$/).optional().describe("Agent name to tag imports with")
|
|
41179
41181
|
}
|
|
41180
|
-
}, async ({
|
|
41182
|
+
}, async ({ itemId, columnId, items, agentName }) => {
|
|
41181
41183
|
try {
|
|
41182
41184
|
const results = [];
|
|
41183
41185
|
const errors = [];
|
|
@@ -41186,15 +41188,15 @@ function registerTools(server2) {
|
|
|
41186
41188
|
let taskContent = `${item.content} knowledge:true`;
|
|
41187
41189
|
if (item.labels?.length) taskContent += " " + item.labels.map((l) => `#${l}`).join(" ");
|
|
41188
41190
|
if (agentName) taskContent += ` built-by:${agentName}`;
|
|
41189
|
-
const result = await api.addTask(
|
|
41191
|
+
const result = await api.addTask(itemId, columnId, taskContent);
|
|
41190
41192
|
if (item.description && result?.taskId) {
|
|
41191
|
-
await api.updateTask(
|
|
41193
|
+
await api.updateTask(itemId, result.taskId, {
|
|
41192
41194
|
action: "updateDescription",
|
|
41193
41195
|
description: item.description
|
|
41194
41196
|
});
|
|
41195
41197
|
}
|
|
41196
41198
|
if (item.learnings && result?.taskId) {
|
|
41197
|
-
await api.updateTask(
|
|
41199
|
+
await api.updateTask(itemId, result.taskId, {
|
|
41198
41200
|
action: "updateLearnings",
|
|
41199
41201
|
learnings: item.learnings
|
|
41200
41202
|
});
|
|
@@ -41218,17 +41220,17 @@ function registerTools(server2) {
|
|
|
41218
41220
|
title: "Archive Completed Tasks",
|
|
41219
41221
|
description: "Bulk archive completed tasks. Optionally filter by age (days since completion) or column.",
|
|
41220
41222
|
inputSchema: {
|
|
41221
|
-
|
|
41223
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41222
41224
|
olderThanDays: external_exports.number().optional().describe("Only archive tasks completed more than N days ago"),
|
|
41223
41225
|
columnId: external_exports.string().optional().describe("Only archive tasks in this column")
|
|
41224
41226
|
}
|
|
41225
|
-
}, async ({
|
|
41227
|
+
}, async ({ itemId, olderThanDays, columnId }) => {
|
|
41226
41228
|
try {
|
|
41227
|
-
const
|
|
41229
|
+
const item = await api.getFile(itemId);
|
|
41228
41230
|
const now = /* @__PURE__ */ new Date();
|
|
41229
41231
|
let archived = 0;
|
|
41230
41232
|
const errors = [];
|
|
41231
|
-
for (const column of
|
|
41233
|
+
for (const column of item.columns) {
|
|
41232
41234
|
if (columnId && column.id !== columnId) continue;
|
|
41233
41235
|
for (const task of column.tasks) {
|
|
41234
41236
|
if (!task.checked) continue;
|
|
@@ -41241,7 +41243,7 @@ function registerTools(server2) {
|
|
|
41241
41243
|
if (daysSince < olderThanDays) continue;
|
|
41242
41244
|
}
|
|
41243
41245
|
try {
|
|
41244
|
-
await api.updateTask(
|
|
41246
|
+
await api.updateTask(itemId, task.id, {
|
|
41245
41247
|
action: "updateMetadata",
|
|
41246
41248
|
displayContent: task.displayContent,
|
|
41247
41249
|
metadata: { ...task.metadata, archived: true }
|
|
@@ -41264,47 +41266,47 @@ function registerTools(server2) {
|
|
|
41264
41266
|
|
|
41265
41267
|
// src/resources.ts
|
|
41266
41268
|
function registerResources(server2) {
|
|
41267
|
-
server2.registerResource("
|
|
41268
|
-
description: "List of all AutoMD boards",
|
|
41269
|
+
server2.registerResource("items", "automd://items", {
|
|
41270
|
+
description: "List of all AutoMD items (boards, checklists, pages)",
|
|
41269
41271
|
mimeType: "application/json"
|
|
41270
41272
|
}, async () => {
|
|
41271
|
-
const
|
|
41273
|
+
const items = await api.listFiles();
|
|
41272
41274
|
return {
|
|
41273
41275
|
contents: [
|
|
41274
41276
|
{
|
|
41275
|
-
uri: "automd://
|
|
41277
|
+
uri: "automd://items",
|
|
41276
41278
|
mimeType: "application/json",
|
|
41277
|
-
text: JSON.stringify(
|
|
41279
|
+
text: JSON.stringify(items, null, 2)
|
|
41278
41280
|
}
|
|
41279
41281
|
]
|
|
41280
41282
|
};
|
|
41281
41283
|
});
|
|
41282
|
-
server2.registerResource("
|
|
41283
|
-
description: "A single AutoMD board with columns and tasks",
|
|
41284
|
+
server2.registerResource("item", new ResourceTemplate("automd://items/{itemId}", { list: void 0 }), {
|
|
41285
|
+
description: "A single AutoMD item (board, checklist, or page) with columns and tasks",
|
|
41284
41286
|
mimeType: "application/json"
|
|
41285
|
-
}, async (uri, {
|
|
41286
|
-
const
|
|
41287
|
+
}, async (uri, { itemId }) => {
|
|
41288
|
+
const item = await api.getFile(itemId);
|
|
41287
41289
|
return {
|
|
41288
41290
|
contents: [
|
|
41289
41291
|
{
|
|
41290
41292
|
uri: uri.href,
|
|
41291
41293
|
mimeType: "application/json",
|
|
41292
|
-
text: JSON.stringify(
|
|
41294
|
+
text: JSON.stringify(item, null, 2)
|
|
41293
41295
|
}
|
|
41294
41296
|
]
|
|
41295
41297
|
};
|
|
41296
41298
|
});
|
|
41297
|
-
server2.registerResource("
|
|
41298
|
-
description: "Raw markdown content of
|
|
41299
|
+
server2.registerResource("item-markdown", new ResourceTemplate("automd://items/{itemId}/markdown", { list: void 0 }), {
|
|
41300
|
+
description: "Raw markdown content of an item",
|
|
41299
41301
|
mimeType: "text/markdown"
|
|
41300
|
-
}, async (uri, {
|
|
41301
|
-
const
|
|
41302
|
+
}, async (uri, { itemId }) => {
|
|
41303
|
+
const item = await api.getFile(itemId);
|
|
41302
41304
|
return {
|
|
41303
41305
|
contents: [
|
|
41304
41306
|
{
|
|
41305
41307
|
uri: uri.href,
|
|
41306
41308
|
mimeType: "text/markdown",
|
|
41307
|
-
text:
|
|
41309
|
+
text: item.markdown
|
|
41308
41310
|
}
|
|
41309
41311
|
]
|
|
41310
41312
|
};
|
|
@@ -41340,16 +41342,17 @@ function registerSystemPrompts(server2) {
|
|
|
41340
41342
|
|
|
41341
41343
|
## Core Concepts
|
|
41342
41344
|
|
|
41343
|
-
AutoMD has
|
|
41345
|
+
AutoMD has four item types:
|
|
41344
41346
|
- **Boards** \u2014 Kanban-style markdown files with columns (H1) and tasks (H2). Each has YAML frontmatter with metadata.
|
|
41345
41347
|
- **Checklists** \u2014 Task lists using ## (H2) headings with [ ]/[x] checkbox prefixes. Great for simple to-do lists and tracking.
|
|
41346
|
-
- **
|
|
41348
|
+
- **Pages** \u2014 Free-form markdown documents for specs, documentation, and reference material.
|
|
41349
|
+
- **Knowledge Bases** \u2014 Structured collections of knowledge entries (## H2) without checkboxes or progress tracking. Ideal for decisions, patterns, and institutional memory.
|
|
41347
41350
|
|
|
41348
|
-
All
|
|
41351
|
+
All four types support YAML frontmatter, descriptions, acceptance criteria, subtasks, and learnings.
|
|
41349
41352
|
|
|
41350
41353
|
**Knowledge items** are tasks with \`knowledge:true\` \u2014 they store decisions, patterns, references, and institutional memory. They use the same task infrastructure but represent knowledge, not work to be done.
|
|
41351
41354
|
|
|
41352
|
-
**Vocabulary** (optional YAML frontmatter) defines domain-specific label dimensions for
|
|
41355
|
+
**Vocabulary** (optional YAML frontmatter) defines domain-specific label dimensions for an item:
|
|
41353
41356
|
\`\`\`yaml
|
|
41354
41357
|
vocabulary:
|
|
41355
41358
|
technology: [react, node, python]
|
|
@@ -41389,13 +41392,13 @@ Description paragraph \u2014 background, context, the "why".
|
|
|
41389
41392
|
- Use \`synthesize_topic\` to assemble context briefs about a topic
|
|
41390
41393
|
|
|
41391
41394
|
## Available Tools
|
|
41392
|
-
-
|
|
41395
|
+
- Item management: list_items, get_item, create_item (supports board/checklist/page/knowledge types), delete_item, rename_item
|
|
41393
41396
|
- Task management: add_task, update_task, toggle_task, move_task, delete_task
|
|
41394
41397
|
- Metadata: update_task_metadata, update_acceptance_criteria, update_learnings
|
|
41395
41398
|
- Knowledge: add_knowledge, update_knowledge, find_knowledge, synthesize_topic, import_memories
|
|
41396
41399
|
- Search: search_tasks, search_context
|
|
41397
41400
|
- Bulk: bulk_update_tasks, archive_completed_tasks
|
|
41398
|
-
- Projects: list_projects,
|
|
41401
|
+
- Projects: list_projects, get_project_items, create_project
|
|
41399
41402
|
|
|
41400
41403
|
Always use the most specific tool for the job. Prefer knowledge tools for knowledge management over raw task tools.`
|
|
41401
41404
|
}
|
|
@@ -41409,11 +41412,11 @@ function registerWorkflowPrompts(server2) {
|
|
|
41409
41412
|
server2.registerPrompt("decompose_task", {
|
|
41410
41413
|
description: "Break down a complex task into subtasks with estimates",
|
|
41411
41414
|
argsSchema: {
|
|
41412
|
-
|
|
41415
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41413
41416
|
taskId: external_exports.string().describe("The task ID to decompose")
|
|
41414
41417
|
}
|
|
41415
|
-
}, async ({
|
|
41416
|
-
const board = await api.getFile(
|
|
41418
|
+
}, async ({ itemId, taskId }) => {
|
|
41419
|
+
const board = await api.getFile(itemId);
|
|
41417
41420
|
const allTasks = board.columns.flatMap((c) => c.tasks);
|
|
41418
41421
|
const task = allTasks.find((t) => t.id === taskId);
|
|
41419
41422
|
const taskJson = JSON.stringify(task, null, 2);
|
|
@@ -41433,7 +41436,7 @@ Please:
|
|
|
41433
41436
|
3. Identify any dependencies between subtasks
|
|
41434
41437
|
4. Suggest which subtasks could be parallelized
|
|
41435
41438
|
|
|
41436
|
-
|
|
41439
|
+
Subtasks are GFM checkboxes (\`- [ ] text\`) inside the parent task's content. Use update_task to add them to the parent task's body, or use add_task to create standalone tasks.`
|
|
41437
41440
|
}
|
|
41438
41441
|
}]
|
|
41439
41442
|
};
|
|
@@ -41441,11 +41444,11 @@ Provide the specific add_subtask tool calls to create each subtask.`
|
|
|
41441
41444
|
server2.registerPrompt("write_acceptance_criteria", {
|
|
41442
41445
|
description: "Write acceptance criteria for a task",
|
|
41443
41446
|
argsSchema: {
|
|
41444
|
-
|
|
41447
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41445
41448
|
taskId: external_exports.string().describe("The task ID")
|
|
41446
41449
|
}
|
|
41447
|
-
}, async ({
|
|
41448
|
-
const board = await api.getFile(
|
|
41450
|
+
}, async ({ itemId, taskId }) => {
|
|
41451
|
+
const board = await api.getFile(itemId);
|
|
41449
41452
|
const allTasks = board.columns.flatMap((c) => c.tasks);
|
|
41450
41453
|
const task = allTasks.find((t) => t.id === taskId);
|
|
41451
41454
|
const taskJson = JSON.stringify(task, null, 2);
|
|
@@ -41492,7 +41495,7 @@ Please:
|
|
|
41492
41495
|
3. Create initial tasks to get started (including knowledge items for key decisions)
|
|
41493
41496
|
4. Set up a knowledge base board alongside the task board if the project would benefit from it
|
|
41494
41497
|
|
|
41495
|
-
Use
|
|
41498
|
+
Use create_item with appropriate markdown including YAML frontmatter with vocabulary. Then add initial tasks with add_task and add_knowledge.`
|
|
41496
41499
|
}
|
|
41497
41500
|
}]
|
|
41498
41501
|
};
|
|
@@ -41539,7 +41542,7 @@ I'll paste my notes/memories below. Please:
|
|
|
41539
41542
|
1. Parse the content into individual knowledge items
|
|
41540
41543
|
2. Categorize each with appropriate labels
|
|
41541
41544
|
3. Use import_memories to bulk-create them on an appropriate board
|
|
41542
|
-
4. If no knowledge board exists, create one first with
|
|
41545
|
+
4. If no knowledge board exists, create one first with create_item
|
|
41543
41546
|
|
|
41544
41547
|
Each imported item should have:
|
|
41545
41548
|
- A clear, concise title
|
|
@@ -41559,11 +41562,11 @@ function registerPlanningPrompts(server2) {
|
|
|
41559
41562
|
server2.registerPrompt("sprint_planning", {
|
|
41560
41563
|
description: "Help plan next sprint from backlog",
|
|
41561
41564
|
argsSchema: {
|
|
41562
|
-
|
|
41565
|
+
itemId: external_exports.string().describe("The item ID to plan from"),
|
|
41563
41566
|
sprintCapacityHours: external_exports.number().optional().describe("Total sprint capacity in hours")
|
|
41564
41567
|
}
|
|
41565
|
-
}, async ({
|
|
41566
|
-
const board = await api.getFile(
|
|
41568
|
+
}, async ({ itemId, sprintCapacityHours }) => {
|
|
41569
|
+
const board = await api.getFile(itemId);
|
|
41567
41570
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41568
41571
|
const capacityNote = sprintCapacityHours ? `The team has ${sprintCapacityHours} hours of capacity for this sprint.` : "No specific capacity constraint was provided.";
|
|
41569
41572
|
return {
|
|
@@ -41594,11 +41597,11 @@ Provide specific tool calls the agent can execute to move tasks into the sprint
|
|
|
41594
41597
|
server2.registerPrompt("estimate_tasks", {
|
|
41595
41598
|
description: "Estimate effort for unestimated tasks on a board",
|
|
41596
41599
|
argsSchema: {
|
|
41597
|
-
|
|
41600
|
+
itemId: external_exports.string().describe("The item ID"),
|
|
41598
41601
|
columnId: external_exports.string().optional().describe("Optional column ID to scope estimation")
|
|
41599
41602
|
}
|
|
41600
|
-
}, async ({
|
|
41601
|
-
const board = await api.getFile(
|
|
41603
|
+
}, async ({ itemId, columnId }) => {
|
|
41604
|
+
const board = await api.getFile(itemId);
|
|
41602
41605
|
const allTasks = board.columns.flatMap(
|
|
41603
41606
|
(c) => columnId ? c.id === columnId ? c.tasks : [] : c.tasks
|
|
41604
41607
|
);
|
|
@@ -41627,10 +41630,10 @@ Provide update_task_metadata tool calls to set estimates.`
|
|
|
41627
41630
|
server2.registerPrompt("dependency_analysis", {
|
|
41628
41631
|
description: "Analyze task dependencies and suggest ordering",
|
|
41629
41632
|
argsSchema: {
|
|
41630
|
-
|
|
41633
|
+
itemId: external_exports.string().describe("The item ID to analyze")
|
|
41631
41634
|
}
|
|
41632
|
-
}, async ({
|
|
41633
|
-
const board = await api.getFile(
|
|
41635
|
+
}, async ({ itemId }) => {
|
|
41636
|
+
const board = await api.getFile(itemId);
|
|
41634
41637
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41635
41638
|
return {
|
|
41636
41639
|
messages: [{
|
|
@@ -41661,10 +41664,10 @@ function registerOperationsPrompts(server2) {
|
|
|
41661
41664
|
server2.registerPrompt("triage_tasks", {
|
|
41662
41665
|
description: "Review uncategorized tasks and suggest columns/priorities",
|
|
41663
41666
|
argsSchema: {
|
|
41664
|
-
|
|
41667
|
+
itemId: external_exports.string().describe("The item ID to triage")
|
|
41665
41668
|
}
|
|
41666
|
-
}, async ({
|
|
41667
|
-
const board = await api.getFile(
|
|
41669
|
+
}, async ({ itemId }) => {
|
|
41670
|
+
const board = await api.getFile(itemId);
|
|
41668
41671
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41669
41672
|
return {
|
|
41670
41673
|
messages: [{
|
|
@@ -41691,10 +41694,10 @@ For each suggestion, explain your reasoning and provide the specific tool calls
|
|
|
41691
41694
|
server2.registerPrompt("daily_standup", {
|
|
41692
41695
|
description: "Summarize progress: what's done, in progress, blocked",
|
|
41693
41696
|
argsSchema: {
|
|
41694
|
-
|
|
41697
|
+
itemId: external_exports.string().describe("The item ID to summarize")
|
|
41695
41698
|
}
|
|
41696
|
-
}, async ({
|
|
41697
|
-
const board = await api.getFile(
|
|
41699
|
+
}, async ({ itemId }) => {
|
|
41700
|
+
const board = await api.getFile(itemId);
|
|
41698
41701
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41699
41702
|
return {
|
|
41700
41703
|
messages: [{
|
|
@@ -41720,10 +41723,10 @@ Format the summary in a way that would be useful for a quick team sync.`
|
|
|
41720
41723
|
server2.registerPrompt("retrospective", {
|
|
41721
41724
|
description: "Run a retrospective on completed work and extract learnings",
|
|
41722
41725
|
argsSchema: {
|
|
41723
|
-
|
|
41726
|
+
itemId: external_exports.string().describe("The item ID to retrospect on")
|
|
41724
41727
|
}
|
|
41725
|
-
}, async ({
|
|
41726
|
-
const board = await api.getFile(
|
|
41728
|
+
}, async ({ itemId }) => {
|
|
41729
|
+
const board = await api.getFile(itemId);
|
|
41727
41730
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41728
41731
|
return {
|
|
41729
41732
|
messages: [{
|
|
@@ -41741,7 +41744,7 @@ Analyze completed tasks and the board state to provide:
|
|
|
41741
41744
|
3. **Action Items** \u2014 Concrete improvements for next iteration
|
|
41742
41745
|
4. **Learnings to Capture** \u2014 Key decisions and patterns worth preserving as knowledge items
|
|
41743
41746
|
|
|
41744
|
-
For each learning worth capturing, provide add_knowledge or
|
|
41747
|
+
For each learning worth capturing, provide add_knowledge tool calls for new knowledge items, or update_learnings tool calls to attach learnings to existing tasks.`
|
|
41745
41748
|
}
|
|
41746
41749
|
}]
|
|
41747
41750
|
};
|
|
@@ -41749,10 +41752,10 @@ For each learning worth capturing, provide add_knowledge or add_learning tool ca
|
|
|
41749
41752
|
server2.registerPrompt("board_cleanup", {
|
|
41750
41753
|
description: "Clean up stale tasks, duplicates, and organizational issues",
|
|
41751
41754
|
argsSchema: {
|
|
41752
|
-
|
|
41755
|
+
itemId: external_exports.string().describe("The item ID to clean up")
|
|
41753
41756
|
}
|
|
41754
|
-
}, async ({
|
|
41755
|
-
const board = await api.getFile(
|
|
41757
|
+
}, async ({ itemId }) => {
|
|
41758
|
+
const board = await api.getFile(itemId);
|
|
41756
41759
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41757
41760
|
return {
|
|
41758
41761
|
messages: [{
|
|
@@ -41779,11 +41782,11 @@ Provide the specific tool calls to implement each cleanup action.`
|
|
|
41779
41782
|
server2.registerPrompt("handoff_summary", {
|
|
41780
41783
|
description: "Generate a handoff summary for transitioning work between people or AI agents",
|
|
41781
41784
|
argsSchema: {
|
|
41782
|
-
|
|
41785
|
+
itemId: external_exports.string().describe("The item ID to summarize"),
|
|
41783
41786
|
context: external_exports.string().optional().describe('What the handoff is for (e.g. "new team member", "agent sync")')
|
|
41784
41787
|
}
|
|
41785
|
-
}, async ({
|
|
41786
|
-
const board = await api.getFile(
|
|
41788
|
+
}, async ({ itemId, context }) => {
|
|
41789
|
+
const board = await api.getFile(itemId);
|
|
41787
41790
|
const boardJson = JSON.stringify(board, null, 2);
|
|
41788
41791
|
return {
|
|
41789
41792
|
messages: [{
|
package/package.json
CHANGED
|
@@ -1,40 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "automd-mcp",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "MCP server for AutoMD — manage
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"automd-mcp": "./dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist"
|
|
12
|
-
],
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "automd-mcp",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "MCP server for AutoMD — manage boards, checklists, and pages stored as markdown",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"automd-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "tsx watch src/index.ts",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"prepublishOnly": "pnpm build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"kanban",
|
|
23
|
+
"markdown",
|
|
24
|
+
"automd",
|
|
25
|
+
"task-management"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/luka-zivkovic/automd"
|
|
30
|
+
},
|
|
31
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
32
|
+
"author": "Luka Zivkovic",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
35
|
+
"@types/mdast": "^4.0.4",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"tsx": "^4.19.0",
|
|
38
|
+
"typescript": "^5.7.2",
|
|
39
|
+
"zod": "^4.3.6"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/LICENSE.md
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# License
|
|
2
|
-
|
|
3
|
-
Portions of this software are licensed as follows:
|
|
4
|
-
|
|
5
|
-
- Content of branches other than the main branch (i.e. "master") is not licensed.
|
|
6
|
-
- Source code files that contain ".ee." in their filename or ".ee" in their dirname are NOT licensed under the Sustainable Use License. To use source code files that contain ".ee." in their filename or ".ee" in their dirname you must hold a valid AutoMD Enterprise License specifically allowing you access to such source code files, as defined in "LICENSE_EE.md".
|
|
7
|
-
- All third party components incorporated into the AutoMD Software are licensed under the original license provided by the owner of the applicable component.
|
|
8
|
-
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use License" as defined below.
|
|
9
|
-
|
|
10
|
-
# Sustainable Use License
|
|
11
|
-
|
|
12
|
-
Version 1.0
|
|
13
|
-
|
|
14
|
-
## Acceptance
|
|
15
|
-
|
|
16
|
-
By using the software, you agree to all of the terms and conditions below.
|
|
17
|
-
|
|
18
|
-
## Copyright License
|
|
19
|
-
|
|
20
|
-
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
|
21
|
-
|
|
22
|
-
## Limitations
|
|
23
|
-
|
|
24
|
-
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software. You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
25
|
-
|
|
26
|
-
## Patents
|
|
27
|
-
|
|
28
|
-
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
29
|
-
|
|
30
|
-
## Notices
|
|
31
|
-
|
|
32
|
-
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
|
33
|
-
|
|
34
|
-
## No Other Rights
|
|
35
|
-
|
|
36
|
-
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
37
|
-
|
|
38
|
-
## Termination
|
|
39
|
-
|
|
40
|
-
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
|
41
|
-
|
|
42
|
-
## No Liability
|
|
43
|
-
|
|
44
|
-
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
45
|
-
|
|
46
|
-
## Definitions
|
|
47
|
-
|
|
48
|
-
The **licensor** is the entity offering these terms, AutoMD (automd.io).
|
|
49
|
-
|
|
50
|
-
The **software** is the software the licensor makes available under these terms, including any portion of it.
|
|
51
|
-
|
|
52
|
-
**You** refers to the individual or entity agreeing to these terms.
|
|
53
|
-
|
|
54
|
-
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
55
|
-
|
|
56
|
-
**Your license** is the license granted to you for the software under these terms.
|
|
57
|
-
|
|
58
|
-
**Use** means anything you do with the software requiring your license.
|
|
59
|
-
|
|
60
|
-
**Trademark** means trademarks, service marks, and similar rights.
|