kaneo-mcp 0.0.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/src/index.ts ADDED
@@ -0,0 +1,1350 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import {
4
+ CallToolRequestSchema,
5
+ ListToolsRequestSchema,
6
+ type Tool,
7
+ } from "@modelcontextprotocol/sdk/types.js";
8
+ import { KaneoClient } from "./client.js";
9
+
10
+ interface ServerConfig {
11
+ baseUrl: string;
12
+ token: string;
13
+ }
14
+
15
+ class KaneoMCPServer {
16
+ private server: Server;
17
+ private client: KaneoClient;
18
+
19
+ constructor(config: ServerConfig) {
20
+ this.client = new KaneoClient(config);
21
+
22
+ this.server = new Server(
23
+ {
24
+ name: "kaneo-mcp-server",
25
+ version: "1.0.0",
26
+ },
27
+ {
28
+ capabilities: {
29
+ tools: {},
30
+ },
31
+ },
32
+ );
33
+
34
+ this.setupToolHandlers();
35
+ }
36
+
37
+ private setupToolHandlers() {
38
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
39
+ return { tools: this.getTools() };
40
+ });
41
+
42
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
43
+ const { name, arguments: args } = request.params;
44
+
45
+ try {
46
+ switch (name) {
47
+ // Health & Config
48
+ case "health":
49
+ return {
50
+ content: [
51
+ {
52
+ type: "text",
53
+ text: JSON.stringify(await this.client.health()),
54
+ },
55
+ ],
56
+ };
57
+ case "get_config":
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: JSON.stringify(await this.client.getConfig()),
63
+ },
64
+ ],
65
+ };
66
+
67
+ // Projects
68
+ case "list_projects":
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: JSON.stringify(
74
+ await this.client.listProjects(args.workspaceId),
75
+ ),
76
+ },
77
+ ],
78
+ };
79
+ case "create_project":
80
+ return {
81
+ content: [
82
+ {
83
+ type: "text",
84
+ text: JSON.stringify(await this.client.createProject(args)),
85
+ },
86
+ ],
87
+ };
88
+ case "get_project":
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: JSON.stringify(await this.client.getProject(args.id)),
94
+ },
95
+ ],
96
+ };
97
+ case "update_project":
98
+ return {
99
+ content: [
100
+ {
101
+ type: "text",
102
+ text: JSON.stringify(
103
+ await this.client.updateProject(args.id, args),
104
+ ),
105
+ },
106
+ ],
107
+ };
108
+ case "delete_project":
109
+ return {
110
+ content: [
111
+ {
112
+ type: "text",
113
+ text: JSON.stringify(
114
+ await this.client.deleteProject(args.id),
115
+ ),
116
+ },
117
+ ],
118
+ };
119
+ case "archive_project":
120
+ return {
121
+ content: [
122
+ {
123
+ type: "text",
124
+ text: JSON.stringify(
125
+ await this.client.archiveProject(args.id),
126
+ ),
127
+ },
128
+ ],
129
+ };
130
+ case "unarchive_project":
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: JSON.stringify(
136
+ await this.client.unarchiveProject(args.id),
137
+ ),
138
+ },
139
+ ],
140
+ };
141
+
142
+ // Tasks
143
+ case "list_tasks":
144
+ return {
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: JSON.stringify(
149
+ await this.client.listTasks(args.projectId, args),
150
+ ),
151
+ },
152
+ ],
153
+ };
154
+ case "create_task":
155
+ return {
156
+ content: [
157
+ {
158
+ type: "text",
159
+ text: JSON.stringify(
160
+ await this.client.createTask(args.projectId, args),
161
+ ),
162
+ },
163
+ ],
164
+ };
165
+ case "get_task":
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: JSON.stringify(await this.client.getTask(args.id)),
171
+ },
172
+ ],
173
+ };
174
+ case "update_task":
175
+ return {
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: JSON.stringify(
180
+ await this.client.updateTask(args.id, args),
181
+ ),
182
+ },
183
+ ],
184
+ };
185
+ case "delete_task":
186
+ return {
187
+ content: [
188
+ {
189
+ type: "text",
190
+ text: JSON.stringify(await this.client.deleteTask(args.id)),
191
+ },
192
+ ],
193
+ };
194
+ case "update_task_status":
195
+ return {
196
+ content: [
197
+ {
198
+ type: "text",
199
+ text: JSON.stringify(
200
+ await this.client.updateTaskStatus(args.id, args.status),
201
+ ),
202
+ },
203
+ ],
204
+ };
205
+ case "update_task_priority":
206
+ return {
207
+ content: [
208
+ {
209
+ type: "text",
210
+ text: JSON.stringify(
211
+ await this.client.updateTaskPriority(
212
+ args.id,
213
+ args.priority,
214
+ ),
215
+ ),
216
+ },
217
+ ],
218
+ };
219
+ case "update_task_assignee":
220
+ return {
221
+ content: [
222
+ {
223
+ type: "text",
224
+ text: JSON.stringify(
225
+ await this.client.updateTaskAssignee(args.id, args.userId),
226
+ ),
227
+ },
228
+ ],
229
+ };
230
+ case "update_task_due_date":
231
+ return {
232
+ content: [
233
+ {
234
+ type: "text",
235
+ text: JSON.stringify(
236
+ await this.client.updateTaskDueDate(args.id, args.dueDate),
237
+ ),
238
+ },
239
+ ],
240
+ };
241
+ case "update_task_title":
242
+ return {
243
+ content: [
244
+ {
245
+ type: "text",
246
+ text: JSON.stringify(
247
+ await this.client.updateTaskTitle(args.id, args.title),
248
+ ),
249
+ },
250
+ ],
251
+ };
252
+ case "update_task_description":
253
+ return {
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: JSON.stringify(
258
+ await this.client.updateTaskDescription(
259
+ args.id,
260
+ args.description,
261
+ ),
262
+ ),
263
+ },
264
+ ],
265
+ };
266
+ case "move_task":
267
+ return {
268
+ content: [
269
+ {
270
+ type: "text",
271
+ text: JSON.stringify(
272
+ await this.client.moveTask(args.id, args.projectId),
273
+ ),
274
+ },
275
+ ],
276
+ };
277
+
278
+ // Columns
279
+ case "list_columns":
280
+ return {
281
+ content: [
282
+ {
283
+ type: "text",
284
+ text: JSON.stringify(
285
+ await this.client.listColumns(args.projectId),
286
+ ),
287
+ },
288
+ ],
289
+ };
290
+ case "create_column":
291
+ return {
292
+ content: [
293
+ {
294
+ type: "text",
295
+ text: JSON.stringify(
296
+ await this.client.createColumn(args.projectId, args),
297
+ ),
298
+ },
299
+ ],
300
+ };
301
+ case "update_column":
302
+ return {
303
+ content: [
304
+ {
305
+ type: "text",
306
+ text: JSON.stringify(
307
+ await this.client.updateColumn(args.id, args),
308
+ ),
309
+ },
310
+ ],
311
+ };
312
+ case "delete_column":
313
+ return {
314
+ content: [
315
+ {
316
+ type: "text",
317
+ text: JSON.stringify(await this.client.deleteColumn(args.id)),
318
+ },
319
+ ],
320
+ };
321
+ case "reorder_columns":
322
+ return {
323
+ content: [
324
+ {
325
+ type: "text",
326
+ text: JSON.stringify(
327
+ await this.client.reorderColumns(
328
+ args.projectId,
329
+ args.columnIds,
330
+ ),
331
+ ),
332
+ },
333
+ ],
334
+ };
335
+
336
+ // Comments
337
+ case "list_comments":
338
+ return {
339
+ content: [
340
+ {
341
+ type: "text",
342
+ text: JSON.stringify(
343
+ await this.client.listComments(args.taskId),
344
+ ),
345
+ },
346
+ ],
347
+ };
348
+ case "create_comment":
349
+ return {
350
+ content: [
351
+ {
352
+ type: "text",
353
+ text: JSON.stringify(
354
+ await this.client.createComment(args.taskId, args.content),
355
+ ),
356
+ },
357
+ ],
358
+ };
359
+ case "update_comment":
360
+ return {
361
+ content: [
362
+ {
363
+ type: "text",
364
+ text: JSON.stringify(
365
+ await this.client.updateComment(args.id, args.content),
366
+ ),
367
+ },
368
+ ],
369
+ };
370
+ case "delete_comment":
371
+ return {
372
+ content: [
373
+ {
374
+ type: "text",
375
+ text: JSON.stringify(
376
+ await this.client.deleteComment(args.id),
377
+ ),
378
+ },
379
+ ],
380
+ };
381
+
382
+ // Labels
383
+ case "list_labels_for_task":
384
+ return {
385
+ content: [
386
+ {
387
+ type: "text",
388
+ text: JSON.stringify(
389
+ await this.client.listLabelsForTask(args.taskId),
390
+ ),
391
+ },
392
+ ],
393
+ };
394
+ case "list_workspace_labels":
395
+ return {
396
+ content: [
397
+ {
398
+ type: "text",
399
+ text: JSON.stringify(
400
+ await this.client.listWorkspaceLabels(args.workspaceId),
401
+ ),
402
+ },
403
+ ],
404
+ };
405
+ case "create_label":
406
+ return {
407
+ content: [
408
+ {
409
+ type: "text",
410
+ text: JSON.stringify(await this.client.createLabel(args)),
411
+ },
412
+ ],
413
+ };
414
+ case "get_label":
415
+ return {
416
+ content: [
417
+ {
418
+ type: "text",
419
+ text: JSON.stringify(await this.client.getLabel(args.id)),
420
+ },
421
+ ],
422
+ };
423
+ case "update_label":
424
+ return {
425
+ content: [
426
+ {
427
+ type: "text",
428
+ text: JSON.stringify(
429
+ await this.client.updateLabel(args.id, args),
430
+ ),
431
+ },
432
+ ],
433
+ };
434
+ case "delete_label":
435
+ return {
436
+ content: [
437
+ {
438
+ type: "text",
439
+ text: JSON.stringify(await this.client.deleteLabel(args.id)),
440
+ },
441
+ ],
442
+ };
443
+ case "attach_label_to_task":
444
+ return {
445
+ content: [
446
+ {
447
+ type: "text",
448
+ text: JSON.stringify(
449
+ await this.client.attachLabelToTask(
450
+ args.labelId,
451
+ args.taskId,
452
+ ),
453
+ ),
454
+ },
455
+ ],
456
+ };
457
+ case "detach_label_from_task":
458
+ return {
459
+ content: [
460
+ {
461
+ type: "text",
462
+ text: JSON.stringify(
463
+ await this.client.detachLabelFromTask(
464
+ args.labelId,
465
+ args.taskId,
466
+ ),
467
+ ),
468
+ },
469
+ ],
470
+ };
471
+
472
+ // Time Entries
473
+ case "list_time_entries":
474
+ return {
475
+ content: [
476
+ {
477
+ type: "text",
478
+ text: JSON.stringify(
479
+ await this.client.listTimeEntries(args.taskId),
480
+ ),
481
+ },
482
+ ],
483
+ };
484
+ case "get_time_entry":
485
+ return {
486
+ content: [
487
+ {
488
+ type: "text",
489
+ text: JSON.stringify(await this.client.getTimeEntry(args.id)),
490
+ },
491
+ ],
492
+ };
493
+ case "create_time_entry":
494
+ return {
495
+ content: [
496
+ {
497
+ type: "text",
498
+ text: JSON.stringify(await this.client.createTimeEntry(args)),
499
+ },
500
+ ],
501
+ };
502
+ case "update_time_entry":
503
+ return {
504
+ content: [
505
+ {
506
+ type: "text",
507
+ text: JSON.stringify(
508
+ await this.client.updateTimeEntry(args.id, args),
509
+ ),
510
+ },
511
+ ],
512
+ };
513
+
514
+ // Task Relations
515
+ case "list_task_relations":
516
+ return {
517
+ content: [
518
+ {
519
+ type: "text",
520
+ text: JSON.stringify(
521
+ await this.client.listTaskRelations(args.taskId),
522
+ ),
523
+ },
524
+ ],
525
+ };
526
+ case "create_task_relation":
527
+ return {
528
+ content: [
529
+ {
530
+ type: "text",
531
+ text: JSON.stringify(
532
+ await this.client.createTaskRelation(args),
533
+ ),
534
+ },
535
+ ],
536
+ };
537
+ case "delete_task_relation":
538
+ return {
539
+ content: [
540
+ {
541
+ type: "text",
542
+ text: JSON.stringify(
543
+ await this.client.deleteTaskRelation(args.id),
544
+ ),
545
+ },
546
+ ],
547
+ };
548
+
549
+ // Notifications
550
+ case "list_notifications":
551
+ return {
552
+ content: [
553
+ {
554
+ type: "text",
555
+ text: JSON.stringify(await this.client.listNotifications()),
556
+ },
557
+ ],
558
+ };
559
+ case "mark_notification_read":
560
+ return {
561
+ content: [
562
+ {
563
+ type: "text",
564
+ text: JSON.stringify(
565
+ await this.client.markNotificationRead(args.id),
566
+ ),
567
+ },
568
+ ],
569
+ };
570
+ case "mark_all_notifications_read":
571
+ return {
572
+ content: [
573
+ {
574
+ type: "text",
575
+ text: JSON.stringify(
576
+ await this.client.markAllNotificationsRead(),
577
+ ),
578
+ },
579
+ ],
580
+ };
581
+ case "clear_all_notifications":
582
+ return {
583
+ content: [
584
+ {
585
+ type: "text",
586
+ text: JSON.stringify(
587
+ await this.client.clearAllNotifications(),
588
+ ),
589
+ },
590
+ ],
591
+ };
592
+
593
+ // Workspace
594
+ case "list_workspace_members":
595
+ return {
596
+ content: [
597
+ {
598
+ type: "text",
599
+ text: JSON.stringify(
600
+ await this.client.listWorkspaceMembers(args.workspaceId),
601
+ ),
602
+ },
603
+ ],
604
+ };
605
+
606
+ // Search
607
+ case "search":
608
+ return {
609
+ content: [
610
+ {
611
+ type: "text",
612
+ text: JSON.stringify(
613
+ await this.client.search(args.q, args.type),
614
+ ),
615
+ },
616
+ ],
617
+ };
618
+
619
+ // Activity
620
+ case "list_activities":
621
+ return {
622
+ content: [
623
+ {
624
+ type: "text",
625
+ text: JSON.stringify(
626
+ await this.client.listActivities(args.taskId),
627
+ ),
628
+ },
629
+ ],
630
+ };
631
+
632
+ // Invitations
633
+ case "list_pending_invitations":
634
+ return {
635
+ content: [
636
+ {
637
+ type: "text",
638
+ text: JSON.stringify(
639
+ await this.client.listPendingInvitations(),
640
+ ),
641
+ },
642
+ ],
643
+ };
644
+ case "get_invitation":
645
+ return {
646
+ content: [
647
+ {
648
+ type: "text",
649
+ text: JSON.stringify(
650
+ await this.client.getInvitation(args.id),
651
+ ),
652
+ },
653
+ ],
654
+ };
655
+
656
+ default:
657
+ return {
658
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
659
+ isError: true,
660
+ };
661
+ }
662
+ } catch (error) {
663
+ return {
664
+ content: [
665
+ {
666
+ type: "text",
667
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
668
+ },
669
+ ],
670
+ isError: true,
671
+ };
672
+ }
673
+ });
674
+ }
675
+
676
+ private getTools(): Tool[] {
677
+ return [
678
+ // Health & Config
679
+ {
680
+ name: "health",
681
+ description: "Check if the Kaneo API server is healthy",
682
+ inputSchema: { type: "object", properties: {} },
683
+ },
684
+ {
685
+ name: "get_config",
686
+ description: "Get public configuration from the Kaneo API server",
687
+ inputSchema: { type: "object", properties: {} },
688
+ },
689
+
690
+ // Projects
691
+ {
692
+ name: "list_projects",
693
+ description: "List all projects in a workspace",
694
+ inputSchema: {
695
+ type: "object",
696
+ properties: {
697
+ workspaceId: { type: "string", description: "The workspace ID" },
698
+ },
699
+ required: ["workspaceId"],
700
+ },
701
+ },
702
+ {
703
+ name: "create_project",
704
+ description: "Create a new project in a workspace",
705
+ inputSchema: {
706
+ type: "object",
707
+ properties: {
708
+ name: { type: "string", description: "Project name" },
709
+ description: { type: "string", description: "Project description" },
710
+ workspaceId: { type: "string", description: "Workspace ID" },
711
+ },
712
+ required: ["name", "workspaceId"],
713
+ },
714
+ },
715
+ {
716
+ name: "get_project",
717
+ description: "Get a project by ID",
718
+ inputSchema: {
719
+ type: "object",
720
+ properties: { id: { type: "string", description: "Project ID" } },
721
+ required: ["id"],
722
+ },
723
+ },
724
+ {
725
+ name: "update_project",
726
+ description: "Update a project",
727
+ inputSchema: {
728
+ type: "object",
729
+ properties: {
730
+ id: { type: "string", description: "Project ID" },
731
+ name: { type: "string", description: "Project name" },
732
+ description: { type: "string", description: "Project description" },
733
+ },
734
+ required: ["id"],
735
+ },
736
+ },
737
+ {
738
+ name: "delete_project",
739
+ description: "Delete a project",
740
+ inputSchema: {
741
+ type: "object",
742
+ properties: { id: { type: "string", description: "Project ID" } },
743
+ required: ["id"],
744
+ },
745
+ },
746
+ {
747
+ name: "archive_project",
748
+ description: "Archive a project",
749
+ inputSchema: {
750
+ type: "object",
751
+ properties: { id: { type: "string", description: "Project ID" } },
752
+ required: ["id"],
753
+ },
754
+ },
755
+ {
756
+ name: "unarchive_project",
757
+ description: "Unarchive a project",
758
+ inputSchema: {
759
+ type: "object",
760
+ properties: { id: { type: "string", description: "Project ID" } },
761
+ required: ["id"],
762
+ },
763
+ },
764
+
765
+ // Tasks
766
+ {
767
+ name: "list_tasks",
768
+ description: "List tasks in a project with optional filters",
769
+ inputSchema: {
770
+ type: "object",
771
+ properties: {
772
+ projectId: { type: "string", description: "Project ID" },
773
+ status: {
774
+ type: "string",
775
+ description:
776
+ "Filter by status (todo, in_progress, done, canceled)",
777
+ },
778
+ priority: {
779
+ type: "string",
780
+ description: "Filter by priority (low, medium, high, urgent)",
781
+ },
782
+ assigneeId: {
783
+ type: "string",
784
+ description: "Filter by assignee ID",
785
+ },
786
+ },
787
+ required: ["projectId"],
788
+ },
789
+ },
790
+ {
791
+ name: "create_task",
792
+ description: "Create a new task in a project",
793
+ inputSchema: {
794
+ type: "object",
795
+ properties: {
796
+ projectId: { type: "string", description: "Project ID" },
797
+ title: { type: "string", description: "Task title" },
798
+ description: { type: "string", description: "Task description" },
799
+ status: {
800
+ type: "string",
801
+ description: "Task status (todo, in_progress, done, canceled)",
802
+ },
803
+ priority: {
804
+ type: "string",
805
+ description: "Task priority (low, medium, high, urgent)",
806
+ },
807
+ assigneeId: { type: "string", description: "Assignee user ID" },
808
+ startDate: { type: "string", description: "Start date (ISO 8601)" },
809
+ dueDate: { type: "string", description: "Due date (ISO 8601)" },
810
+ },
811
+ required: ["projectId", "title"],
812
+ },
813
+ },
814
+ {
815
+ name: "get_task",
816
+ description: "Get a task by ID",
817
+ inputSchema: {
818
+ type: "object",
819
+ properties: { id: { type: "string", description: "Task ID" } },
820
+ required: ["id"],
821
+ },
822
+ },
823
+ {
824
+ name: "update_task",
825
+ description: "Update a task",
826
+ inputSchema: {
827
+ type: "object",
828
+ properties: {
829
+ id: { type: "string", description: "Task ID" },
830
+ title: { type: "string", description: "Task title" },
831
+ description: { type: "string", description: "Task description" },
832
+ status: { type: "string", description: "Task status" },
833
+ priority: { type: "string", description: "Task priority" },
834
+ assigneeId: { type: "string", description: "Assignee user ID" },
835
+ startDate: { type: "string", description: "Start date" },
836
+ dueDate: { type: "string", description: "Due date" },
837
+ },
838
+ required: ["id"],
839
+ },
840
+ },
841
+ {
842
+ name: "delete_task",
843
+ description: "Delete a task",
844
+ inputSchema: {
845
+ type: "object",
846
+ properties: { id: { type: "string", description: "Task ID" } },
847
+ required: ["id"],
848
+ },
849
+ },
850
+ {
851
+ name: "update_task_status",
852
+ description: "Update only the status of a task",
853
+ inputSchema: {
854
+ type: "object",
855
+ properties: {
856
+ id: { type: "string", description: "Task ID" },
857
+ status: {
858
+ type: "string",
859
+ description: "New status (todo, in_progress, done, canceled)",
860
+ },
861
+ },
862
+ required: ["id", "status"],
863
+ },
864
+ },
865
+ {
866
+ name: "update_task_priority",
867
+ description: "Update only the priority of a task",
868
+ inputSchema: {
869
+ type: "object",
870
+ properties: {
871
+ id: { type: "string", description: "Task ID" },
872
+ priority: {
873
+ type: "string",
874
+ description: "New priority (low, medium, high, urgent)",
875
+ },
876
+ },
877
+ required: ["id", "priority"],
878
+ },
879
+ },
880
+ {
881
+ name: "update_task_assignee",
882
+ description: "Update the assignee of a task",
883
+ inputSchema: {
884
+ type: "object",
885
+ properties: {
886
+ id: { type: "string", description: "Task ID" },
887
+ userId: {
888
+ type: "string",
889
+ description: "User ID to assign (null to unassign)",
890
+ },
891
+ },
892
+ required: ["id"],
893
+ },
894
+ },
895
+ {
896
+ name: "update_task_due_date",
897
+ description: "Update the due date of a task",
898
+ inputSchema: {
899
+ type: "object",
900
+ properties: {
901
+ id: { type: "string", description: "Task ID" },
902
+ dueDate: {
903
+ type: "string",
904
+ description: "Due date ISO string (null to remove)",
905
+ },
906
+ },
907
+ required: ["id"],
908
+ },
909
+ },
910
+ {
911
+ name: "update_task_title",
912
+ description: "Update only the title of a task",
913
+ inputSchema: {
914
+ type: "object",
915
+ properties: {
916
+ id: { type: "string", description: "Task ID" },
917
+ title: { type: "string", description: "New title" },
918
+ },
919
+ required: ["id", "title"],
920
+ },
921
+ },
922
+ {
923
+ name: "update_task_description",
924
+ description: "Update only the description of a task",
925
+ inputSchema: {
926
+ type: "object",
927
+ properties: {
928
+ id: { type: "string", description: "Task ID" },
929
+ description: { type: "string", description: "New description" },
930
+ },
931
+ required: ["id", "description"],
932
+ },
933
+ },
934
+ {
935
+ name: "move_task",
936
+ description: "Move a task to another project",
937
+ inputSchema: {
938
+ type: "object",
939
+ properties: {
940
+ id: { type: "string", description: "Task ID" },
941
+ projectId: { type: "string", description: "Target project ID" },
942
+ },
943
+ required: ["id", "projectId"],
944
+ },
945
+ },
946
+
947
+ // Columns
948
+ {
949
+ name: "list_columns",
950
+ description: "List all columns in a project",
951
+ inputSchema: {
952
+ type: "object",
953
+ properties: {
954
+ projectId: { type: "string", description: "Project ID" },
955
+ },
956
+ required: ["projectId"],
957
+ },
958
+ },
959
+ {
960
+ name: "create_column",
961
+ description: "Create a new column in a project",
962
+ inputSchema: {
963
+ type: "object",
964
+ properties: {
965
+ projectId: { type: "string", description: "Project ID" },
966
+ name: { type: "string", description: "Column name" },
967
+ order: { type: "number", description: "Column order" },
968
+ },
969
+ required: ["projectId", "name"],
970
+ },
971
+ },
972
+ {
973
+ name: "update_column",
974
+ description: "Update a column",
975
+ inputSchema: {
976
+ type: "object",
977
+ properties: {
978
+ id: { type: "string", description: "Column ID" },
979
+ name: { type: "string", description: "Column name" },
980
+ order: { type: "number", description: "Column order" },
981
+ },
982
+ required: ["id"],
983
+ },
984
+ },
985
+ {
986
+ name: "delete_column",
987
+ description: "Delete a column",
988
+ inputSchema: {
989
+ type: "object",
990
+ properties: { id: { type: "string", description: "Column ID" } },
991
+ required: ["id"],
992
+ },
993
+ },
994
+ {
995
+ name: "reorder_columns",
996
+ description: "Reorder columns in a project",
997
+ inputSchema: {
998
+ type: "object",
999
+ properties: {
1000
+ projectId: { type: "string", description: "Project ID" },
1001
+ columnIds: {
1002
+ type: "array",
1003
+ items: { type: "string" },
1004
+ description: "Array of column IDs in new order",
1005
+ },
1006
+ },
1007
+ required: ["projectId", "columnIds"],
1008
+ },
1009
+ },
1010
+
1011
+ // Comments
1012
+ {
1013
+ name: "list_comments",
1014
+ description: "List all comments on a task",
1015
+ inputSchema: {
1016
+ type: "object",
1017
+ properties: { taskId: { type: "string", description: "Task ID" } },
1018
+ required: ["taskId"],
1019
+ },
1020
+ },
1021
+ {
1022
+ name: "create_comment",
1023
+ description: "Add a comment to a task",
1024
+ inputSchema: {
1025
+ type: "object",
1026
+ properties: {
1027
+ taskId: { type: "string", description: "Task ID" },
1028
+ content: { type: "string", description: "Comment content" },
1029
+ },
1030
+ required: ["taskId", "content"],
1031
+ },
1032
+ },
1033
+ {
1034
+ name: "update_comment",
1035
+ description: "Update a comment (author only)",
1036
+ inputSchema: {
1037
+ type: "object",
1038
+ properties: {
1039
+ id: { type: "string", description: "Comment ID" },
1040
+ content: { type: "string", description: "New content" },
1041
+ },
1042
+ required: ["id", "content"],
1043
+ },
1044
+ },
1045
+ {
1046
+ name: "delete_comment",
1047
+ description: "Delete a comment (author only)",
1048
+ inputSchema: {
1049
+ type: "object",
1050
+ properties: { id: { type: "string", description: "Comment ID" } },
1051
+ required: ["id"],
1052
+ },
1053
+ },
1054
+
1055
+ // Labels
1056
+ {
1057
+ name: "list_labels_for_task",
1058
+ description: "List all labels attached to a task",
1059
+ inputSchema: {
1060
+ type: "object",
1061
+ properties: { taskId: { type: "string", description: "Task ID" } },
1062
+ required: ["taskId"],
1063
+ },
1064
+ },
1065
+ {
1066
+ name: "list_workspace_labels",
1067
+ description: "List all labels in a workspace",
1068
+ inputSchema: {
1069
+ type: "object",
1070
+ properties: {
1071
+ workspaceId: { type: "string", description: "Workspace ID" },
1072
+ },
1073
+ required: ["workspaceId"],
1074
+ },
1075
+ },
1076
+ {
1077
+ name: "create_label",
1078
+ description: "Create a new label in a workspace",
1079
+ inputSchema: {
1080
+ type: "object",
1081
+ properties: {
1082
+ name: { type: "string", description: "Label name" },
1083
+ color: { type: "string", description: "Label color (hex code)" },
1084
+ workspaceId: { type: "string", description: "Workspace ID" },
1085
+ },
1086
+ required: ["name", "color", "workspaceId"],
1087
+ },
1088
+ },
1089
+ {
1090
+ name: "get_label",
1091
+ description: "Get a label by ID",
1092
+ inputSchema: {
1093
+ type: "object",
1094
+ properties: { id: { type: "string", description: "Label ID" } },
1095
+ required: ["id"],
1096
+ },
1097
+ },
1098
+ {
1099
+ name: "update_label",
1100
+ description: "Update a label",
1101
+ inputSchema: {
1102
+ type: "object",
1103
+ properties: {
1104
+ id: { type: "string", description: "Label ID" },
1105
+ name: { type: "string", description: "Label name" },
1106
+ color: { type: "string", description: "Label color" },
1107
+ },
1108
+ required: ["id"],
1109
+ },
1110
+ },
1111
+ {
1112
+ name: "delete_label",
1113
+ description: "Delete a label",
1114
+ inputSchema: {
1115
+ type: "object",
1116
+ properties: { id: { type: "string", description: "Label ID" } },
1117
+ required: ["id"],
1118
+ },
1119
+ },
1120
+ {
1121
+ name: "attach_label_to_task",
1122
+ description: "Attach a label to a task",
1123
+ inputSchema: {
1124
+ type: "object",
1125
+ properties: {
1126
+ labelId: { type: "string", description: "Label ID" },
1127
+ taskId: { type: "string", description: "Task ID" },
1128
+ },
1129
+ required: ["labelId", "taskId"],
1130
+ },
1131
+ },
1132
+ {
1133
+ name: "detach_label_from_task",
1134
+ description: "Detach a label from a task",
1135
+ inputSchema: {
1136
+ type: "object",
1137
+ properties: {
1138
+ labelId: { type: "string", description: "Label ID" },
1139
+ taskId: { type: "string", description: "Task ID" },
1140
+ },
1141
+ required: ["labelId", "taskId"],
1142
+ },
1143
+ },
1144
+
1145
+ // Time Entries
1146
+ {
1147
+ name: "list_time_entries",
1148
+ description: "List time entries for a task",
1149
+ inputSchema: {
1150
+ type: "object",
1151
+ properties: { taskId: { type: "string", description: "Task ID" } },
1152
+ required: ["taskId"],
1153
+ },
1154
+ },
1155
+ {
1156
+ name: "get_time_entry",
1157
+ description: "Get a time entry by ID",
1158
+ inputSchema: {
1159
+ type: "object",
1160
+ properties: { id: { type: "string", description: "Time entry ID" } },
1161
+ required: ["id"],
1162
+ },
1163
+ },
1164
+ {
1165
+ name: "create_time_entry",
1166
+ description: "Create a time entry for a task",
1167
+ inputSchema: {
1168
+ type: "object",
1169
+ properties: {
1170
+ taskId: { type: "string", description: "Task ID" },
1171
+ duration: { type: "number", description: "Duration in seconds" },
1172
+ description: {
1173
+ type: "string",
1174
+ description: "Time entry description",
1175
+ },
1176
+ },
1177
+ required: ["taskId", "duration"],
1178
+ },
1179
+ },
1180
+ {
1181
+ name: "update_time_entry",
1182
+ description: "Update a time entry",
1183
+ inputSchema: {
1184
+ type: "object",
1185
+ properties: {
1186
+ id: { type: "string", description: "Time entry ID" },
1187
+ duration: { type: "number", description: "Duration in seconds" },
1188
+ description: {
1189
+ type: "string",
1190
+ description: "Time entry description",
1191
+ },
1192
+ },
1193
+ required: ["id"],
1194
+ },
1195
+ },
1196
+
1197
+ // Task Relations
1198
+ {
1199
+ name: "list_task_relations",
1200
+ description: "List all relations for a task",
1201
+ inputSchema: {
1202
+ type: "object",
1203
+ properties: { taskId: { type: "string", description: "Task ID" } },
1204
+ required: ["taskId"],
1205
+ },
1206
+ },
1207
+ {
1208
+ name: "create_task_relation",
1209
+ description: "Create a relation between tasks",
1210
+ inputSchema: {
1211
+ type: "object",
1212
+ properties: {
1213
+ taskId: { type: "string", description: "Source task ID" },
1214
+ relatedTaskId: { type: "string", description: "Related task ID" },
1215
+ type: {
1216
+ type: "string",
1217
+ enum: ["subtask", "blocks", "related"],
1218
+ description: "Relation type",
1219
+ },
1220
+ },
1221
+ required: ["taskId", "relatedTaskId", "type"],
1222
+ },
1223
+ },
1224
+ {
1225
+ name: "delete_task_relation",
1226
+ description: "Delete a task relation",
1227
+ inputSchema: {
1228
+ type: "object",
1229
+ properties: { id: { type: "string", description: "Relation ID" } },
1230
+ required: ["id"],
1231
+ },
1232
+ },
1233
+
1234
+ // Notifications
1235
+ {
1236
+ name: "list_notifications",
1237
+ description: "List all notifications for the current user",
1238
+ inputSchema: { type: "object", properties: {} },
1239
+ },
1240
+ {
1241
+ name: "mark_notification_read",
1242
+ description: "Mark a notification as read",
1243
+ inputSchema: {
1244
+ type: "object",
1245
+ properties: {
1246
+ id: { type: "string", description: "Notification ID" },
1247
+ },
1248
+ required: ["id"],
1249
+ },
1250
+ },
1251
+ {
1252
+ name: "mark_all_notifications_read",
1253
+ description: "Mark all notifications as read",
1254
+ inputSchema: { type: "object", properties: {} },
1255
+ },
1256
+ {
1257
+ name: "clear_all_notifications",
1258
+ description: "Clear all notifications",
1259
+ inputSchema: { type: "object", properties: {} },
1260
+ },
1261
+
1262
+ // Workspace
1263
+ {
1264
+ name: "list_workspace_members",
1265
+ description: "List all members in a workspace",
1266
+ inputSchema: {
1267
+ type: "object",
1268
+ properties: {
1269
+ workspaceId: { type: "string", description: "Workspace ID" },
1270
+ },
1271
+ required: ["workspaceId"],
1272
+ },
1273
+ },
1274
+
1275
+ // Search
1276
+ {
1277
+ name: "search",
1278
+ description: "Search across projects, tasks, comments, and activities",
1279
+ inputSchema: {
1280
+ type: "object",
1281
+ properties: {
1282
+ q: { type: "string", description: "Search query" },
1283
+ type: {
1284
+ type: "string",
1285
+ enum: [
1286
+ "all",
1287
+ "tasks",
1288
+ "projects",
1289
+ "workspaces",
1290
+ "comments",
1291
+ "activities",
1292
+ ],
1293
+ description: "Search type",
1294
+ },
1295
+ },
1296
+ required: ["q"],
1297
+ },
1298
+ },
1299
+
1300
+ // Activity
1301
+ {
1302
+ name: "list_activities",
1303
+ description: "List all activities for a task",
1304
+ inputSchema: {
1305
+ type: "object",
1306
+ properties: { taskId: { type: "string", description: "Task ID" } },
1307
+ required: ["taskId"],
1308
+ },
1309
+ },
1310
+
1311
+ // Invitations
1312
+ {
1313
+ name: "list_pending_invitations",
1314
+ description: "List pending invitations for the current user",
1315
+ inputSchema: { type: "object", properties: {} },
1316
+ },
1317
+ {
1318
+ name: "get_invitation",
1319
+ description: "Get an invitation by ID",
1320
+ inputSchema: {
1321
+ type: "object",
1322
+ properties: { id: { type: "string", description: "Invitation ID" } },
1323
+ required: ["id"],
1324
+ },
1325
+ },
1326
+ ];
1327
+ }
1328
+
1329
+ async start() {
1330
+ const transport = new StdioServerTransport();
1331
+ await this.server.connect(transport);
1332
+ }
1333
+ }
1334
+
1335
+ async function main() {
1336
+ const baseUrl = process.env.KANEO_BASE_URL || "http://localhost:1337";
1337
+ const token = process.env.KANEO_TOKEN;
1338
+
1339
+ if (!token) {
1340
+ console.error("Error: KANEO_TOKEN environment variable is required");
1341
+ process.exit(1);
1342
+ }
1343
+
1344
+ const server = new KaneoMCPServer({ baseUrl, token });
1345
+ await server.start();
1346
+ }
1347
+
1348
+ main().catch(console.error);
1349
+
1350
+ export { KaneoMCPServer, type ServerConfig };