@opsee/mcp-server 0.5.6 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -1
- package/gen/api/v1/models_pb.d.ts +102 -1
- package/gen/api/v1/models_pb.js +21 -2
- package/gen/api/v1/notification_pb.d.ts +21 -1
- package/gen/api/v1/notification_pb.js +12 -5
- package/gen/api/v1/task_dependency_pb.d.ts +151 -0
- package/gen/api/v1/task_dependency_pb.js +60 -0
- package/gen/api/v1/task_pb.d.ts +136 -0
- package/gen/api/v1/task_pb.js +37 -9
- package/package.json +1 -1
- package/src/client/api.ts +12 -0
- package/src/server.ts +6 -0
- package/src/tools/comments.ts +96 -0
- package/src/tools/labels.ts +199 -0
- package/src/tools/task-dependencies.ts +96 -0
- package/src/tools/tasks.ts +56 -8
- package/src/tools/user.ts +41 -1
- package/src/utils/format.ts +81 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// @generated by protoc-gen-es v2.2.3
|
|
2
|
+
// @generated from file api/v1/task_dependency.proto (package api.v1, syntax proto3)
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
|
|
5
|
+
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
|
|
6
|
+
import { file_google_protobuf_empty } from "@bufbuild/protobuf/wkt";
|
|
7
|
+
import { file_google_api_annotations } from "../../google/api/annotations_pb";
|
|
8
|
+
import { file_validate_validate } from "../../validate/validate_pb";
|
|
9
|
+
import { file_api_v1_pagination } from "./pagination_pb";
|
|
10
|
+
import { file_api_v1_models } from "./models_pb";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Describes the file api/v1/task_dependency.proto.
|
|
14
|
+
*/
|
|
15
|
+
export const file_api_v1_task_dependency = /*@__PURE__*/
|
|
16
|
+
fileDesc("ChxhcGkvdjEvdGFza19kZXBlbmRlbmN5LnByb3RvEgZhcGkudjEijAEKGEFkZFRhc2tEZXBlbmRlbmN5UmVxdWVzdBIdCgxmcm9tX3Rhc2tfaWQYASABKA1CB/pCBCoCKAESGwoKdG9fdGFza19pZBgCIAEoDUIH+kIEKgIoARI0CgR0eXBlGAMgASgOMhouYXBpLnYxLlRhc2tEZXBlbmRlbmN5VHlwZUIK+kIHggEEEAEgACJeChpHZXRUYXNrRGVwZW5kZW5jaWVzUmVxdWVzdBIYCgd0YXNrX2lkGAEgASgNQgf6QgQqAigBEiYKCnBhZ2luYXRpb24YAiABKAsyEi5hcGkudjEuUGFnaW5hdGlvbiIyChtEZWxldGVUYXNrRGVwZW5kZW5jeVJlcXVlc3QSEwoCaWQYASABKA1CB/pCBCoCKAEiTAoZQWRkVGFza0RlcGVuZGVuY3lSZXNwb25zZRIvCg90YXNrX2RlcGVuZGVuY3kYASABKAsyFi5hcGkudjEuVGFza0RlcGVuZGVuY3kieAobR2V0VGFza0RlcGVuZGVuY2llc1Jlc3BvbnNlEjEKEXRhc2tfZGVwZW5kZW5jaWVzGAEgAygLMhYuYXBpLnYxLlRhc2tEZXBlbmRlbmN5EiYKCnBhZ2luYXRpb24YAiABKAsyEi5hcGkudjEuUGFnaW5hdGlvbjKYAwoVVGFza0RlcGVuZGVuY3lTZXJ2aWNlEn4KEUFkZFRhc2tEZXBlbmRlbmN5EiAuYXBpLnYxLkFkZFRhc2tEZXBlbmRlbmN5UmVxdWVzdBohLmFwaS52MS5BZGRUYXNrRGVwZW5kZW5jeVJlc3BvbnNlIiSC0+STAh46ASoiGS9hcGkvdjEvdGFzay1kZXBlbmRlbmNpZXMSgQEKE0dldFRhc2tEZXBlbmRlbmNpZXMSIi5hcGkudjEuR2V0VGFza0RlcGVuZGVuY2llc1JlcXVlc3QaIy5hcGkudjEuR2V0VGFza0RlcGVuZGVuY2llc1Jlc3BvbnNlIiGC0+STAhsSGS9hcGkvdjEvdGFzay1kZXBlbmRlbmNpZXMSewoURGVsZXRlVGFza0RlcGVuZGVuY3kSIy5hcGkudjEuRGVsZXRlVGFza0RlcGVuZGVuY3lSZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IiaC0+STAiAqHi9hcGkvdjEvdGFzay1kZXBlbmRlbmNpZXMve2lkfUJ4Cgpjb20uYXBpLnYxQhNUYXNrRGVwZW5kZW5jeVByb3RvUAFaHG9wc2VlL2JhY2tlbmQvZ2VuL2FwaS92MTtnZW6iAgNBWFiqAgZBcGkuVjHKAgZBcGlcVjHiAhJBcGlcVjFcR1BCTWV0YWRhdGHqAgdBcGk6OlYxYgZwcm90bzM", [file_google_protobuf_empty, file_google_api_annotations, file_validate_validate, file_api_v1_pagination, file_api_v1_models]);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Describes the message api.v1.AddTaskDependencyRequest.
|
|
20
|
+
* Use `create(AddTaskDependencyRequestSchema)` to create a new message.
|
|
21
|
+
*/
|
|
22
|
+
export const AddTaskDependencyRequestSchema = /*@__PURE__*/
|
|
23
|
+
messageDesc(file_api_v1_task_dependency, 0);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Describes the message api.v1.GetTaskDependenciesRequest.
|
|
27
|
+
* Use `create(GetTaskDependenciesRequestSchema)` to create a new message.
|
|
28
|
+
*/
|
|
29
|
+
export const GetTaskDependenciesRequestSchema = /*@__PURE__*/
|
|
30
|
+
messageDesc(file_api_v1_task_dependency, 1);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Describes the message api.v1.DeleteTaskDependencyRequest.
|
|
34
|
+
* Use `create(DeleteTaskDependencyRequestSchema)` to create a new message.
|
|
35
|
+
*/
|
|
36
|
+
export const DeleteTaskDependencyRequestSchema = /*@__PURE__*/
|
|
37
|
+
messageDesc(file_api_v1_task_dependency, 2);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Describes the message api.v1.AddTaskDependencyResponse.
|
|
41
|
+
* Use `create(AddTaskDependencyResponseSchema)` to create a new message.
|
|
42
|
+
*/
|
|
43
|
+
export const AddTaskDependencyResponseSchema = /*@__PURE__*/
|
|
44
|
+
messageDesc(file_api_v1_task_dependency, 3);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Describes the message api.v1.GetTaskDependenciesResponse.
|
|
48
|
+
* Use `create(GetTaskDependenciesResponseSchema)` to create a new message.
|
|
49
|
+
*/
|
|
50
|
+
export const GetTaskDependenciesResponseSchema = /*@__PURE__*/
|
|
51
|
+
messageDesc(file_api_v1_task_dependency, 4);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Service
|
|
55
|
+
*
|
|
56
|
+
* @generated from service api.v1.TaskDependencyService
|
|
57
|
+
*/
|
|
58
|
+
export const TaskDependencyService = /*@__PURE__*/
|
|
59
|
+
serviceDesc(file_api_v1_task_dependency, 0);
|
|
60
|
+
|
package/gen/api/v1/task_pb.d.ts
CHANGED
|
@@ -303,6 +303,11 @@ export declare type GetTasksRequest = Message<"api.v1.GetTasksRequest"> & {
|
|
|
303
303
|
* @generated from field: api.v1.FilterOptions filter_options = 3;
|
|
304
304
|
*/
|
|
305
305
|
filterOptions?: FilterOptions;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @generated from field: repeated uint32 label_ids = 4;
|
|
309
|
+
*/
|
|
310
|
+
labelIds: number[];
|
|
306
311
|
};
|
|
307
312
|
|
|
308
313
|
/**
|
|
@@ -497,9 +502,18 @@ export declare type ImportTasksRequest = Message<"api.v1.ImportTasksRequest"> &
|
|
|
497
502
|
projectId: number;
|
|
498
503
|
|
|
499
504
|
/**
|
|
505
|
+
* csv_content is capped at 10 MiB to prevent OOM from a malicious or
|
|
506
|
+
* accidental gigabyte upload. The service layer additionally caps the
|
|
507
|
+
* row count.
|
|
508
|
+
*
|
|
500
509
|
* @generated from field: bytes csv_content = 2;
|
|
501
510
|
*/
|
|
502
511
|
csvContent: Uint8Array;
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* @generated from field: bool skip_notifications = 3;
|
|
515
|
+
*/
|
|
516
|
+
skipNotifications: boolean;
|
|
503
517
|
};
|
|
504
518
|
|
|
505
519
|
/**
|
|
@@ -508,6 +522,32 @@ export declare type ImportTasksRequest = Message<"api.v1.ImportTasksRequest"> &
|
|
|
508
522
|
*/
|
|
509
523
|
export declare const ImportTasksRequestSchema: GenMessage<ImportTasksRequest>;
|
|
510
524
|
|
|
525
|
+
/**
|
|
526
|
+
* @generated from message api.v1.ImportedTask
|
|
527
|
+
*/
|
|
528
|
+
export declare type ImportedTask = Message<"api.v1.ImportedTask"> & {
|
|
529
|
+
/**
|
|
530
|
+
* @generated from field: string external_id = 1;
|
|
531
|
+
*/
|
|
532
|
+
externalId: string;
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* @generated from field: uint32 task_id = 2;
|
|
536
|
+
*/
|
|
537
|
+
taskId: number;
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @generated from field: bool created = 3;
|
|
541
|
+
*/
|
|
542
|
+
created: boolean;
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Describes the message api.v1.ImportedTask.
|
|
547
|
+
* Use `create(ImportedTaskSchema)` to create a new message.
|
|
548
|
+
*/
|
|
549
|
+
export declare const ImportedTaskSchema: GenMessage<ImportedTask>;
|
|
550
|
+
|
|
511
551
|
/**
|
|
512
552
|
* @generated from message api.v1.ImportTasksResponse
|
|
513
553
|
*/
|
|
@@ -531,6 +571,16 @@ export declare type ImportTasksResponse = Message<"api.v1.ImportTasksResponse">
|
|
|
531
571
|
* @generated from field: repeated string errors = 4;
|
|
532
572
|
*/
|
|
533
573
|
errors: string[];
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @generated from field: int32 skipped_count = 5;
|
|
577
|
+
*/
|
|
578
|
+
skippedCount: number;
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* @generated from field: repeated api.v1.ImportedTask created_tasks = 6;
|
|
582
|
+
*/
|
|
583
|
+
createdTasks: ImportedTask[];
|
|
534
584
|
};
|
|
535
585
|
|
|
536
586
|
/**
|
|
@@ -539,6 +589,84 @@ export declare type ImportTasksResponse = Message<"api.v1.ImportTasksResponse">
|
|
|
539
589
|
*/
|
|
540
590
|
export declare const ImportTasksResponseSchema: GenMessage<ImportTasksResponse>;
|
|
541
591
|
|
|
592
|
+
/**
|
|
593
|
+
* @generated from message api.v1.TaskLink
|
|
594
|
+
*/
|
|
595
|
+
export declare type TaskLink = Message<"api.v1.TaskLink"> & {
|
|
596
|
+
/**
|
|
597
|
+
* external_id matches the column we add on Task; 128-char varchar in DB.
|
|
598
|
+
*
|
|
599
|
+
* @generated from field: string external_id = 1;
|
|
600
|
+
*/
|
|
601
|
+
externalId: string;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @generated from field: optional string parent_external_id = 2;
|
|
605
|
+
*/
|
|
606
|
+
parentExternalId?: string;
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* @generated from field: optional string milestone_name = 3;
|
|
610
|
+
*/
|
|
611
|
+
milestoneName?: string;
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Describes the message api.v1.TaskLink.
|
|
616
|
+
* Use `create(TaskLinkSchema)` to create a new message.
|
|
617
|
+
*/
|
|
618
|
+
export declare const TaskLinkSchema: GenMessage<TaskLink>;
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* @generated from message api.v1.LinkTasksByExternalIdRequest
|
|
622
|
+
*/
|
|
623
|
+
export declare type LinkTasksByExternalIdRequest = Message<"api.v1.LinkTasksByExternalIdRequest"> & {
|
|
624
|
+
/**
|
|
625
|
+
* @generated from field: uint32 project_id = 1;
|
|
626
|
+
*/
|
|
627
|
+
projectId: number;
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Cap on per-call links keeps the in-transaction work bounded; matches the
|
|
631
|
+
* per-import row cap on the service side.
|
|
632
|
+
*
|
|
633
|
+
* @generated from field: repeated api.v1.TaskLink links = 2;
|
|
634
|
+
*/
|
|
635
|
+
links: TaskLink[];
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Describes the message api.v1.LinkTasksByExternalIdRequest.
|
|
640
|
+
* Use `create(LinkTasksByExternalIdRequestSchema)` to create a new message.
|
|
641
|
+
*/
|
|
642
|
+
export declare const LinkTasksByExternalIdRequestSchema: GenMessage<LinkTasksByExternalIdRequest>;
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* @generated from message api.v1.LinkTasksByExternalIdResponse
|
|
646
|
+
*/
|
|
647
|
+
export declare type LinkTasksByExternalIdResponse = Message<"api.v1.LinkTasksByExternalIdResponse"> & {
|
|
648
|
+
/**
|
|
649
|
+
* @generated from field: int32 linked_parents = 1;
|
|
650
|
+
*/
|
|
651
|
+
linkedParents: number;
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* @generated from field: int32 linked_milestones = 2;
|
|
655
|
+
*/
|
|
656
|
+
linkedMilestones: number;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* @generated from field: repeated string errors = 3;
|
|
660
|
+
*/
|
|
661
|
+
errors: string[];
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Describes the message api.v1.LinkTasksByExternalIdResponse.
|
|
666
|
+
* Use `create(LinkTasksByExternalIdResponseSchema)` to create a new message.
|
|
667
|
+
*/
|
|
668
|
+
export declare const LinkTasksByExternalIdResponseSchema: GenMessage<LinkTasksByExternalIdResponse>;
|
|
669
|
+
|
|
542
670
|
/**
|
|
543
671
|
* @generated from message api.v1.BulkEditTasksRequest
|
|
544
672
|
*/
|
|
@@ -733,6 +861,14 @@ export declare const TaskService: GenService<{
|
|
|
733
861
|
input: typeof ImportTasksRequestSchema;
|
|
734
862
|
output: typeof ImportTasksResponseSchema;
|
|
735
863
|
},
|
|
864
|
+
/**
|
|
865
|
+
* @generated from rpc api.v1.TaskService.LinkTasksByExternalId
|
|
866
|
+
*/
|
|
867
|
+
linkTasksByExternalId: {
|
|
868
|
+
methodKind: "unary";
|
|
869
|
+
input: typeof LinkTasksByExternalIdRequestSchema;
|
|
870
|
+
output: typeof LinkTasksByExternalIdResponseSchema;
|
|
871
|
+
},
|
|
736
872
|
/**
|
|
737
873
|
* @generated from rpc api.v1.TaskService.AddTask
|
|
738
874
|
*/
|
package/gen/api/v1/task_pb.js
CHANGED
|
@@ -14,7 +14,7 @@ import { file_api_v1_models } from "./models_pb";
|
|
|
14
14
|
* Describes the file api/v1/task.proto.
|
|
15
15
|
*/
|
|
16
16
|
export const file_api_v1_task = /*@__PURE__*/
|
|
17
|
-
fileDesc("ChFhcGkvdjEvdGFzay5wcm90bxIGYXBpLnYxIvkFCg5BZGRUYXNrUmVxdWVzdBIiCgppZGVudGlmaWVyGAEgASgJQgn6QgZyBBABGDJIAIgBARIZCgV0aXRsZRgCIAEoCUIK+kIHcgUQARjIARIYCgtkZXNjcmlwdGlvbhgDIAEoCUgBiAEBEh4KDWRpc3BsYXlfb3JkZXIYBCABKAVCB/pCBBoCKAASIgoMc3RvcnlfcG9pbnRzGAUgASgFQgf6QgQaAigBSAKIAQESLAoPZXN0aW1hdGVkX2hvdXJzGAYgASgBQg76QgsSCSkAAAAAAAAAAEgDiAEBEikKDGFjdHVhbF9ob3VycxgHIAEoAUIO+kILEgkpAAAAAAAAAABIBIgBARIsCghkdWVfZGF0ZRgIIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASFwoPYWlfbW9kZV9lbmFibGVkGAkgASgIEhoKDW1ldGFkYXRhX2pzb24YCiABKAlIBYgBARIQCghib2FyZF9pZBgLIAEoDRIXCg9ib2FyZF9jb2x1bW5faWQYDCABKA0SEgoKcHJvamVjdF9pZBgNIAEoDRIUCgx0YXNrX3R5cGVfaWQYDiABKA0SGAoQdGFza19wcmlvcml0eV9pZBgPIAEoDRIYChByZXBvcnRlcl91c2VyX2lkGBAgASgNEh0KEGFzc2lnbmVkX3VzZXJfaWQYESABKA1IBogBARIbCg5wYXJlbnRfdGFza19pZBgSIAEoDUgHiAEBEhYKDnJlcG9zaXRvcnlfaWRzGBMgAygNEhUKCGN5Y2xlX2lkGBQgASgNSAiIAQFCDQoLX2lkZW50aWZpZXJCDgoMX2Rlc2NyaXB0aW9uQg8KDV9zdG9yeV9wb2ludHNCEgoQX2VzdGltYXRlZF9ob3Vyc0IPCg1fYWN0dWFsX2hvdXJzQhAKDl9tZXRhZGF0YV9qc29uQhMKEV9hc3NpZ25lZF91c2VyX2lkQhEKD19wYXJlbnRfdGFza19pZEILCglfY3ljbGVfaWQi4gYKD0VkaXRUYXNrUmVxdWVzdBITCgJpZBgBIAEoDUIH+kIEKgIoARIdCgppZGVudGlmaWVyGAIgASgJQgn6QgZyBBABGDISGQoFdGl0bGUYAyABKAlCCvpCB3IFEAEYyAESGAoLZGVzY3JpcHRpb24YBCABKAlIAIgBARIeCg1kaXNwbGF5X29yZGVyGAUgASgFQgf6QgQaAigAEiIKDHN0b3J5X3BvaW50cxgGIAEoBUIH+kIEGgIoAUgBiAEBEiwKD2VzdGltYXRlZF9ob3VycxgHIAEoAUIO+
|
|
17
|
+
fileDesc("ChFhcGkvdjEvdGFzay5wcm90bxIGYXBpLnYxIvkFCg5BZGRUYXNrUmVxdWVzdBIiCgppZGVudGlmaWVyGAEgASgJQgn6QgZyBBABGDJIAIgBARIZCgV0aXRsZRgCIAEoCUIK+kIHcgUQARjIARIYCgtkZXNjcmlwdGlvbhgDIAEoCUgBiAEBEh4KDWRpc3BsYXlfb3JkZXIYBCABKAVCB/pCBBoCKAASIgoMc3RvcnlfcG9pbnRzGAUgASgFQgf6QgQaAigBSAKIAQESLAoPZXN0aW1hdGVkX2hvdXJzGAYgASgBQg76QgsSCSkAAAAAAAAAAEgDiAEBEikKDGFjdHVhbF9ob3VycxgHIAEoAUIO+kILEgkpAAAAAAAAAABIBIgBARIsCghkdWVfZGF0ZRgIIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASFwoPYWlfbW9kZV9lbmFibGVkGAkgASgIEhoKDW1ldGFkYXRhX2pzb24YCiABKAlIBYgBARIQCghib2FyZF9pZBgLIAEoDRIXCg9ib2FyZF9jb2x1bW5faWQYDCABKA0SEgoKcHJvamVjdF9pZBgNIAEoDRIUCgx0YXNrX3R5cGVfaWQYDiABKA0SGAoQdGFza19wcmlvcml0eV9pZBgPIAEoDRIYChByZXBvcnRlcl91c2VyX2lkGBAgASgNEh0KEGFzc2lnbmVkX3VzZXJfaWQYESABKA1IBogBARIbCg5wYXJlbnRfdGFza19pZBgSIAEoDUgHiAEBEhYKDnJlcG9zaXRvcnlfaWRzGBMgAygNEhUKCGN5Y2xlX2lkGBQgASgNSAiIAQFCDQoLX2lkZW50aWZpZXJCDgoMX2Rlc2NyaXB0aW9uQg8KDV9zdG9yeV9wb2ludHNCEgoQX2VzdGltYXRlZF9ob3Vyc0IPCg1fYWN0dWFsX2hvdXJzQhAKDl9tZXRhZGF0YV9qc29uQhMKEV9hc3NpZ25lZF91c2VyX2lkQhEKD19wYXJlbnRfdGFza19pZEILCglfY3ljbGVfaWQi4gYKD0VkaXRUYXNrUmVxdWVzdBITCgJpZBgBIAEoDUIH+kIEKgIoARIdCgppZGVudGlmaWVyGAIgASgJQgn6QgZyBBABGDISGQoFdGl0bGUYAyABKAlCCvpCB3IFEAEYyAESGAoLZGVzY3JpcHRpb24YBCABKAlIAIgBARIeCg1kaXNwbGF5X29yZGVyGAUgASgFQgf6QgQaAigAEiIKDHN0b3J5X3BvaW50cxgGIAEoBUIH+kIEGgIoAUgBiAEBEiwKD2VzdGltYXRlZF9ob3VycxgHIAEoAUIO+kILEgkpAAAAAAAAAABIAogBARIpCgxhY3R1YWxfaG91cnMYCCABKAFCDvpCCxIJKQAAAAAAAAAASAOIAQESLAoIZHVlX2RhdGUYCSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEhcKD2FpX21vZGVfZW5hYmxlZBgKIAEoCBIaCg1tZXRhZGF0YV9qc29uGAsgASgJSASIAQESEAoIYm9hcmRfaWQYDCABKA0SFwoPYm9hcmRfY29sdW1uX2lkGA0gASgNEhIKCnByb2plY3RfaWQYDiABKA0SFAoMdGFza190eXBlX2lkGA8gASgNEhgKEHRhc2tfcHJpb3JpdHlfaWQYECABKA0SGAoQcmVwb3J0ZXJfdXNlcl9pZBgRIAEoDRIdChBhc3NpZ25lZF91c2VyX2lkGBIgASgNSAWIAQESGwoOcGFyZW50X3Rhc2tfaWQYEyABKA1IBogBARIWCg5yZXBvc2l0b3J5X2lkcxgUIAMoDRIVCghjeWNsZV9pZBgVIAEoDUgHiAEBEi8KC3Jlc29sdmVkX2F0GBYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIeChFvcmlnaW5hbF9lc3RpbWF0ZRgXIAEoAUgIiAEBQg4KDF9kZXNjcmlwdGlvbkIPCg1fc3RvcnlfcG9pbnRzQhIKEF9lc3RpbWF0ZWRfaG91cnNCDwoNX2FjdHVhbF9ob3Vyc0IQCg5fbWV0YWRhdGFfanNvbkITChFfYXNzaWduZWRfdXNlcl9pZEIRCg9fcGFyZW50X3Rhc2tfaWRCCwoJX2N5Y2xlX2lkQhQKEl9vcmlnaW5hbF9lc3RpbWF0ZSIcCg5HZXRUYXNrUmVxdWVzdBIKCgJpZBgBIAEoDSIuChRHZXRUYXNrQnlVVUlEUmVxdWVzdBIWCgR1dWlkGAEgASgJQgj6QgVyA7ABASKiAQoPR2V0VGFza3NSZXF1ZXN0EhsKCnByb2plY3RfaWQYASABKA1CB/pCBCoCKAESMAoKcGFnaW5hdGlvbhgCIAEoCzISLmFwaS52MS5QYWdpbmF0aW9uQgj6QgWKAQIQARItCg5maWx0ZXJfb3B0aW9ucxgDIAEoCzIVLmFwaS52MS5GaWx0ZXJPcHRpb25zEhEKCWxhYmVsX2lkcxgEIAMoDSIfChFEZWxldGVUYXNrUmVxdWVzdBIKCgJpZBgBIAEoDSJXChBHZXRUYXNrc1Jlc3BvbnNlEhsKBXRhc2tzGAEgAygLMgwuYXBpLnYxLlRhc2sSJgoKcGFnaW5hdGlvbhgCIAEoCzISLmFwaS52MS5QYWdpbmF0aW9uIi0KD0FkZFRhc2tSZXNwb25zZRIaCgR0YXNrGAEgASgLMgwuYXBpLnYxLlRhc2siLgoQRWRpdFRhc2tSZXNwb25zZRIaCgR0YXNrGAEgASgLMgwuYXBpLnYxLlRhc2siLQoPR2V0VGFza1Jlc3BvbnNlEhoKBHRhc2sYASABKAsyDC5hcGkudjEuVGFzayI0ChhUcmlnZ2VyQUlXb3JrZmxvd1JlcXVlc3QSGAoHdGFza19pZBgBIAEoDUIH+kIEKgIoASJOChlUcmlnZ2VyQUlXb3JrZmxvd1Jlc3BvbnNlEhAKCGpvYl9uYW1lGAEgASgJEg4KBnN0YXR1cxgCIAEoCRIPCgdtZXNzYWdlGAMgASgJInIKEkV4cG9ydFRhc2tzUmVxdWVzdBIbCgpwcm9qZWN0X2lkGAEgASgNQgf6QgQqAigBEi0KDmZpbHRlcl9vcHRpb25zGAIgASgLMhUuYXBpLnYxLkZpbHRlck9wdGlvbnMSEAoIdGFza19pZHMYAyADKA0iPAoTRXhwb3J0VGFza3NSZXNwb25zZRITCgtjc3ZfY29udGVudBgBIAEoDBIQCghmaWxlbmFtZRgCIAEoCSJwChJJbXBvcnRUYXNrc1JlcXVlc3QSGwoKcHJvamVjdF9pZBgBIAEoDUIH+kIEKgIoARIhCgtjc3ZfY29udGVudBgCIAEoDEIM+kIJegcQARiAgIAFEhoKEnNraXBfbm90aWZpY2F0aW9ucxgDIAEoCCJFCgxJbXBvcnRlZFRhc2sSEwoLZXh0ZXJuYWxfaWQYASABKAkSDwoHdGFza19pZBgCIAEoDRIPCgdjcmVhdGVkGAMgASgIIq0BChNJbXBvcnRUYXNrc1Jlc3BvbnNlEhUKDWNyZWF0ZWRfY291bnQYASABKAUSFQoNdXBkYXRlZF9jb3VudBgCIAEoBRIUCgxmYWlsZWRfY291bnQYAyABKAUSDgoGZXJyb3JzGAQgAygJEhUKDXNraXBwZWRfY291bnQYBSABKAUSKwoNY3JlYXRlZF90YXNrcxgGIAMoCzIULmFwaS52MS5JbXBvcnRlZFRhc2sipwEKCFRhc2tMaW5rEh8KC2V4dGVybmFsX2lkGAEgASgJQgr6QgdyBRABGIABEikKEnBhcmVudF9leHRlcm5hbF9pZBgCIAEoCUII+kIFcgMYgAFIAIgBARIlCg5taWxlc3RvbmVfbmFtZRgDIAEoCUII+kIFcgMYgAJIAYgBAUIVChNfcGFyZW50X2V4dGVybmFsX2lkQhEKD19taWxlc3RvbmVfbmFtZSJnChxMaW5rVGFza3NCeUV4dGVybmFsSWRSZXF1ZXN0EhsKCnByb2plY3RfaWQYASABKA1CB/pCBCoCKAESKgoFbGlua3MYAiADKAsyEC5hcGkudjEuVGFza0xpbmtCCfpCBpIBAxCIJyJiCh1MaW5rVGFza3NCeUV4dGVybmFsSWRSZXNwb25zZRIWCg5saW5rZWRfcGFyZW50cxgBIAEoBRIZChFsaW5rZWRfbWlsZXN0b25lcxgCIAEoBRIOCgZlcnJvcnMYAyADKAki0QIKFEJ1bGtFZGl0VGFza3NSZXF1ZXN0EhsKCnByb2plY3RfaWQYASABKA1CB/pCBCoCKAESGgoIdGFza19pZHMYAiADKA1CCPpCBZIBAggBEhwKD2JvYXJkX2NvbHVtbl9pZBgDIAEoDUgAiAEBEh0KEHRhc2tfcHJpb3JpdHlfaWQYBCABKA1IAYgBARIZCgx0YXNrX3R5cGVfaWQYBSABKA1IAogBARIdChBhc3NpZ25lZF91c2VyX2lkGAYgASgNSAOIAQESFQoIY3ljbGVfaWQYByABKA1IBIgBARIWCg5yZXBvc2l0b3J5X2lkcxgIIAMoDUISChBfYm9hcmRfY29sdW1uX2lkQhMKEV90YXNrX3ByaW9yaXR5X2lkQg8KDV90YXNrX3R5cGVfaWRCEwoRX2Fzc2lnbmVkX3VzZXJfaWRCCwoJX2N5Y2xlX2lkIi4KFUJ1bGtFZGl0VGFza3NSZXNwb25zZRIVCg11cGRhdGVkX2NvdW50GAEgASgFIlEKFkJ1bGtEZWxldGVUYXNrc1JlcXVlc3QSGwoKcHJvamVjdF9pZBgBIAEoDUIH+kIEKgIoARIaCgh0YXNrX2lkcxgCIAMoDUII+kIFkgECCAEiMAoXQnVsa0RlbGV0ZVRhc2tzUmVzcG9uc2USFQoNZGVsZXRlZF9jb3VudBgBIAEoBSJ2ChFBZGRXb3JrTG9nUmVxdWVzdBIYCgd0YXNrX2lkGAEgASgNQgf6QgQqAigBEh0KBWhvdXJzGAIgASgBQg76QgsSCSmamZmZmZm5PxIYCgtkZXNjcmlwdGlvbhgDIAEoCUgAiAEBQg4KDF9kZXNjcmlwdGlvbiI3ChJBZGRXb3JrTG9nUmVzcG9uc2USIQoId29ya19sb2cYASABKAsyDy5hcGkudjEuV29ya0xvZyIzChREZWxldGVXb3JrTG9nUmVxdWVzdBIPCgd0YXNrX2lkGAEgASgNEgoKAmlkGAIgASgNMukMCgtUYXNrU2VydmljZRJ9CgtFeHBvcnRUYXNrcxIaLmFwaS52MS5FeHBvcnRUYXNrc1JlcXVlc3QaGy5hcGkudjEuRXhwb3J0VGFza3NSZXNwb25zZSI1gtPkkwIvOgEqIiovYXBpL3YxL3Byb2plY3RzL3twcm9qZWN0X2lkfS90YXNrcy9leHBvcnQSfQoLSW1wb3J0VGFza3MSGi5hcGkudjEuSW1wb3J0VGFza3NSZXF1ZXN0GhsuYXBpLnYxLkltcG9ydFRhc2tzUmVzcG9uc2UiNYLT5JMCLzoBKiIqL2FwaS92MS9wcm9qZWN0cy97cHJvamVjdF9pZH0vdGFza3MvaW1wb3J0EqgBChVMaW5rVGFza3NCeUV4dGVybmFsSWQSJC5hcGkudjEuTGlua1Rhc2tzQnlFeHRlcm5hbElkUmVxdWVzdBolLmFwaS52MS5MaW5rVGFza3NCeUV4dGVybmFsSWRSZXNwb25zZSJCgtPkkwI8OgEqIjcvYXBpL3YxL3Byb2plY3RzL3twcm9qZWN0X2lkfS90YXNrcy9saW5rLWJ5LWV4dGVybmFsLWlkElQKB0FkZFRhc2sSFi5hcGkudjEuQWRkVGFza1JlcXVlc3QaFy5hcGkudjEuQWRkVGFza1Jlc3BvbnNlIhiC0+STAhI6ASoiDS9hcGkvdjEvdGFza3MSXAoIRWRpdFRhc2sSFy5hcGkudjEuRWRpdFRhc2tSZXF1ZXN0GhguYXBpLnYxLkVkaXRUYXNrUmVzcG9uc2UiHYLT5JMCFzoBKhoSL2FwaS92MS90YXNrcy97aWR9ElYKB0dldFRhc2sSFi5hcGkudjEuR2V0VGFza1JlcXVlc3QaFy5hcGkudjEuR2V0VGFza1Jlc3BvbnNlIhqC0+STAhQSEi9hcGkvdjEvdGFza3Mve2lkfRJpCg1HZXRUYXNrQnlVVUlEEhwuYXBpLnYxLkdldFRhc2tCeVVVSURSZXF1ZXN0GhcuYXBpLnYxLkdldFRhc2tSZXNwb25zZSIhgtPkkwIbEhkvYXBpL3YxL3Rhc2tzL3V1aWQve3V1aWR9ElQKCEdldFRhc2tzEhcuYXBpLnYxLkdldFRhc2tzUmVxdWVzdBoYLmFwaS52MS5HZXRUYXNrc1Jlc3BvbnNlIhWC0+STAg8SDS9hcGkvdjEvdGFza3MSWwoKRGVsZXRlVGFzaxIZLmFwaS52MS5EZWxldGVUYXNrUmVxdWVzdBoWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eSIagtPkkwIUKhIvYXBpL3YxL3Rhc2tzL3tpZH0ShwEKEVRyaWdnZXJBSVdvcmtmbG93EiAuYXBpLnYxLlRyaWdnZXJBSVdvcmtmbG93UmVxdWVzdBohLmFwaS52MS5UcmlnZ2VyQUlXb3JrZmxvd1Jlc3BvbnNlIi2C0+STAic6ASoiIi9hcGkvdjEvdGFza3Mve3Rhc2tfaWR9L3RyaWdnZXItYWkScQoKQWRkV29ya0xvZxIZLmFwaS52MS5BZGRXb3JrTG9nUmVxdWVzdBoaLmFwaS52MS5BZGRXb3JrTG9nUmVzcG9uc2UiLILT5JMCJjoBKiIhL2FwaS92MS90YXNrcy97dGFza19pZH0vd29yay1sb2dzEnUKDURlbGV0ZVdvcmtMb2cSHC5hcGkudjEuRGVsZXRlV29ya0xvZ1JlcXVlc3QaFi5nb29nbGUucHJvdG9idWYuRW1wdHkiLoLT5JMCKComL2FwaS92MS90YXNrcy97dGFza19pZH0vd29yay1sb2dzL3tpZH0SgQEKDUJ1bGtFZGl0VGFza3MSHC5hcGkudjEuQnVsa0VkaXRUYXNrc1JlcXVlc3QaHS5hcGkudjEuQnVsa0VkaXRUYXNrc1Jlc3BvbnNlIjOC0+STAi06ASoaKC9hcGkvdjEvcHJvamVjdHMve3Byb2plY3RfaWR9L3Rhc2tzL2J1bGsSjgEKD0J1bGtEZWxldGVUYXNrcxIeLmFwaS52MS5CdWxrRGVsZXRlVGFza3NSZXF1ZXN0Gh8uYXBpLnYxLkJ1bGtEZWxldGVUYXNrc1Jlc3BvbnNlIjqC0+STAjQ6ASoiLy9hcGkvdjEvcHJvamVjdHMve3Byb2plY3RfaWR9L3Rhc2tzL2J1bGstZGVsZXRlQm4KCmNvbS5hcGkudjFCCVRhc2tQcm90b1ABWhxvcHNlZS9iYWNrZW5kL2dlbi9hcGkvdjE7Z2VuogIDQVhYqgIGQXBpLlYxygIGQXBpXFYx4gISQXBpXFYxXEdQQk1ldGFkYXRh6gIHQXBpOjpWMWIGcHJvdG8z", [file_google_protobuf_empty, file_google_protobuf_timestamp, file_google_api_annotations, file_validate_validate, file_api_v1_pagination, file_api_v1_filter, file_api_v1_models]);
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Describes the message api.v1.AddTaskRequest.
|
|
@@ -121,61 +121,89 @@ export const ExportTasksResponseSchema = /*@__PURE__*/
|
|
|
121
121
|
export const ImportTasksRequestSchema = /*@__PURE__*/
|
|
122
122
|
messageDesc(file_api_v1_task, 14);
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Describes the message api.v1.ImportedTask.
|
|
126
|
+
* Use `create(ImportedTaskSchema)` to create a new message.
|
|
127
|
+
*/
|
|
128
|
+
export const ImportedTaskSchema = /*@__PURE__*/
|
|
129
|
+
messageDesc(file_api_v1_task, 15);
|
|
130
|
+
|
|
124
131
|
/**
|
|
125
132
|
* Describes the message api.v1.ImportTasksResponse.
|
|
126
133
|
* Use `create(ImportTasksResponseSchema)` to create a new message.
|
|
127
134
|
*/
|
|
128
135
|
export const ImportTasksResponseSchema = /*@__PURE__*/
|
|
129
|
-
messageDesc(file_api_v1_task,
|
|
136
|
+
messageDesc(file_api_v1_task, 16);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Describes the message api.v1.TaskLink.
|
|
140
|
+
* Use `create(TaskLinkSchema)` to create a new message.
|
|
141
|
+
*/
|
|
142
|
+
export const TaskLinkSchema = /*@__PURE__*/
|
|
143
|
+
messageDesc(file_api_v1_task, 17);
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Describes the message api.v1.LinkTasksByExternalIdRequest.
|
|
147
|
+
* Use `create(LinkTasksByExternalIdRequestSchema)` to create a new message.
|
|
148
|
+
*/
|
|
149
|
+
export const LinkTasksByExternalIdRequestSchema = /*@__PURE__*/
|
|
150
|
+
messageDesc(file_api_v1_task, 18);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Describes the message api.v1.LinkTasksByExternalIdResponse.
|
|
154
|
+
* Use `create(LinkTasksByExternalIdResponseSchema)` to create a new message.
|
|
155
|
+
*/
|
|
156
|
+
export const LinkTasksByExternalIdResponseSchema = /*@__PURE__*/
|
|
157
|
+
messageDesc(file_api_v1_task, 19);
|
|
130
158
|
|
|
131
159
|
/**
|
|
132
160
|
* Describes the message api.v1.BulkEditTasksRequest.
|
|
133
161
|
* Use `create(BulkEditTasksRequestSchema)` to create a new message.
|
|
134
162
|
*/
|
|
135
163
|
export const BulkEditTasksRequestSchema = /*@__PURE__*/
|
|
136
|
-
messageDesc(file_api_v1_task,
|
|
164
|
+
messageDesc(file_api_v1_task, 20);
|
|
137
165
|
|
|
138
166
|
/**
|
|
139
167
|
* Describes the message api.v1.BulkEditTasksResponse.
|
|
140
168
|
* Use `create(BulkEditTasksResponseSchema)` to create a new message.
|
|
141
169
|
*/
|
|
142
170
|
export const BulkEditTasksResponseSchema = /*@__PURE__*/
|
|
143
|
-
messageDesc(file_api_v1_task,
|
|
171
|
+
messageDesc(file_api_v1_task, 21);
|
|
144
172
|
|
|
145
173
|
/**
|
|
146
174
|
* Describes the message api.v1.BulkDeleteTasksRequest.
|
|
147
175
|
* Use `create(BulkDeleteTasksRequestSchema)` to create a new message.
|
|
148
176
|
*/
|
|
149
177
|
export const BulkDeleteTasksRequestSchema = /*@__PURE__*/
|
|
150
|
-
messageDesc(file_api_v1_task,
|
|
178
|
+
messageDesc(file_api_v1_task, 22);
|
|
151
179
|
|
|
152
180
|
/**
|
|
153
181
|
* Describes the message api.v1.BulkDeleteTasksResponse.
|
|
154
182
|
* Use `create(BulkDeleteTasksResponseSchema)` to create a new message.
|
|
155
183
|
*/
|
|
156
184
|
export const BulkDeleteTasksResponseSchema = /*@__PURE__*/
|
|
157
|
-
messageDesc(file_api_v1_task,
|
|
185
|
+
messageDesc(file_api_v1_task, 23);
|
|
158
186
|
|
|
159
187
|
/**
|
|
160
188
|
* Describes the message api.v1.AddWorkLogRequest.
|
|
161
189
|
* Use `create(AddWorkLogRequestSchema)` to create a new message.
|
|
162
190
|
*/
|
|
163
191
|
export const AddWorkLogRequestSchema = /*@__PURE__*/
|
|
164
|
-
messageDesc(file_api_v1_task,
|
|
192
|
+
messageDesc(file_api_v1_task, 24);
|
|
165
193
|
|
|
166
194
|
/**
|
|
167
195
|
* Describes the message api.v1.AddWorkLogResponse.
|
|
168
196
|
* Use `create(AddWorkLogResponseSchema)` to create a new message.
|
|
169
197
|
*/
|
|
170
198
|
export const AddWorkLogResponseSchema = /*@__PURE__*/
|
|
171
|
-
messageDesc(file_api_v1_task,
|
|
199
|
+
messageDesc(file_api_v1_task, 25);
|
|
172
200
|
|
|
173
201
|
/**
|
|
174
202
|
* Describes the message api.v1.DeleteWorkLogRequest.
|
|
175
203
|
* Use `create(DeleteWorkLogRequestSchema)` to create a new message.
|
|
176
204
|
*/
|
|
177
205
|
export const DeleteWorkLogRequestSchema = /*@__PURE__*/
|
|
178
|
-
messageDesc(file_api_v1_task,
|
|
206
|
+
messageDesc(file_api_v1_task, 26);
|
|
179
207
|
|
|
180
208
|
/**
|
|
181
209
|
* Service definition
|
package/package.json
CHANGED
package/src/client/api.ts
CHANGED
|
@@ -22,6 +22,10 @@ import { UserService } from "../../gen/api/v1/user_pb.js";
|
|
|
22
22
|
import { VCSIntegrationService } from "../../gen/api/v1/vcs_integration_pb.js";
|
|
23
23
|
import { MilestoneService } from "../../gen/api/v1/milestone_pb.js";
|
|
24
24
|
import { MilestoneTaskService } from "../../gen/api/v1/milestone_task_pb.js";
|
|
25
|
+
import { LabelService } from "../../gen/api/v1/label_pb.js";
|
|
26
|
+
import { TaskLabelService } from "../../gen/api/v1/task_label_pb.js";
|
|
27
|
+
import { CommentService } from "../../gen/api/v1/comment_pb.js";
|
|
28
|
+
import { TaskDependencyService } from "../../gen/api/v1/task_dependency_pb.js";
|
|
25
29
|
|
|
26
30
|
const authInterceptor: Interceptor = (next) => async (req) => {
|
|
27
31
|
// Remote mode: token from AsyncLocalStorage (per-request)
|
|
@@ -97,6 +101,10 @@ export type ApiClients = {
|
|
|
97
101
|
vcsIntegrations: Client<typeof VCSIntegrationService>;
|
|
98
102
|
milestones: Client<typeof MilestoneService>;
|
|
99
103
|
milestoneTasks: Client<typeof MilestoneTaskService>;
|
|
104
|
+
labels: Client<typeof LabelService>;
|
|
105
|
+
taskLabels: Client<typeof TaskLabelService>;
|
|
106
|
+
comments: Client<typeof CommentService>;
|
|
107
|
+
taskDependencies: Client<typeof TaskDependencyService>;
|
|
100
108
|
};
|
|
101
109
|
|
|
102
110
|
export function getClients(): ApiClients {
|
|
@@ -115,6 +123,10 @@ export function getClients(): ApiClients {
|
|
|
115
123
|
vcsIntegrations: makeClient(VCSIntegrationService),
|
|
116
124
|
milestones: makeClient(MilestoneService),
|
|
117
125
|
milestoneTasks: makeClient(MilestoneTaskService),
|
|
126
|
+
labels: makeClient(LabelService),
|
|
127
|
+
taskLabels: makeClient(TaskLabelService),
|
|
128
|
+
comments: makeClient(CommentService),
|
|
129
|
+
taskDependencies: makeClient(TaskDependencyService),
|
|
118
130
|
};
|
|
119
131
|
}
|
|
120
132
|
return cachedClients;
|
package/src/server.ts
CHANGED
|
@@ -8,6 +8,9 @@ import { registerCycleTools } from "./tools/cycles.js";
|
|
|
8
8
|
import { registerDocTools } from "./tools/docs.js";
|
|
9
9
|
import { registerRepositoryTools } from "./tools/repositories.js";
|
|
10
10
|
import { registerMilestoneTools } from "./tools/milestones.js";
|
|
11
|
+
import { registerLabelTools } from "./tools/labels.js";
|
|
12
|
+
import { registerCommentTools } from "./tools/comments.js";
|
|
13
|
+
import { registerTaskDependencyTools } from "./tools/task-dependencies.js";
|
|
11
14
|
|
|
12
15
|
export function createServer(clientFactory?: () => ApiClients): McpServer {
|
|
13
16
|
const factory = clientFactory ?? getClients;
|
|
@@ -25,6 +28,9 @@ export function createServer(clientFactory?: () => ApiClients): McpServer {
|
|
|
25
28
|
registerDocTools(server, factory);
|
|
26
29
|
registerRepositoryTools(server, factory);
|
|
27
30
|
registerMilestoneTools(server, factory);
|
|
31
|
+
registerLabelTools(server, factory);
|
|
32
|
+
registerCommentTools(server, factory);
|
|
33
|
+
registerTaskDependencyTools(server, factory);
|
|
28
34
|
|
|
29
35
|
return server;
|
|
30
36
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { ApiClients } from "../client/api.js";
|
|
4
|
+
import { defaultPagination } from "../client/api.js";
|
|
5
|
+
import { authManager } from "../auth/manager.js";
|
|
6
|
+
import {
|
|
7
|
+
formatComment,
|
|
8
|
+
formatCommentList,
|
|
9
|
+
formatError,
|
|
10
|
+
} from "../utils/format.js";
|
|
11
|
+
|
|
12
|
+
export function registerCommentTools(
|
|
13
|
+
server: McpServer,
|
|
14
|
+
getClients: () => ApiClients,
|
|
15
|
+
): void {
|
|
16
|
+
server.tool(
|
|
17
|
+
"opsee_list_comments",
|
|
18
|
+
"List comments on a task, oldest first. Includes both regular and internal comments visible to the caller.",
|
|
19
|
+
{
|
|
20
|
+
taskId: z.number().describe("The task ID"),
|
|
21
|
+
page: z.number().optional().describe("Page number (default: 1)"),
|
|
22
|
+
pageSize: z.number().optional().describe("Items per page (default: 50)"),
|
|
23
|
+
},
|
|
24
|
+
{ readOnlyHint: true, destructiveHint: false },
|
|
25
|
+
async ({ taskId, page, pageSize }) => {
|
|
26
|
+
try {
|
|
27
|
+
const clients = getClients();
|
|
28
|
+
const res = await clients.comments.getComments({
|
|
29
|
+
taskId,
|
|
30
|
+
pagination: defaultPagination(page || 1, pageSize || 50),
|
|
31
|
+
});
|
|
32
|
+
return { content: [{ type: "text", text: formatCommentList(res.comments) }] };
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return { content: [{ type: "text", text: formatError(error) }], isError: true };
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
server.tool(
|
|
40
|
+
"opsee_add_comment",
|
|
41
|
+
"Add a comment to a task. Posts as the authenticated user. Set isInternal=true to mark the comment as internal (visibility depends on backend RBAC).",
|
|
42
|
+
{
|
|
43
|
+
taskId: z.number().describe("The task ID to comment on"),
|
|
44
|
+
content: z.string().min(1).describe("Comment body"),
|
|
45
|
+
isInternal: z.boolean().optional().describe("Mark as internal comment (default: false)"),
|
|
46
|
+
},
|
|
47
|
+
{ readOnlyHint: false, destructiveHint: false },
|
|
48
|
+
async ({ taskId, content, isInternal }) => {
|
|
49
|
+
try {
|
|
50
|
+
const clients = getClients();
|
|
51
|
+
|
|
52
|
+
let userId = 0;
|
|
53
|
+
const cachedId = authManager.getUserId();
|
|
54
|
+
if (cachedId) userId = Number(cachedId);
|
|
55
|
+
if (!userId) {
|
|
56
|
+
const meRes = await clients.users.getMe({});
|
|
57
|
+
if (meRes.user) userId = meRes.user.id;
|
|
58
|
+
}
|
|
59
|
+
if (!userId) {
|
|
60
|
+
return { content: [{ type: "text", text: "Could not resolve current user. Authentication may be incomplete." }], isError: true };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const res = await clients.comments.addComment({
|
|
64
|
+
content,
|
|
65
|
+
isInternal: isInternal ?? false,
|
|
66
|
+
taskId,
|
|
67
|
+
userId,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (!res.comment) {
|
|
71
|
+
return { content: [{ type: "text", text: "Failed to add comment." }] };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return { content: [{ type: "text", text: `Comment added:\n${formatComment(res.comment)}` }] };
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return { content: [{ type: "text", text: formatError(error) }], isError: true };
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
server.tool(
|
|
82
|
+
"opsee_delete_comment",
|
|
83
|
+
"Delete a comment by ID. This is permanent.",
|
|
84
|
+
{ commentId: z.number().describe("The comment ID") },
|
|
85
|
+
{ readOnlyHint: false, destructiveHint: true },
|
|
86
|
+
async ({ commentId }) => {
|
|
87
|
+
try {
|
|
88
|
+
const clients = getClients();
|
|
89
|
+
await clients.comments.deleteComment({ id: commentId });
|
|
90
|
+
return { content: [{ type: "text", text: "Comment deleted." }] };
|
|
91
|
+
} catch (error) {
|
|
92
|
+
return { content: [{ type: "text", text: formatError(error) }], isError: true };
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
}
|