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