Skip to content

Commit 15f8c9f

Browse files
Merge branch 'main' into feat/sub-issues
2 parents c900cca + 45d0270 commit 15f8c9f

15 files changed

Lines changed: 819 additions & 160 deletions

File tree

.github/workflows/docker-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ on:
99
schedule:
1010
- cron: "27 0 * * *"
1111
push:
12-
branches: ["main"]
12+
branches: ["main", "next"]
1313
# Publish semver tags as releases.
1414
tags: ["v*.*.*"]
1515
pull_request:
16-
branches: ["main"]
16+
branches: ["main", "next"]
1717

1818
env:
1919
# Use docker.io for Docker Hub if empty

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ These are one time installations required to be able to test your changes locall
1919

2020
## Submitting a pull request
2121

22+
> **Important**: Please open your pull request against the `next` branch, not `main`. The `next` branch is where we integrate new features and changes before they are merged to `main`.
23+
2224
1. [Fork][fork] and clone the repository
2325
1. Make sure the tests pass on your machine: `go test -v ./...`
2426
1. Make sure linter passes on your machine: `golangci-lint run`
2527
1. Create a new branch: `git checkout -b my-branch-name`
2628
1. Make your change, add tests, and make sure the tests and linter still pass
27-
1. Push to your fork and [submit a pull request][pr]
29+
1. Push to your fork and [submit a pull request][pr] targeting the `next` branch
2830
1. Pat yourself on the back and wait for your pull request to be reviewed and merged.
2931

3032
Here are a few things you can do that will increase the likelihood of your pull request being accepted:

cmd/github-mcp-server/main.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"errors"
55
"fmt"
66
"os"
7+
"strings"
78

89
"github.com/github/github-mcp-server/internal/ghmcp"
910
"github.com/github/github-mcp-server/pkg/github"
1011
"github.com/spf13/cobra"
12+
"github.com/spf13/pflag"
1113
"github.com/spf13/viper"
1214
)
1315

@@ -54,14 +56,14 @@ var (
5456
EnableCommandLogging: viper.GetBool("enable-command-logging"),
5557
LogFilePath: viper.GetString("log-file"),
5658
}
57-
5859
return ghmcp.RunStdioServer(stdioServerConfig)
5960
},
6061
}
6162
)
6263

6364
func init() {
6465
cobra.OnInitialize(initConfig)
66+
rootCmd.SetGlobalNormalizationFunc(wordSepNormalizeFunc)
6567

6668
rootCmd.SetVersionTemplate("{{.Short}}\n{{.Version}}\n")
6769

@@ -91,6 +93,7 @@ func initConfig() {
9193
// Initialize Viper configuration
9294
viper.SetEnvPrefix("github")
9395
viper.AutomaticEnv()
96+
9497
}
9598

9699
func main() {
@@ -99,3 +102,12 @@ func main() {
99102
os.Exit(1)
100103
}
101104
}
105+
106+
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
107+
from := []string{"_"}
108+
to := "-"
109+
for _, sep := range from {
110+
name = strings.ReplaceAll(name, sep, to)
111+
}
112+
return pflag.NormalizedName(name)
113+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ require (
4141
github.com/sourcegraph/conc v0.3.0 // indirect
4242
github.com/spf13/afero v1.14.0 // indirect
4343
github.com/spf13/cast v1.7.1 // indirect
44-
github.com/spf13/pflag v1.0.6 // indirect
44+
github.com/spf13/pflag v1.0.6
4545
github.com/subosito/gotenv v1.6.0 // indirect
4646
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
4747
go.uber.org/multierr v1.11.0 // indirect

pkg/github/__toolsnaps__/search_issues.snap

Lines changed: 11 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": {
@@ -14,6 +14,10 @@
1414
],
1515
"type": "string"
1616
},
17+
"owner": {
18+
"description": "Optional repository owner. If provided with repo, only notifications for this repository are listed.",
19+
"type": "string"
20+
},
1721
"page": {
1822
"description": "Page number for pagination (min 1)",
1923
"minimum": 1,
@@ -25,10 +29,14 @@
2529
"minimum": 1,
2630
"type": "number"
2731
},
28-
"q": {
32+
"query": {
2933
"description": "Search query using GitHub issues search syntax",
3034
"type": "string"
3135
},
36+
"repo": {
37+
"description": "Optional repository name. If provided with owner, only notifications for this repository are listed.",
38+
"type": "string"
39+
},
3240
"sort": {
3341
"description": "Sort field by number of matches of categories, defaults to best match",
3442
"enum": [
@@ -48,7 +56,7 @@
4856
}
4957
},
5058
"required": [
51-
"q"
59+
"query"
5260
],
5361
"type": "object"
5462
},
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
"owner": {
18+
"description": "Optional repository owner. If provided with repo, only notifications for this repository are listed.",
19+
"type": "string"
20+
},
21+
"page": {
22+
"description": "Page number for pagination (min 1)",
23+
"minimum": 1,
24+
"type": "number"
25+
},
26+
"perPage": {
27+
"description": "Results per page for pagination (min 1, max 100)",
28+
"maximum": 100,
29+
"minimum": 1,
30+
"type": "number"
31+
},
32+
"query": {
33+
"description": "Search query using GitHub pull request search syntax",
34+
"type": "string"
35+
},
36+
"repo": {
37+
"description": "Optional repository name. If provided with owner, only notifications for this repository are listed.",
38+
"type": "string"
39+
},
40+
"sort": {
41+
"description": "Sort field by number of matches of categories, defaults to best match",
42+
"enum": [
43+
"comments",
44+
"reactions",
45+
"reactions-+1",
46+
"reactions--1",
47+
"reactions-smile",
48+
"reactions-thinking_face",
49+
"reactions-heart",
50+
"reactions-tada",
51+
"interactions",
52+
"created",
53+
"updated"
54+
],
55+
"type": "string"
56+
}
57+
},
58+
"required": [
59+
"query"
60+
],
61+
"type": "object"
62+
},
63+
"name": "search_pull_requests"
64+
}

pkg/github/__toolsnaps__/search_users.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"title": "Search users",
44
"readOnlyHint": true
55
},
6-
"description": "Search for GitHub users",
6+
"description": "Search for GitHub users exclusively",
77
"inputSchema": {
88
"properties": {
99
"order": {
@@ -25,8 +25,8 @@
2525
"minimum": 1,
2626
"type": "number"
2727
},
28-
"q": {
29-
"description": "Search query using GitHub users search syntax",
28+
"query": {
29+
"description": "Search query using GitHub users search syntax scoped to type:user",
3030
"type": "string"
3131
},
3232
"sort": {
@@ -40,7 +40,7 @@
4040
}
4141
},
4242
"required": [
43-
"q"
43+
"query"
4444
],
4545
"type": "object"
4646
},

pkg/github/issues.go

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -600,18 +600,24 @@ func ReprioritizeSubIssue(getClient GetClientFn, t translations.TranslationHelpe
600600
}
601601
}
602602

603-
// SearchIssues creates a tool to search for issues and pull requests.
603+
// SearchIssues creates a tool to search for issues.
604604
func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
605605
return mcp.NewTool("search_issues",
606-
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories.")),
606+
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues in GitHub repositories using issues search syntax already scoped to is:issue")),
607607
mcp.WithToolAnnotation(mcp.ToolAnnotation{
608608
Title: t("TOOL_SEARCH_ISSUES_USER_TITLE", "Search issues"),
609609
ReadOnlyHint: ToBoolPtr(true),
610610
}),
611-
mcp.WithString("q",
611+
mcp.WithString("query",
612612
mcp.Required(),
613613
mcp.Description("Search query using GitHub issues search syntax"),
614614
),
615+
mcp.WithString("owner",
616+
mcp.Description("Optional repository owner. If provided with repo, only notifications for this repository are listed."),
617+
),
618+
mcp.WithString("repo",
619+
mcp.Description("Optional repository name. If provided with owner, only notifications for this repository are listed."),
620+
),
615621
mcp.WithString("sort",
616622
mcp.Description("Sort field by number of matches of categories, defaults to best match"),
617623
mcp.Enum(
@@ -635,56 +641,7 @@ func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (
635641
WithPagination(),
636642
),
637643
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
638-
query, err := RequiredParam[string](request, "q")
639-
if err != nil {
640-
return mcp.NewToolResultError(err.Error()), nil
641-
}
642-
sort, err := OptionalParam[string](request, "sort")
643-
if err != nil {
644-
return mcp.NewToolResultError(err.Error()), nil
645-
}
646-
order, err := OptionalParam[string](request, "order")
647-
if err != nil {
648-
return mcp.NewToolResultError(err.Error()), nil
649-
}
650-
pagination, err := OptionalPaginationParams(request)
651-
if err != nil {
652-
return mcp.NewToolResultError(err.Error()), nil
653-
}
654-
655-
opts := &github.SearchOptions{
656-
Sort: sort,
657-
Order: order,
658-
ListOptions: github.ListOptions{
659-
PerPage: pagination.perPage,
660-
Page: pagination.page,
661-
},
662-
}
663-
664-
client, err := getClient(ctx)
665-
if err != nil {
666-
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
667-
}
668-
result, resp, err := client.Search.Issues(ctx, query, opts)
669-
if err != nil {
670-
return nil, fmt.Errorf("failed to search issues: %w", err)
671-
}
672-
defer func() { _ = resp.Body.Close() }()
673-
674-
if resp.StatusCode != http.StatusOK {
675-
body, err := io.ReadAll(resp.Body)
676-
if err != nil {
677-
return nil, fmt.Errorf("failed to read response body: %w", err)
678-
}
679-
return mcp.NewToolResultError(fmt.Sprintf("failed to search issues: %s", string(body))), nil
680-
}
681-
682-
r, err := json.Marshal(result)
683-
if err != nil {
684-
return nil, fmt.Errorf("failed to marshal response: %w", err)
685-
}
686-
687-
return mcp.NewToolResultText(string(r)), nil
644+
return searchHandler(ctx, getClient, request, "issue", "failed to search issues")
688645
}
689646
}
690647

0 commit comments

Comments
 (0)