Skip to content

Commit d8d4c56

Browse files
Copilotomgitsads
andcommitted
Migrate SearchIssues and search_utils helper
Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>
1 parent a4e8f7b commit d8d4c56

File tree

2 files changed

+64
-52
lines changed

2 files changed

+64
-52
lines changed

pkg/github/issues.go

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -846,26 +846,26 @@ func ReprioritizeSubIssue(ctx context.Context, client *github.Client, owner stri
846846
}
847847

848848
// SearchIssues creates a tool to search for issues.
849-
func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
850-
return mcp.NewTool("search_issues",
851-
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories using issues search syntax already scoped to is:issue")),
852-
mcp.WithToolAnnotation(mcp.ToolAnnotation{
853-
Title: t("TOOL_SEARCH_ISSUES_USER_TITLE", "Search issues"),
854-
ReadOnlyHint: ToBoolPtr(true),
855-
}),
856-
mcp.WithString("query",
857-
mcp.Required(),
858-
mcp.Description("Search query using GitHub issues search syntax"),
859-
),
860-
mcp.WithString("owner",
861-
mcp.Description("Optional repository owner. If provided with repo, only issues for this repository are listed."),
862-
),
863-
mcp.WithString("repo",
864-
mcp.Description("Optional repository name. If provided with owner, only issues for this repository are listed."),
865-
),
866-
mcp.WithString("sort",
867-
mcp.Description("Sort field by number of matches of categories, defaults to best match"),
868-
mcp.Enum(
849+
func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
850+
schema := &jsonschema.Schema{
851+
Type: "object",
852+
Properties: map[string]*jsonschema.Schema{
853+
"query": {
854+
Type: "string",
855+
Description: "Search query using GitHub issues search syntax",
856+
},
857+
"owner": {
858+
Type: "string",
859+
Description: "Optional repository owner. If provided with repo, only issues for this repository are listed.",
860+
},
861+
"repo": {
862+
Type: "string",
863+
Description: "Optional repository name. If provided with owner, only issues for this repository are listed.",
864+
},
865+
"sort": {
866+
Type: "string",
867+
Description: "Sort field by number of matches of categories, defaults to best match",
868+
Enum: []any{
869869
"comments",
870870
"reactions",
871871
"reactions-+1",
@@ -877,16 +877,30 @@ func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (
877877
"interactions",
878878
"created",
879879
"updated",
880-
),
881-
),
882-
mcp.WithString("order",
883-
mcp.Description("Sort order"),
884-
mcp.Enum("asc", "desc"),
885-
),
886-
WithPagination(),
887-
),
888-
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
889-
return searchHandler(ctx, getClient, request, "issue", "failed to search issues")
880+
},
881+
},
882+
"order": {
883+
Type: "string",
884+
Description: "Sort order",
885+
Enum: []any{"asc", "desc"},
886+
},
887+
},
888+
Required: []string{"query"},
889+
}
890+
WithPagination(schema)
891+
892+
return mcp.Tool{
893+
Name: "search_issues",
894+
Description: t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories using issues search syntax already scoped to is:issue"),
895+
Annotations: &mcp.ToolAnnotations{
896+
Title: t("TOOL_SEARCH_ISSUES_USER_TITLE", "Search issues"),
897+
ReadOnlyHint: true,
898+
},
899+
InputSchema: schema,
900+
},
901+
func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
902+
result, err := searchHandler(ctx, getClient, args, "issue", "failed to search issues")
903+
return result, nil, err
890904
}
891905
}
892906

pkg/github/search_utils.go

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//go:build ignore
2-
31
package github
42

53
import (
@@ -10,8 +8,8 @@ import (
108
"net/http"
119
"regexp"
1210

11+
"github.com/github/github-mcp-server/pkg/utils"
1312
"github.com/google/go-github/v79/github"
14-
"github.com/mark3labs/mcp-go/mcp"
1513
)
1614

1715
func hasFilter(query, filterType string) bool {
@@ -40,44 +38,44 @@ func hasTypeFilter(query string) bool {
4038
func searchHandler(
4139
ctx context.Context,
4240
getClient GetClientFn,
43-
request mcp.CallToolRequest,
41+
args map[string]any,
4442
searchType string,
4543
errorPrefix string,
4644
) (*mcp.CallToolResult, error) {
47-
query, err := RequiredParam[string](request, "query")
45+
query, err := RequiredParam[string](args, "query")
4846
if err != nil {
49-
return mcp.NewToolResultError(err.Error()), nil
47+
return utils.NewToolResultError(err.Error()), nil
5048
}
5149

5250
if !hasSpecificFilter(query, "is", searchType) {
5351
query = fmt.Sprintf("is:%s %s", searchType, query)
5452
}
5553

56-
owner, err := OptionalParam[string](request, "owner")
54+
owner, err := OptionalParam[string](args, "owner")
5755
if err != nil {
58-
return mcp.NewToolResultError(err.Error()), nil
56+
return utils.NewToolResultError(err.Error()), nil
5957
}
6058

61-
repo, err := OptionalParam[string](request, "repo")
59+
repo, err := OptionalParam[string](args, "repo")
6260
if err != nil {
63-
return mcp.NewToolResultError(err.Error()), nil
61+
return utils.NewToolResultError(err.Error()), nil
6462
}
6563

6664
if owner != "" && repo != "" && !hasRepoFilter(query) {
6765
query = fmt.Sprintf("repo:%s/%s %s", owner, repo, query)
6866
}
6967

70-
sort, err := OptionalParam[string](request, "sort")
68+
sort, err := OptionalParam[string](args, "sort")
7169
if err != nil {
72-
return mcp.NewToolResultError(err.Error()), nil
70+
return utils.NewToolResultError(err.Error()), nil
7371
}
74-
order, err := OptionalParam[string](request, "order")
72+
order, err := OptionalParam[string](args, "order")
7573
if err != nil {
76-
return mcp.NewToolResultError(err.Error()), nil
74+
return utils.NewToolResultError(err.Error()), nil
7775
}
78-
pagination, err := OptionalPaginationParams(request)
76+
pagination, err := OptionalPaginationParams(args)
7977
if err != nil {
80-
return mcp.NewToolResultError(err.Error()), nil
78+
return utils.NewToolResultError(err.Error()), nil
8179
}
8280

8381
opts := &github.SearchOptions{
@@ -92,26 +90,26 @@ func searchHandler(
9290

9391
client, err := getClient(ctx)
9492
if err != nil {
95-
return nil, fmt.Errorf("%s: failed to get GitHub client: %w", errorPrefix, err)
93+
return utils.NewToolResultErrorFromErr(errorPrefix+": failed to get GitHub client", err), nil
9694
}
9795
result, resp, err := client.Search.Issues(ctx, query, opts)
9896
if err != nil {
99-
return nil, fmt.Errorf("%s: %w", errorPrefix, err)
97+
return utils.NewToolResultErrorFromErr(errorPrefix, err), nil
10098
}
10199
defer func() { _ = resp.Body.Close() }()
102100

103101
if resp.StatusCode != http.StatusOK {
104102
body, err := io.ReadAll(resp.Body)
105103
if err != nil {
106-
return nil, fmt.Errorf("%s: failed to read response body: %w", errorPrefix, err)
104+
return utils.NewToolResultErrorFromErr(errorPrefix+": failed to read response body", err), nil
107105
}
108-
return mcp.NewToolResultError(fmt.Sprintf("%s: %s", errorPrefix, string(body))), nil
106+
return utils.NewToolResultError(fmt.Sprintf("%s: %s", errorPrefix, string(body))), nil
109107
}
110108

111109
r, err := json.Marshal(result)
112110
if err != nil {
113-
return nil, fmt.Errorf("%s: failed to marshal response: %w", errorPrefix, err)
111+
return utils.NewToolResultErrorFromErr(errorPrefix+": failed to marshal response", err), nil
114112
}
115113

116-
return mcp.NewToolResultText(string(r)), nil
114+
return utils.NewToolResultText(string(r)), nil
117115
}

0 commit comments

Comments
 (0)