@vibetasks/mcp-server 0.3.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +205 -6
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -18,14 +18,19 @@ function setupTools(taskOps) {
18
18
  // create_task
19
19
  {
20
20
  name: "create_task",
21
- description: "Create a new task in TaskFlow. Can optionally be a subtask by providing parent_task_id.",
21
+ description: "Create a new task in VibeTasks. Use this instead of TodoWrite - tasks persist across sessions and sync everywhere.",
22
22
  inputSchema: z.object({
23
23
  title: z.string().describe("Task title (required)"),
24
- notes: z.string().optional().describe("Task notes in markdown"),
24
+ description: z.string().optional().describe("Brief description of what this task involves"),
25
+ notes: z.string().optional().describe("Detailed notes in markdown"),
26
+ subtasks: z.array(z.object({
27
+ title: z.string().describe("Subtask title"),
28
+ done: z.boolean().default(false).describe("Is this subtask completed?"),
29
+ notes: z.string().optional().describe("Progress notes for this subtask")
30
+ })).optional().describe("Inline subtasks - each with title, done status, and optional notes"),
25
31
  due_date: z.string().optional().describe("Due date (ISO 8601 format)"),
26
32
  priority: z.enum(["none", "low", "medium", "high"]).default("none").describe("Task priority"),
27
- tags: z.array(z.string()).optional().describe("Tag names to attach"),
28
- parent_task_id: z.string().optional().describe("Parent task ID to create this as a subtask")
33
+ tags: z.array(z.string()).optional().describe("Tag names to attach")
29
34
  }),
30
35
  handler: async (args, taskOps2) => {
31
36
  let tagIds = [];
@@ -35,13 +40,20 @@ function setupTools(taskOps) {
35
40
  tagIds.push(tag.id);
36
41
  }
37
42
  }
43
+ const subtasksJson = args.subtasks?.map((st) => ({
44
+ id: crypto.randomUUID(),
45
+ title: st.title,
46
+ done: st.done || false,
47
+ notes: st.notes
48
+ })) || [];
38
49
  const task = await taskOps2.createTask({
39
50
  title: args.title,
51
+ description: args.description,
40
52
  notes: args.notes,
41
53
  notes_format: "markdown",
42
54
  due_date: args.due_date,
43
55
  priority: args.priority,
44
- parent_task_id: args.parent_task_id
56
+ subtasks_json: subtasksJson
45
57
  });
46
58
  if (tagIds.length > 0) {
47
59
  await taskOps2.linkTaskTags(task.id, tagIds);
@@ -56,9 +68,10 @@ function setupTools(taskOps) {
56
68
  task: {
57
69
  id: task.id,
58
70
  title: task.title,
71
+ description: task.description,
59
72
  priority: task.priority,
60
73
  due_date: task.due_date,
61
- parent_task_id: task.parent_task_id,
74
+ subtasks: subtasksJson,
62
75
  created_at: task.created_at
63
76
  }
64
77
  },
@@ -669,6 +682,192 @@ Generated by TaskFlow MCP Server`;
669
682
  ]
670
683
  };
671
684
  }
685
+ },
686
+ // update_subtask
687
+ {
688
+ name: "update_subtask",
689
+ description: "Update a subtask within a task. Mark it done, add progress notes, or update the title. Use this to track progress on individual steps.",
690
+ inputSchema: z.object({
691
+ task_id: z.string().describe("Parent task ID"),
692
+ subtask_id: z.string().describe("Subtask ID to update"),
693
+ done: z.boolean().optional().describe("Mark subtask as done/not done"),
694
+ title: z.string().optional().describe("Update subtask title"),
695
+ notes: z.string().optional().describe('Add progress notes (e.g., "Completed auth module, need to test edge cases")')
696
+ }),
697
+ handler: async (args, taskOps2) => {
698
+ const task = await taskOps2.getTask(args.task_id);
699
+ const subtasks = task.subtasks_json || task.subtasks || [];
700
+ const subtaskIndex = subtasks.findIndex((st) => st.id === args.subtask_id);
701
+ if (subtaskIndex === -1) {
702
+ return {
703
+ content: [
704
+ {
705
+ type: "text",
706
+ text: JSON.stringify({ success: false, error: `Subtask ${args.subtask_id} not found` }, null, 2)
707
+ }
708
+ ]
709
+ };
710
+ }
711
+ if (args.done !== void 0) subtasks[subtaskIndex].done = args.done;
712
+ if (args.title !== void 0) subtasks[subtaskIndex].title = args.title;
713
+ if (args.notes !== void 0) subtasks[subtaskIndex].notes = args.notes;
714
+ const updated = await taskOps2.updateTask(args.task_id, { subtasks_json: subtasks });
715
+ return {
716
+ content: [
717
+ {
718
+ type: "text",
719
+ text: JSON.stringify(
720
+ {
721
+ success: true,
722
+ task_id: args.task_id,
723
+ subtask: subtasks[subtaskIndex],
724
+ all_subtasks: subtasks,
725
+ progress: `${subtasks.filter((s) => s.done).length}/${subtasks.length} done`
726
+ },
727
+ null,
728
+ 2
729
+ )
730
+ }
731
+ ]
732
+ };
733
+ }
734
+ },
735
+ // add_subtask
736
+ {
737
+ name: "add_subtask",
738
+ description: "Add a new subtask to an existing task. Use this when you discover new steps while working.",
739
+ inputSchema: z.object({
740
+ task_id: z.string().describe("Parent task ID"),
741
+ title: z.string().describe("Subtask title"),
742
+ notes: z.string().optional().describe("Optional notes")
743
+ }),
744
+ handler: async (args, taskOps2) => {
745
+ const task = await taskOps2.getTask(args.task_id);
746
+ const subtasks = task.subtasks_json || task.subtasks || [];
747
+ const newSubtask = {
748
+ id: crypto.randomUUID(),
749
+ title: args.title,
750
+ done: false,
751
+ notes: args.notes
752
+ };
753
+ subtasks.push(newSubtask);
754
+ await taskOps2.updateTask(args.task_id, { subtasks_json: subtasks });
755
+ return {
756
+ content: [
757
+ {
758
+ type: "text",
759
+ text: JSON.stringify(
760
+ {
761
+ success: true,
762
+ task_id: args.task_id,
763
+ new_subtask: newSubtask,
764
+ total_subtasks: subtasks.length
765
+ },
766
+ null,
767
+ 2
768
+ )
769
+ }
770
+ ]
771
+ };
772
+ }
773
+ },
774
+ // get_task_images
775
+ {
776
+ name: "get_task_images",
777
+ description: "Get image attachments for a task. Returns signed URLs that can be viewed. Use this to see mockups, screenshots, or error images attached to a task.",
778
+ inputSchema: z.object({
779
+ task_id: z.string().describe("Task ID to get images for")
780
+ }),
781
+ handler: async (args, taskOps2) => {
782
+ const task = await taskOps2.getTask(args.task_id);
783
+ const attachments = task.attachments || [];
784
+ const images = attachments.filter((a) => a.is_image || a.file_type?.startsWith("image/"));
785
+ const imageData = await Promise.all(
786
+ images.map(async (img) => {
787
+ const url = await taskOps2.getAttachmentUrl(img.storage_path);
788
+ return {
789
+ id: img.id,
790
+ file_name: img.file_name,
791
+ file_type: img.file_type,
792
+ url,
793
+ alt_text: img.alt_text,
794
+ ai_description: img.ai_description
795
+ };
796
+ })
797
+ );
798
+ return {
799
+ content: [
800
+ {
801
+ type: "text",
802
+ text: JSON.stringify(
803
+ {
804
+ success: true,
805
+ task_id: args.task_id,
806
+ task_title: task.title,
807
+ images: imageData,
808
+ count: imageData.length
809
+ },
810
+ null,
811
+ 2
812
+ )
813
+ }
814
+ ]
815
+ };
816
+ }
817
+ },
818
+ // get_current_task
819
+ {
820
+ name: "get_current_task",
821
+ description: 'Get the task you should be working on right now. Returns the first "vibing" task with full details including subtasks, description, context notes, and images. Call this at the start of a session to know where you left off.',
822
+ inputSchema: z.object({}),
823
+ handler: async (_args, taskOps2) => {
824
+ const allTasks = await taskOps2.getTasks("all");
825
+ const vibingTasks = allTasks.filter((t) => t.status === "vibing");
826
+ if (vibingTasks.length === 0) {
827
+ return {
828
+ content: [
829
+ {
830
+ type: "text",
831
+ text: JSON.stringify(
832
+ {
833
+ success: true,
834
+ current_task: null,
835
+ message: "No tasks currently vibing. Use list_tasks to see available tasks, or create_task to add one."
836
+ },
837
+ null,
838
+ 2
839
+ )
840
+ }
841
+ ]
842
+ };
843
+ }
844
+ const task = await taskOps2.getTask(vibingTasks[0].id);
845
+ return {
846
+ content: [
847
+ {
848
+ type: "text",
849
+ text: JSON.stringify(
850
+ {
851
+ success: true,
852
+ current_task: {
853
+ id: task.id,
854
+ title: task.title,
855
+ description: task.description,
856
+ context_notes: task.context_notes,
857
+ subtasks: task.subtasks_json || task.subtasks || [],
858
+ progress: task.subtasks_json ? `${task.subtasks_json.filter((s) => s.done).length}/${task.subtasks_json.length} subtasks done` : null,
859
+ priority: task.priority,
860
+ has_images: (task.attachments || []).some((a) => a.is_image || a.file_type?.startsWith("image/"))
861
+ },
862
+ other_vibing_count: vibingTasks.length - 1
863
+ },
864
+ null,
865
+ 2
866
+ )
867
+ }
868
+ ]
869
+ };
870
+ }
672
871
  }
673
872
  ];
674
873
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibetasks/mcp-server",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "description": "VibeTasks MCP Server for Claude Code, Cursor, and AI coding tools. Status-based task management: todo → vibing → done.",
5
5
  "author": "Vyas",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@modelcontextprotocol/sdk": "^0.5.0",
48
- "@vibetasks/core": "^0.3.0",
48
+ "@vibetasks/core": "^0.4.2",
49
49
  "zod": "^3.22.0"
50
50
  },
51
51
  "devDependencies": {