Skip to content

Commit 805358b

Browse files
JoannaaKLSamMorrowDrums
authored andcommitted
Split pr and issue search
Add description Extract common code Test fixes Updated search description Move search prs to prs toolset Update tools snaps
1 parent 5f92434 commit 805358b

File tree

8 files changed

+153
-122
lines changed

8 files changed

+153
-122
lines changed

pkg/github/__toolsnaps__/search_issues.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"title": "Search issues",
44
"readOnlyHint": true
55
},
6-
"description": "Search for issues in GitHub repositories.",
6+
"description": "Search for issues in GitHub repositories using issues search syntax already scoped to is:issue",
77
"inputSchema": {
88
"properties": {
99
"order": {
@@ -25,7 +25,7 @@
2525
"minimum": 1,
2626
"type": "number"
2727
},
28-
"q": {
28+
"query": {
2929
"description": "Search query using GitHub issues search syntax",
3030
"type": "string"
3131
},
@@ -48,7 +48,7 @@
4848
}
4949
},
5050
"required": [
51-
"q"
51+
"query"
5252
],
5353
"type": "object"
5454
},
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"annotations": {
3+
"title": "Search pull requests",
4+
"readOnlyHint": true
5+
},
6+
"description": "Search for pull requests in GitHub repositories using issues search syntax already scoped to is:pr",
7+
"inputSchema": {
8+
"properties": {
9+
"order": {
10+
"description": "Sort order",
11+
"enum": [
12+
"asc",
13+
"desc"
14+
],
15+
"type": "string"
16+
},
17+
"page": {
18+
"description": "Page number for pagination (min 1)",
19+
"minimum": 1,
20+
"type": "number"
21+
},
22+
"perPage": {
23+
"description": "Results per page for pagination (min 1, max 100)",
24+
"maximum": 100,
25+
"minimum": 1,
26+
"type": "number"
27+
},
28+
"query": {
29+
"description": "Search query using GitHub pull request search syntax",
30+
"type": "string"
31+
},
32+
"sort": {
33+
"description": "Sort field by number of matches of categories, defaults to best match",
34+
"enum": [
35+
"comments",
36+
"reactions",
37+
"reactions-+1",
38+
"reactions--1",
39+
"reactions-smile",
40+
"reactions-thinking_face",
41+
"reactions-heart",
42+
"reactions-tada",
43+
"interactions",
44+
"created",
45+
"updated"
46+
],
47+
"type": "string"
48+
}
49+
},
50+
"required": [
51+
"query"
52+
],
53+
"type": "object"
54+
},
55+
"name": "search_pull_requests"
56+
}

pkg/github/issues.go

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc
156156
// SearchIssues creates a tool to search for issues.
157157
func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
158158
return mcp.NewTool("search_issues",
159-
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories.")),
159+
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories using issues search syntax already scoped to is:issue")),
160160
mcp.WithToolAnnotation(mcp.ToolAnnotation{
161161
Title: t("TOOL_SEARCH_ISSUES_USER_TITLE", "Search issues"),
162162
ReadOnlyHint: ToBoolPtr(true),
163163
}),
164-
mcp.WithString("q",
164+
mcp.WithString("query",
165165
mcp.Required(),
166166
mcp.Description("Search query using GitHub issues search syntax"),
167167
),
@@ -188,56 +188,7 @@ func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (
188188
WithPagination(),
189189
),
190190
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
191-
query, err := RequiredParam[string](request, "q")
192-
if err != nil {
193-
return mcp.NewToolResultError(err.Error()), nil
194-
}
195-
sort, err := OptionalParam[string](request, "sort")
196-
if err != nil {
197-
return mcp.NewToolResultError(err.Error()), nil
198-
}
199-
order, err := OptionalParam[string](request, "order")
200-
if err != nil {
201-
return mcp.NewToolResultError(err.Error()), nil
202-
}
203-
pagination, err := OptionalPaginationParams(request)
204-
if err != nil {
205-
return mcp.NewToolResultError(err.Error()), nil
206-
}
207-
208-
opts := &github.SearchOptions{
209-
Sort: sort,
210-
Order: order,
211-
ListOptions: github.ListOptions{
212-
PerPage: pagination.perPage,
213-
Page: pagination.page,
214-
},
215-
}
216-
217-
client, err := getClient(ctx)
218-
if err != nil {
219-
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
220-
}
221-
result, resp, err := client.Search.Issues(ctx, query, opts)
222-
if err != nil {
223-
return nil, fmt.Errorf("failed to search issues: %w", err)
224-
}
225-
defer func() { _ = resp.Body.Close() }()
226-
227-
if resp.StatusCode != http.StatusOK {
228-
body, err := io.ReadAll(resp.Body)
229-
if err != nil {
230-
return nil, fmt.Errorf("failed to read response body: %w", err)
231-
}
232-
return mcp.NewToolResultError(fmt.Sprintf("failed to search issues: %s", string(body))), nil
233-
}
234-
235-
r, err := json.Marshal(result)
236-
if err != nil {
237-
return nil, fmt.Errorf("failed to marshal response: %w", err)
238-
}
239-
240-
return mcp.NewToolResultText(string(r)), nil
191+
return searchHandler(ctx, getClient, request, "issue", "failed to search issues")
241192
}
242193
}
243194

pkg/github/issues_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,12 @@ func Test_SearchIssues(t *testing.T) {
237237

238238
assert.Equal(t, "search_issues", tool.Name)
239239
assert.NotEmpty(t, tool.Description)
240-
assert.Contains(t, tool.InputSchema.Properties, "q")
240+
assert.Contains(t, tool.InputSchema.Properties, "query")
241241
assert.Contains(t, tool.InputSchema.Properties, "sort")
242242
assert.Contains(t, tool.InputSchema.Properties, "order")
243243
assert.Contains(t, tool.InputSchema.Properties, "perPage")
244244
assert.Contains(t, tool.InputSchema.Properties, "page")
245-
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"q"})
245+
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"query"})
246246

247247
// Setup mock search results
248248
mockSearchResult := &github.IssuesSearchResult{
@@ -290,7 +290,7 @@ func Test_SearchIssues(t *testing.T) {
290290
expectQueryParams(
291291
t,
292292
map[string]string{
293-
"q": "repo:owner/repo is:issue is:open",
293+
"q": "is:issue repo:owner/repo is:open",
294294
"sort": "created",
295295
"order": "desc",
296296
"page": "1",
@@ -302,7 +302,7 @@ func Test_SearchIssues(t *testing.T) {
302302
),
303303
),
304304
requestArgs: map[string]interface{}{
305-
"q": "repo:owner/repo is:issue is:open",
305+
"query": "repo:owner/repo is:open",
306306
"sort": "created",
307307
"order": "desc",
308308
"page": float64(1),
@@ -320,7 +320,7 @@ func Test_SearchIssues(t *testing.T) {
320320
),
321321
),
322322
requestArgs: map[string]interface{}{
323-
"q": "repo:owner/repo is:issue is:open",
323+
"query": "is:issue repo:owner/repo is:open",
324324
},
325325
expectError: false,
326326
expectedResult: mockSearchResult,
@@ -337,7 +337,7 @@ func Test_SearchIssues(t *testing.T) {
337337
),
338338
),
339339
requestArgs: map[string]interface{}{
340-
"q": "invalid:query",
340+
"query": "invalid:query",
341341
},
342342
expectError: true,
343343
expectedErrMsg: "failed to search issues",

pkg/github/pullrequests.go

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -536,12 +536,12 @@ func MergePullRequest(getClient GetClientFn, t translations.TranslationHelperFun
536536
// SearchPullRequests creates a tool to search for pull requests.
537537
func SearchPullRequests(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
538538
return mcp.NewTool("search_pull_requests",
539-
mcp.WithDescription(t("TOOL_SEARCH_PULL_REQUESTS_DESCRIPTION", "Search for pull requests in GitHub repositories.")),
539+
mcp.WithDescription(t("TOOL_SEARCH_PULL_REQUESTS_DESCRIPTION", "Search for pull requests in GitHub repositories using issues search syntax already scoped to is:pr")),
540540
mcp.WithToolAnnotation(mcp.ToolAnnotation{
541541
Title: t("TOOL_SEARCH_PULL_REQUESTS_USER_TITLE", "Search pull requests"),
542542
ReadOnlyHint: ToBoolPtr(true),
543543
}),
544-
mcp.WithString("q",
544+
mcp.WithString("query",
545545
mcp.Required(),
546546
mcp.Description("Search query using GitHub pull request search syntax"),
547547
),
@@ -568,56 +568,7 @@ func SearchPullRequests(getClient GetClientFn, t translations.TranslationHelperF
568568
WithPagination(),
569569
),
570570
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
571-
query, err := RequiredParam[string](request, "q")
572-
if err != nil {
573-
return mcp.NewToolResultError(err.Error()), nil
574-
}
575-
sort, err := OptionalParam[string](request, "sort")
576-
if err != nil {
577-
return mcp.NewToolResultError(err.Error()), nil
578-
}
579-
order, err := OptionalParam[string](request, "order")
580-
if err != nil {
581-
return mcp.NewToolResultError(err.Error()), nil
582-
}
583-
pagination, err := OptionalPaginationParams(request)
584-
if err != nil {
585-
return mcp.NewToolResultError(err.Error()), nil
586-
}
587-
588-
opts := &github.SearchOptions{
589-
Sort: sort,
590-
Order: order,
591-
ListOptions: github.ListOptions{
592-
PerPage: pagination.perPage,
593-
Page: pagination.page,
594-
},
595-
}
596-
597-
client, err := getClient(ctx)
598-
if err != nil {
599-
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
600-
}
601-
result, resp, err := client.Search.Issues(ctx, query, opts)
602-
if err != nil {
603-
return nil, fmt.Errorf("failed to search pull requests: %w", err)
604-
}
605-
defer func() { _ = resp.Body.Close() }()
606-
607-
if resp.StatusCode != http.StatusOK {
608-
body, err := io.ReadAll(resp.Body)
609-
if err != nil {
610-
return nil, fmt.Errorf("failed to read response body: %w", err)
611-
}
612-
return mcp.NewToolResultError(fmt.Sprintf("failed to search pull requests: %s", string(body))), nil
613-
}
614-
615-
r, err := json.Marshal(result)
616-
if err != nil {
617-
return nil, fmt.Errorf("failed to marshal response: %w", err)
618-
}
619-
620-
return mcp.NewToolResultText(string(r)), nil
571+
return searchHandler(ctx, getClient, request, "pr", "failed to search pull requests")
621572
}
622573
}
623574

pkg/github/pullrequests_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,12 +572,12 @@ func Test_SearchPullRequests(t *testing.T) {
572572

573573
assert.Equal(t, "search_pull_requests", tool.Name)
574574
assert.NotEmpty(t, tool.Description)
575-
assert.Contains(t, tool.InputSchema.Properties, "q")
575+
assert.Contains(t, tool.InputSchema.Properties, "query")
576576
assert.Contains(t, tool.InputSchema.Properties, "sort")
577577
assert.Contains(t, tool.InputSchema.Properties, "order")
578578
assert.Contains(t, tool.InputSchema.Properties, "perPage")
579579
assert.Contains(t, tool.InputSchema.Properties, "page")
580-
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"q"})
580+
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"query"})
581581

582582
mockSearchResult := &github.IssuesSearchResult{
583583
Total: github.Ptr(2),
@@ -624,7 +624,7 @@ func Test_SearchPullRequests(t *testing.T) {
624624
expectQueryParams(
625625
t,
626626
map[string]string{
627-
"q": "repo:owner/repo is:pr is:open",
627+
"q": "is:pr repo:owner/repo is:open",
628628
"sort": "created",
629629
"order": "desc",
630630
"page": "1",
@@ -636,7 +636,7 @@ func Test_SearchPullRequests(t *testing.T) {
636636
),
637637
),
638638
requestArgs: map[string]interface{}{
639-
"q": "repo:owner/repo is:pr is:open",
639+
"query": "repo:owner/repo is:open",
640640
"sort": "created",
641641
"order": "desc",
642642
"page": float64(1),
@@ -654,7 +654,7 @@ func Test_SearchPullRequests(t *testing.T) {
654654
),
655655
),
656656
requestArgs: map[string]interface{}{
657-
"q": "repo:owner/repo is:pr is:open",
657+
"query": "is:pr repo:owner/repo is:open",
658658
},
659659
expectError: false,
660660
expectedResult: mockSearchResult,
@@ -671,18 +671,18 @@ func Test_SearchPullRequests(t *testing.T) {
671671
),
672672
),
673673
requestArgs: map[string]interface{}{
674-
"q": "invalid:query",
674+
"query": "invalid:query",
675675
},
676676
expectError: true,
677-
expectedErrMsg: "failed to search issues",
677+
expectedErrMsg: "failed to search pull requests",
678678
},
679679
}
680680

681681
for _, tc := range tests {
682682
t.Run(tc.name, func(t *testing.T) {
683683
// Setup client with mock
684684
client := github.NewClient(tc.mockedClient)
685-
_, handler := SearchIssues(stubGetClientFn(client), translations.NullTranslationHelper)
685+
_, handler := SearchPullRequests(stubGetClientFn(client), translations.NullTranslationHelper)
686686

687687
// Create call request
688688
request := createMCPRequest(tc.requestArgs)

0 commit comments

Comments
 (0)