projoflow-mcp-server 1.1.5 → 1.2.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.
Files changed (2) hide show
  1. package/index.js +415 -2
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -275,7 +275,7 @@ const TOOLS = [
275
275
  },
276
276
  {
277
277
  name: "update_task",
278
- description: "Update a task's details or status",
278
+ description: "Update a task's details, status, or assignment. Use list_workspace_members to find user IDs.",
279
279
  inputSchema: {
280
280
  type: "object",
281
281
  properties: {
@@ -284,7 +284,9 @@ const TOOLS = [
284
284
  description: { type: "string" },
285
285
  status: { type: "string", enum: ["todo", "in_progress", "review", "done"] },
286
286
  priority: { type: "string", enum: ["low", "medium", "high", "urgent"] },
287
- due_date: { type: "string" }
287
+ due_date: { type: "string", description: "Due date (YYYY-MM-DD)" },
288
+ assigned_to: { type: "string", description: "User ID to assign/reassign the task to (get from list_workspace_members)" },
289
+ estimated_hours: { type: "number", description: "Estimated hours to complete" }
288
290
  },
289
291
  required: ["task_id"]
290
292
  }
@@ -489,6 +491,218 @@ const TOOLS = [
489
491
  },
490
492
  required: ["file_path"]
491
493
  }
494
+ },
495
+ {
496
+ name: "get_task",
497
+ description: "Get full details of a specific task including assignee info",
498
+ inputSchema: {
499
+ type: "object",
500
+ properties: {
501
+ task_id: { type: "string", description: "Task ID" }
502
+ },
503
+ required: ["task_id"]
504
+ }
505
+ },
506
+ {
507
+ name: "delete_task",
508
+ description: "Delete a task permanently",
509
+ inputSchema: {
510
+ type: "object",
511
+ properties: {
512
+ task_id: { type: "string", description: "Task ID" }
513
+ },
514
+ required: ["task_id"]
515
+ }
516
+ },
517
+ {
518
+ name: "get_client",
519
+ description: "Get full details of a specific client",
520
+ inputSchema: {
521
+ type: "object",
522
+ properties: {
523
+ client_id: { type: "string", description: "Client ID" }
524
+ },
525
+ required: ["client_id"]
526
+ }
527
+ },
528
+ {
529
+ name: "update_client",
530
+ description: "Update a client's details",
531
+ inputSchema: {
532
+ type: "object",
533
+ properties: {
534
+ client_id: { type: "string", description: "Client ID" },
535
+ name: { type: "string" },
536
+ contact_name: { type: "string" },
537
+ email: { type: "string" },
538
+ phone: { type: "string" },
539
+ company: { type: "string" },
540
+ notes: { type: "string" }
541
+ },
542
+ required: ["client_id"]
543
+ }
544
+ },
545
+ {
546
+ name: "delete_client",
547
+ description: "Delete a client permanently. Will fail if client has linked projects.",
548
+ inputSchema: {
549
+ type: "object",
550
+ properties: {
551
+ client_id: { type: "string", description: "Client ID" }
552
+ },
553
+ required: ["client_id"]
554
+ }
555
+ },
556
+ {
557
+ name: "create_lead",
558
+ description: "Create a new lead/inquiry",
559
+ inputSchema: {
560
+ type: "object",
561
+ properties: {
562
+ company_name: { type: "string", description: "Company or person name" },
563
+ contact_name: { type: "string", description: "Contact person name" },
564
+ email: { type: "string" },
565
+ phone: { type: "string" },
566
+ budget_range: { type: "string", enum: ["under_5k", "5k_10k", "10k_25k", "25k_50k", "50k_plus", "not_sure"] },
567
+ timeline: { type: "string", enum: ["asap", "1_month", "2_3_months", "3_6_months", "flexible"] },
568
+ project_description: { type: "string", description: "What the lead needs" },
569
+ source: { type: "string", description: "How they found you" },
570
+ notes: { type: "string" },
571
+ status: { type: "string", enum: ["new", "contacted", "qualified", "converted", "lost"], default: "new" }
572
+ },
573
+ required: ["company_name", "email"]
574
+ }
575
+ },
576
+ {
577
+ name: "get_lead",
578
+ description: "Get full details of a specific lead",
579
+ inputSchema: {
580
+ type: "object",
581
+ properties: {
582
+ lead_id: { type: "string", description: "Lead ID" }
583
+ },
584
+ required: ["lead_id"]
585
+ }
586
+ },
587
+ {
588
+ name: "delete_lead",
589
+ description: "Delete a lead permanently",
590
+ inputSchema: {
591
+ type: "object",
592
+ properties: {
593
+ lead_id: { type: "string", description: "Lead ID" }
594
+ },
595
+ required: ["lead_id"]
596
+ }
597
+ },
598
+ {
599
+ name: "list_notes",
600
+ description: "List notes for a project, optionally filtered by type",
601
+ inputSchema: {
602
+ type: "object",
603
+ properties: {
604
+ project_id: { type: "string", description: "Project ID" },
605
+ note_type: { type: "string", enum: ["general", "meeting", "technical", "decision"], description: "Filter by note type" }
606
+ },
607
+ required: ["project_id"]
608
+ }
609
+ },
610
+ {
611
+ name: "update_note",
612
+ description: "Update a project note",
613
+ inputSchema: {
614
+ type: "object",
615
+ properties: {
616
+ note_id: { type: "string", description: "Note ID" },
617
+ title: { type: "string" },
618
+ content: { type: "string" },
619
+ note_type: { type: "string", enum: ["general", "meeting", "technical", "decision"] }
620
+ },
621
+ required: ["note_id"]
622
+ }
623
+ },
624
+ {
625
+ name: "delete_note",
626
+ description: "Delete a project note permanently",
627
+ inputSchema: {
628
+ type: "object",
629
+ properties: {
630
+ note_id: { type: "string", description: "Note ID" }
631
+ },
632
+ required: ["note_id"]
633
+ }
634
+ },
635
+ {
636
+ name: "delete_document",
637
+ description: "Delete a project document from storage and database",
638
+ inputSchema: {
639
+ type: "object",
640
+ properties: {
641
+ document_id: { type: "string", description: "Document ID from list_project_documents" }
642
+ },
643
+ required: ["document_id"]
644
+ }
645
+ },
646
+ {
647
+ name: "update_time_entry",
648
+ description: "Update a time entry",
649
+ inputSchema: {
650
+ type: "object",
651
+ properties: {
652
+ time_entry_id: { type: "string", description: "Time entry ID" },
653
+ duration_minutes: { type: "number" },
654
+ description: { type: "string" },
655
+ date: { type: "string", description: "Date (YYYY-MM-DD)" },
656
+ billable: { type: "boolean" },
657
+ task_id: { type: "string" }
658
+ },
659
+ required: ["time_entry_id"]
660
+ }
661
+ },
662
+ {
663
+ name: "delete_time_entry",
664
+ description: "Delete a time entry permanently",
665
+ inputSchema: {
666
+ type: "object",
667
+ properties: {
668
+ time_entry_id: { type: "string", description: "Time entry ID" }
669
+ },
670
+ required: ["time_entry_id"]
671
+ }
672
+ },
673
+ {
674
+ name: "update_comment",
675
+ description: "Update a task comment's content",
676
+ inputSchema: {
677
+ type: "object",
678
+ properties: {
679
+ comment_id: { type: "string", description: "Comment ID" },
680
+ content: { type: "string", description: "New comment content" }
681
+ },
682
+ required: ["comment_id", "content"]
683
+ }
684
+ },
685
+ {
686
+ name: "delete_comment",
687
+ description: "Delete a task comment permanently",
688
+ inputSchema: {
689
+ type: "object",
690
+ properties: {
691
+ comment_id: { type: "string", description: "Comment ID" }
692
+ },
693
+ required: ["comment_id"]
694
+ }
695
+ },
696
+ {
697
+ name: "delete_project",
698
+ description: "Delete a project and all its related data (tasks, time entries, notes, documents) permanently",
699
+ inputSchema: {
700
+ type: "object",
701
+ properties: {
702
+ project_id: { type: "string", description: "Project ID" }
703
+ },
704
+ required: ["project_id"]
705
+ }
492
706
  }
493
707
  ];
494
708
 
@@ -940,6 +1154,205 @@ async function handleTool(name, args) {
940
1154
  };
941
1155
  }
942
1156
 
1157
+ case "get_task": {
1158
+ const { data, error } = await supabase
1159
+ .from("tasks")
1160
+ .select("*, users(id, email, name), projects(id, name)")
1161
+ .eq("id", args.task_id)
1162
+ .single();
1163
+ if (error) throw new Error(error.message);
1164
+ return data;
1165
+ }
1166
+
1167
+ case "delete_task": {
1168
+ const { error } = await supabase
1169
+ .from("tasks")
1170
+ .delete()
1171
+ .eq("id", args.task_id);
1172
+ if (error) throw new Error(error.message);
1173
+ return { success: true, message: "Task deleted" };
1174
+ }
1175
+
1176
+ case "get_client": {
1177
+ const { data, error } = await supabase
1178
+ .from("clients")
1179
+ .select("*")
1180
+ .eq("id", args.client_id)
1181
+ .single();
1182
+ if (error) throw new Error(error.message);
1183
+ return data;
1184
+ }
1185
+
1186
+ case "update_client": {
1187
+ const { client_id, ...updates } = args;
1188
+ const { data, error } = await supabase
1189
+ .from("clients")
1190
+ .update(updates)
1191
+ .eq("id", client_id)
1192
+ .select()
1193
+ .single();
1194
+ if (error) throw new Error(error.message);
1195
+ return data;
1196
+ }
1197
+
1198
+ case "delete_client": {
1199
+ const { error } = await supabase
1200
+ .from("clients")
1201
+ .delete()
1202
+ .eq("id", args.client_id);
1203
+ if (error) throw new Error(error.message);
1204
+ return { success: true, message: "Client deleted" };
1205
+ }
1206
+
1207
+ case "create_lead": {
1208
+ const { data, error } = await supabase
1209
+ .from("leads")
1210
+ .insert({
1211
+ company_name: args.company_name,
1212
+ contact_name: args.contact_name,
1213
+ email: args.email,
1214
+ phone: args.phone,
1215
+ budget_range: args.budget_range,
1216
+ timeline: args.timeline,
1217
+ project_description: args.project_description,
1218
+ source: args.source,
1219
+ notes: args.notes,
1220
+ status: args.status || "new"
1221
+ })
1222
+ .select()
1223
+ .single();
1224
+ if (error) throw new Error(error.message);
1225
+ return data;
1226
+ }
1227
+
1228
+ case "get_lead": {
1229
+ const { data, error } = await supabase
1230
+ .from("leads")
1231
+ .select("*")
1232
+ .eq("id", args.lead_id)
1233
+ .single();
1234
+ if (error) throw new Error(error.message);
1235
+ return data;
1236
+ }
1237
+
1238
+ case "delete_lead": {
1239
+ const { error } = await supabase
1240
+ .from("leads")
1241
+ .delete()
1242
+ .eq("id", args.lead_id);
1243
+ if (error) throw new Error(error.message);
1244
+ return { success: true, message: "Lead deleted" };
1245
+ }
1246
+
1247
+ case "list_notes": {
1248
+ let query = supabase
1249
+ .from("notes")
1250
+ .select("*")
1251
+ .eq("project_id", args.project_id)
1252
+ .order("created_at", { ascending: false });
1253
+ if (args.note_type) query = query.eq("note_type", args.note_type);
1254
+ const { data, error } = await query;
1255
+ if (error) throw new Error(error.message);
1256
+ return data;
1257
+ }
1258
+
1259
+ case "update_note": {
1260
+ const { note_id, ...updates } = args;
1261
+ const { data, error } = await supabase
1262
+ .from("notes")
1263
+ .update(updates)
1264
+ .eq("id", note_id)
1265
+ .select()
1266
+ .single();
1267
+ if (error) throw new Error(error.message);
1268
+ return data;
1269
+ }
1270
+
1271
+ case "delete_note": {
1272
+ const { error } = await supabase
1273
+ .from("notes")
1274
+ .delete()
1275
+ .eq("id", args.note_id);
1276
+ if (error) throw new Error(error.message);
1277
+ return { success: true, message: "Note deleted" };
1278
+ }
1279
+
1280
+ case "delete_document": {
1281
+ // Get the file path first
1282
+ const { data: doc, error: fetchError } = await supabase
1283
+ .from("project_documents")
1284
+ .select("file_path")
1285
+ .eq("id", args.document_id)
1286
+ .single();
1287
+ if (fetchError) throw new Error(fetchError.message);
1288
+
1289
+ // Delete from storage
1290
+ if (doc.file_path) {
1291
+ const { error: storageError } = await supabase.storage
1292
+ .from("project-documents")
1293
+ .remove([doc.file_path]);
1294
+ if (storageError) throw new Error(`Storage deletion failed: ${storageError.message}`);
1295
+ }
1296
+
1297
+ // Delete from database
1298
+ const { error } = await supabase
1299
+ .from("project_documents")
1300
+ .delete()
1301
+ .eq("id", args.document_id);
1302
+ if (error) throw new Error(error.message);
1303
+ return { success: true, message: "Document deleted" };
1304
+ }
1305
+
1306
+ case "update_time_entry": {
1307
+ const { time_entry_id, ...updates } = args;
1308
+ const { data, error } = await supabase
1309
+ .from("time_entries")
1310
+ .update(updates)
1311
+ .eq("id", time_entry_id)
1312
+ .select("*, projects(name), tasks(title)")
1313
+ .single();
1314
+ if (error) throw new Error(error.message);
1315
+ return data;
1316
+ }
1317
+
1318
+ case "delete_time_entry": {
1319
+ const { error } = await supabase
1320
+ .from("time_entries")
1321
+ .delete()
1322
+ .eq("id", args.time_entry_id);
1323
+ if (error) throw new Error(error.message);
1324
+ return { success: true, message: "Time entry deleted" };
1325
+ }
1326
+
1327
+ case "update_comment": {
1328
+ const { data, error } = await supabase
1329
+ .from("task_comments")
1330
+ .update({ content: args.content })
1331
+ .eq("id", args.comment_id)
1332
+ .select()
1333
+ .single();
1334
+ if (error) throw new Error(error.message);
1335
+ return data;
1336
+ }
1337
+
1338
+ case "delete_comment": {
1339
+ const { error } = await supabase
1340
+ .from("task_comments")
1341
+ .delete()
1342
+ .eq("id", args.comment_id);
1343
+ if (error) throw new Error(error.message);
1344
+ return { success: true, message: "Comment deleted" };
1345
+ }
1346
+
1347
+ case "delete_project": {
1348
+ const { error } = await supabase
1349
+ .from("projects")
1350
+ .delete()
1351
+ .eq("id", args.project_id);
1352
+ if (error) throw new Error(error.message);
1353
+ return { success: true, message: "Project and all related data deleted" };
1354
+ }
1355
+
943
1356
  default:
944
1357
  throw new Error(`Unknown tool: ${name}`);
945
1358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projoflow-mcp-server",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for ProjoFlow project management - connect AI tools to your projects",
5
5
  "main": "index.js",
6
6
  "type": "module",