Skip to content

Commit a4e8f7b

Browse files
Copilotomgitsads
andcommitted
Migrate AddIssueComment, SubIssueWrite and helper functions
Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>
1 parent 16a69cf commit a4e8f7b

1 file changed

Lines changed: 125 additions & 105 deletions

File tree

pkg/github/issues.go

Lines changed: 125 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -540,46 +540,53 @@ func ListIssueTypes(getClient GetClientFn, t translations.TranslationHelperFunc)
540540
}
541541

542542
// AddIssueComment creates a tool to add a comment to an issue.
543-
func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
544-
return mcp.NewTool("add_issue_comment",
545-
mcp.WithDescription(t("TOOL_ADD_ISSUE_COMMENT_DESCRIPTION", "Add a comment to a specific issue in a GitHub repository. Use this tool to add comments to pull requests as well (in this case pass pull request number as issue_number), but only if user is not asking specifically to add review comments.")),
546-
mcp.WithToolAnnotation(mcp.ToolAnnotation{
543+
func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
544+
return mcp.Tool{
545+
Name: "add_issue_comment",
546+
Description: t("TOOL_ADD_ISSUE_COMMENT_DESCRIPTION", "Add a comment to a specific issue in a GitHub repository. Use this tool to add comments to pull requests as well (in this case pass pull request number as issue_number), but only if user is not asking specifically to add review comments."),
547+
Annotations: &mcp.ToolAnnotations{
547548
Title: t("TOOL_ADD_ISSUE_COMMENT_USER_TITLE", "Add comment to issue"),
548-
ReadOnlyHint: ToBoolPtr(false),
549-
}),
550-
mcp.WithString("owner",
551-
mcp.Required(),
552-
mcp.Description("Repository owner"),
553-
),
554-
mcp.WithString("repo",
555-
mcp.Required(),
556-
mcp.Description("Repository name"),
557-
),
558-
mcp.WithNumber("issue_number",
559-
mcp.Required(),
560-
mcp.Description("Issue number to comment on"),
561-
),
562-
mcp.WithString("body",
563-
mcp.Required(),
564-
mcp.Description("Comment content"),
565-
),
566-
),
567-
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
568-
owner, err := RequiredParam[string](request, "owner")
549+
ReadOnlyHint: false,
550+
},
551+
InputSchema: &jsonschema.Schema{
552+
Type: "object",
553+
Properties: map[string]*jsonschema.Schema{
554+
"owner": {
555+
Type: "string",
556+
Description: "Repository owner",
557+
},
558+
"repo": {
559+
Type: "string",
560+
Description: "Repository name",
561+
},
562+
"issue_number": {
563+
Type: "number",
564+
Description: "Issue number to comment on",
565+
},
566+
"body": {
567+
Type: "string",
568+
Description: "Comment content",
569+
},
570+
},
571+
Required: []string{"owner", "repo", "issue_number", "body"},
572+
},
573+
},
574+
func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
575+
owner, err := RequiredParam[string](args, "owner")
569576
if err != nil {
570-
return mcp.NewToolResultError(err.Error()), nil
577+
return utils.NewToolResultError(err.Error()), nil, nil
571578
}
572-
repo, err := RequiredParam[string](request, "repo")
579+
repo, err := RequiredParam[string](args, "repo")
573580
if err != nil {
574-
return mcp.NewToolResultError(err.Error()), nil
581+
return utils.NewToolResultError(err.Error()), nil, nil
575582
}
576-
issueNumber, err := RequiredInt(request, "issue_number")
583+
issueNumber, err := RequiredInt(args, "issue_number")
577584
if err != nil {
578-
return mcp.NewToolResultError(err.Error()), nil
585+
return utils.NewToolResultError(err.Error()), nil, nil
579586
}
580-
body, err := RequiredParam[string](request, "body")
587+
body, err := RequiredParam[string](args, "body")
581588
if err != nil {
582-
return mcp.NewToolResultError(err.Error()), nil
589+
return utils.NewToolResultError(err.Error()), nil, nil
583590
}
584591

585592
comment := &github.IssueComment{
@@ -588,125 +595,138 @@ func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc
588595

589596
client, err := getClient(ctx)
590597
if err != nil {
591-
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
598+
return utils.NewToolResultErrorFromErr("failed to get GitHub client", err), nil, nil
592599
}
593600
createdComment, resp, err := client.Issues.CreateComment(ctx, owner, repo, issueNumber, comment)
594601
if err != nil {
595-
return nil, fmt.Errorf("failed to create comment: %w", err)
602+
return utils.NewToolResultErrorFromErr("failed to create comment", err), nil, nil
596603
}
597604
defer func() { _ = resp.Body.Close() }()
598605

599606
if resp.StatusCode != http.StatusCreated {
600607
body, err := io.ReadAll(resp.Body)
601608
if err != nil {
602-
return nil, fmt.Errorf("failed to read response body: %w", err)
609+
return utils.NewToolResultErrorFromErr("failed to read response body", err), nil, nil
603610
}
604-
return mcp.NewToolResultError(fmt.Sprintf("failed to create comment: %s", string(body))), nil
611+
return utils.NewToolResultError(fmt.Sprintf("failed to create comment: %s", string(body))), nil, nil
605612
}
606613

607614
r, err := json.Marshal(createdComment)
608615
if err != nil {
609-
return nil, fmt.Errorf("failed to marshal response: %w", err)
616+
return utils.NewToolResultErrorFromErr("failed to marshal response", err), nil, nil
610617
}
611618

612-
return mcp.NewToolResultText(string(r)), nil
619+
return utils.NewToolResultText(string(r)), nil, nil
613620
}
614621
}
615622

616623
// SubIssueWrite creates a tool to add a sub-issue to a parent issue.
617-
func SubIssueWrite(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
618-
return mcp.NewTool("sub_issue_write",
619-
mcp.WithDescription(t("TOOL_SUB_ISSUE_WRITE_DESCRIPTION", "Add a sub-issue to a parent issue in a GitHub repository.")),
620-
mcp.WithToolAnnotation(mcp.ToolAnnotation{
624+
func SubIssueWrite(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
625+
return mcp.Tool{
626+
Name: "sub_issue_write",
627+
Description: t("TOOL_SUB_ISSUE_WRITE_DESCRIPTION", "Add a sub-issue to a parent issue in a GitHub repository."),
628+
Annotations: &mcp.ToolAnnotations{
621629
Title: t("TOOL_SUB_ISSUE_WRITE_USER_TITLE", "Change sub-issue"),
622-
ReadOnlyHint: ToBoolPtr(false),
623-
}),
624-
mcp.WithString("method",
625-
mcp.Required(),
626-
mcp.Description(`The action to perform on a single sub-issue
630+
ReadOnlyHint: false,
631+
},
632+
InputSchema: &jsonschema.Schema{
633+
Type: "object",
634+
Properties: map[string]*jsonschema.Schema{
635+
"method": {
636+
Type: "string",
637+
Description: `The action to perform on a single sub-issue
627638
Options are:
628639
- 'add' - add a sub-issue to a parent issue in a GitHub repository.
629640
- 'remove' - remove a sub-issue from a parent issue in a GitHub repository.
630641
- 'reprioritize' - change the order of sub-issues within a parent issue in a GitHub repository. Use either 'after_id' or 'before_id' to specify the new position.
631-
`),
632-
),
633-
mcp.WithString("owner",
634-
mcp.Required(),
635-
mcp.Description("Repository owner"),
636-
),
637-
mcp.WithString("repo",
638-
mcp.Required(),
639-
mcp.Description("Repository name"),
640-
),
641-
mcp.WithNumber("issue_number",
642-
mcp.Required(),
643-
mcp.Description("The number of the parent issue"),
644-
),
645-
mcp.WithNumber("sub_issue_id",
646-
mcp.Required(),
647-
mcp.Description("The ID of the sub-issue to add. ID is not the same as issue number"),
648-
),
649-
mcp.WithBoolean("replace_parent",
650-
mcp.Description("When true, replaces the sub-issue's current parent issue. Use with 'add' method only."),
651-
),
652-
mcp.WithNumber("after_id",
653-
mcp.Description("The ID of the sub-issue to be prioritized after (either after_id OR before_id should be specified)"),
654-
),
655-
mcp.WithNumber("before_id",
656-
mcp.Description("The ID of the sub-issue to be prioritized before (either after_id OR before_id should be specified)"),
657-
),
658-
),
659-
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
660-
method, err := RequiredParam[string](request, "method")
642+
`,
643+
},
644+
"owner": {
645+
Type: "string",
646+
Description: "Repository owner",
647+
},
648+
"repo": {
649+
Type: "string",
650+
Description: "Repository name",
651+
},
652+
"issue_number": {
653+
Type: "number",
654+
Description: "The number of the parent issue",
655+
},
656+
"sub_issue_id": {
657+
Type: "number",
658+
Description: "The ID of the sub-issue to add. ID is not the same as issue number",
659+
},
660+
"replace_parent": {
661+
Type: "boolean",
662+
Description: "When true, replaces the sub-issue's current parent issue. Use with 'add' method only.",
663+
},
664+
"after_id": {
665+
Type: "number",
666+
Description: "The ID of the sub-issue to be prioritized after (either after_id OR before_id should be specified)",
667+
},
668+
"before_id": {
669+
Type: "number",
670+
Description: "The ID of the sub-issue to be prioritized before (either after_id OR before_id should be specified)",
671+
},
672+
},
673+
Required: []string{"method", "owner", "repo", "issue_number", "sub_issue_id"},
674+
},
675+
},
676+
func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
677+
method, err := RequiredParam[string](args, "method")
661678
if err != nil {
662-
return mcp.NewToolResultError(err.Error()), nil
679+
return utils.NewToolResultError(err.Error()), nil, nil
663680
}
664681

665-
owner, err := RequiredParam[string](request, "owner")
682+
owner, err := RequiredParam[string](args, "owner")
666683
if err != nil {
667-
return mcp.NewToolResultError(err.Error()), nil
684+
return utils.NewToolResultError(err.Error()), nil, nil
668685
}
669-
repo, err := RequiredParam[string](request, "repo")
686+
repo, err := RequiredParam[string](args, "repo")
670687
if err != nil {
671-
return mcp.NewToolResultError(err.Error()), nil
688+
return utils.NewToolResultError(err.Error()), nil, nil
672689
}
673-
issueNumber, err := RequiredInt(request, "issue_number")
690+
issueNumber, err := RequiredInt(args, "issue_number")
674691
if err != nil {
675-
return mcp.NewToolResultError(err.Error()), nil
692+
return utils.NewToolResultError(err.Error()), nil, nil
676693
}
677-
subIssueID, err := RequiredInt(request, "sub_issue_id")
694+
subIssueID, err := RequiredInt(args, "sub_issue_id")
678695
if err != nil {
679-
return mcp.NewToolResultError(err.Error()), nil
696+
return utils.NewToolResultError(err.Error()), nil, nil
680697
}
681-
replaceParent, err := OptionalParam[bool](request, "replace_parent")
698+
replaceParent, err := OptionalParam[bool](args, "replace_parent")
682699
if err != nil {
683-
return mcp.NewToolResultError(err.Error()), nil
700+
return utils.NewToolResultError(err.Error()), nil, nil
684701
}
685-
afterID, err := OptionalIntParam(request, "after_id")
702+
afterID, err := OptionalIntParam(args, "after_id")
686703
if err != nil {
687-
return mcp.NewToolResultError(err.Error()), nil
704+
return utils.NewToolResultError(err.Error()), nil, nil
688705
}
689-
beforeID, err := OptionalIntParam(request, "before_id")
706+
beforeID, err := OptionalIntParam(args, "before_id")
690707
if err != nil {
691-
return mcp.NewToolResultError(err.Error()), nil
708+
return utils.NewToolResultError(err.Error()), nil, nil
692709
}
693710

694711
client, err := getClient(ctx)
695712
if err != nil {
696-
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
713+
return utils.NewToolResultErrorFromErr("failed to get GitHub client", err), nil, nil
697714
}
698715

699716
switch strings.ToLower(method) {
700717
case "add":
701-
return AddSubIssue(ctx, client, owner, repo, issueNumber, subIssueID, replaceParent)
718+
result, err := AddSubIssue(ctx, client, owner, repo, issueNumber, subIssueID, replaceParent)
719+
return result, nil, err
702720
case "remove":
703721
// Call the remove sub-issue function
704-
return RemoveSubIssue(ctx, client, owner, repo, issueNumber, subIssueID)
722+
result, err := RemoveSubIssue(ctx, client, owner, repo, issueNumber, subIssueID)
723+
return result, nil, err
705724
case "reprioritize":
706725
// Call the reprioritize sub-issue function
707-
return ReprioritizeSubIssue(ctx, client, owner, repo, issueNumber, subIssueID, afterID, beforeID)
726+
result, err := ReprioritizeSubIssue(ctx, client, owner, repo, issueNumber, subIssueID, afterID, beforeID)
727+
return result, nil, err
708728
default:
709-
return mcp.NewToolResultError(fmt.Sprintf("unknown method: %s", method)), nil
729+
return utils.NewToolResultError(fmt.Sprintf("unknown method: %s", method)), nil, nil
710730
}
711731
}
712732
}
@@ -733,15 +753,15 @@ func AddSubIssue(ctx context.Context, client *github.Client, owner string, repo
733753
if err != nil {
734754
return nil, fmt.Errorf("failed to read response body: %w", err)
735755
}
736-
return mcp.NewToolResultError(fmt.Sprintf("failed to add sub-issue: %s", string(body))), nil
756+
return utils.NewToolResultError(fmt.Sprintf("failed to add sub-issue: %s", string(body))), nil
737757
}
738758

739759
r, err := json.Marshal(subIssue)
740760
if err != nil {
741761
return nil, fmt.Errorf("failed to marshal response: %w", err)
742762
}
743763

744-
return mcp.NewToolResultText(string(r)), nil
764+
return utils.NewToolResultText(string(r)), nil
745765

746766
}
747767

@@ -765,24 +785,24 @@ func RemoveSubIssue(ctx context.Context, client *github.Client, owner string, re
765785
if err != nil {
766786
return nil, fmt.Errorf("failed to read response body: %w", err)
767787
}
768-
return mcp.NewToolResultError(fmt.Sprintf("failed to remove sub-issue: %s", string(body))), nil
788+
return utils.NewToolResultError(fmt.Sprintf("failed to remove sub-issue: %s", string(body))), nil
769789
}
770790

771791
r, err := json.Marshal(subIssue)
772792
if err != nil {
773793
return nil, fmt.Errorf("failed to marshal response: %w", err)
774794
}
775795

776-
return mcp.NewToolResultText(string(r)), nil
796+
return utils.NewToolResultText(string(r)), nil
777797
}
778798

779799
func ReprioritizeSubIssue(ctx context.Context, client *github.Client, owner string, repo string, issueNumber int, subIssueID int, afterID int, beforeID int) (*mcp.CallToolResult, error) {
780800
// Validate that either after_id or before_id is specified, but not both
781801
if afterID == 0 && beforeID == 0 {
782-
return mcp.NewToolResultError("either after_id or before_id must be specified"), nil
802+
return utils.NewToolResultError("either after_id or before_id must be specified"), nil
783803
}
784804
if afterID != 0 && beforeID != 0 {
785-
return mcp.NewToolResultError("only one of after_id or before_id should be specified, not both"), nil
805+
return utils.NewToolResultError("only one of after_id or before_id should be specified, not both"), nil
786806
}
787807

788808
subIssueRequest := github.SubIssueRequest{
@@ -814,15 +834,15 @@ func ReprioritizeSubIssue(ctx context.Context, client *github.Client, owner stri
814834
if err != nil {
815835
return nil, fmt.Errorf("failed to read response body: %w", err)
816836
}
817-
return mcp.NewToolResultError(fmt.Sprintf("failed to reprioritize sub-issue: %s", string(body))), nil
837+
return utils.NewToolResultError(fmt.Sprintf("failed to reprioritize sub-issue: %s", string(body))), nil
818838
}
819839

820840
r, err := json.Marshal(subIssue)
821841
if err != nil {
822842
return nil, fmt.Errorf("failed to marshal response: %w", err)
823843
}
824844

825-
return mcp.NewToolResultText(string(r)), nil
845+
return utils.NewToolResultText(string(r)), nil
826846
}
827847

828848
// SearchIssues creates a tool to search for issues.

0 commit comments

Comments
 (0)