Skip to content

Commit 5f341a9

Browse files
make a working version of completions
1 parent 023f59d commit 5f341a9

25 files changed

+242
-50
lines changed

e2e/e2e_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
"github.com/github/github-mcp-server/pkg/github"
2121
"github.com/github/github-mcp-server/pkg/translations"
2222
gogithub "github.com/google/go-github/v69/github"
23-
mcpClient "github.com/mark3labs/mcp-go/client"
24-
"github.com/mark3labs/mcp-go/mcp"
23+
mcpClient "github.com/sammorrowdrums/mcp-go/client"
24+
"github.com/sammorrowdrums/mcp-go/mcp"
2525
"github.com/stretchr/testify/require"
2626
)
2727

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ go 1.23.7
55
require (
66
github.com/google/go-github/v69 v69.2.0
77
github.com/josephburnett/jd v1.9.2
8-
github.com/mark3labs/mcp-go v0.30.0
98
github.com/migueleliasweb/go-github-mock v1.3.0
9+
github.com/sammorrowdrums/mcp-go v0.0.0-20250528234530-f0daf2216052
1010
github.com/sirupsen/logrus v1.9.3
1111
github.com/spf13/cobra v1.9.1
1212
github.com/spf13/viper v1.20.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
4747
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
4848
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
4949
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
50-
github.com/mark3labs/mcp-go v0.30.0 h1:Taz7fiefkxY/l8jz1nA90V+WdM2eoMtlvwfWforVYbo=
51-
github.com/mark3labs/mcp-go v0.30.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
5250
github.com/migueleliasweb/go-github-mock v1.3.0 h1:2sVP9JEMB2ubQw1IKto3/fzF51oFC6eVWOOFDgQoq88=
5351
github.com/migueleliasweb/go-github-mock v1.3.0/go.mod h1:ipQhV8fTcj/G6m7BKzin08GaJ/3B5/SonRAkgrk0zCY=
5452
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -62,6 +60,8 @@ github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWN
6260
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
6361
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
6462
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
63+
github.com/sammorrowdrums/mcp-go v0.0.0-20250528234530-f0daf2216052 h1:c9HI0HGuXED8zwXCdnk2iGyaSC8mvZlBGl+SdHxYJgs=
64+
github.com/sammorrowdrums/mcp-go v0.0.0-20250528234530-f0daf2216052/go.mod h1:Kwt02UMWGJxJ1IHMO9Wrj4GabTSvv9uVUrpht1vjiuk=
6565
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7 h1:cYCy18SHPKRkvclm+pWm1Lk4YrREb4IOIb/YdFO0p2M=
6666
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8=
6767
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=

internal/ghmcp/server.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
mcplog "github.com/github/github-mcp-server/pkg/log"
1717
"github.com/github/github-mcp-server/pkg/translations"
1818
gogithub "github.com/google/go-github/v69/github"
19-
"github.com/mark3labs/mcp-go/mcp"
20-
"github.com/mark3labs/mcp-go/server"
19+
"github.com/sammorrowdrums/mcp-go/mcp"
20+
"github.com/sammorrowdrums/mcp-go/server"
2121
"github.com/shurcooL/githubv4"
2222
"github.com/sirupsen/logrus"
2323
)
@@ -91,7 +91,15 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
9191
OnBeforeInitialize: []server.OnBeforeInitializeFunc{beforeInit},
9292
}
9393

94-
ghServer := github.NewServer(cfg.Version, server.WithHooks(hooks))
94+
getClient := func(_ context.Context) (*gogithub.Client, error) {
95+
return restClient, nil // closing over client
96+
}
97+
98+
getGQLClient := func(_ context.Context) (*githubv4.Client, error) {
99+
return gqlClient, nil // closing over client
100+
}
101+
102+
ghServer := github.NewServer(getClient, cfg.Version, server.WithHooks(hooks))
95103

96104
enabledToolsets := cfg.EnabledToolsets
97105
if cfg.DynamicToolsets {
@@ -104,14 +112,6 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
104112
}
105113
}
106114

107-
getClient := func(_ context.Context) (*gogithub.Client, error) {
108-
return restClient, nil // closing over client
109-
}
110-
111-
getGQLClient := func(_ context.Context) (*githubv4.Client, error) {
112-
return gqlClient, nil // closing over client
113-
}
114-
115115
// Create default toolsets
116116
toolsets, err := github.InitToolsets(
117117
enabledToolsets,

pkg/github/code_scanning.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99

1010
"github.com/github/github-mcp-server/pkg/translations"
1111
"github.com/google/go-github/v69/github"
12-
"github.com/mark3labs/mcp-go/mcp"
13-
"github.com/mark3labs/mcp-go/server"
12+
"github.com/sammorrowdrums/mcp-go/mcp"
13+
"github.com/sammorrowdrums/mcp-go/server"
1414
)
1515

1616
func GetCodeScanningAlert(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {

pkg/github/context_tools.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"context"
55

66
"github.com/github/github-mcp-server/pkg/translations"
7-
"github.com/mark3labs/mcp-go/mcp"
8-
"github.com/mark3labs/mcp-go/server"
7+
"github.com/sammorrowdrums/mcp-go/mcp"
8+
"github.com/sammorrowdrums/mcp-go/server"
99
)
1010

1111
// GetMe creates a tool to get details of the authenticated user.

pkg/github/dynamic_tools.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77

88
"github.com/github/github-mcp-server/pkg/toolsets"
99
"github.com/github/github-mcp-server/pkg/translations"
10-
"github.com/mark3labs/mcp-go/mcp"
11-
"github.com/mark3labs/mcp-go/server"
10+
"github.com/sammorrowdrums/mcp-go/mcp"
11+
"github.com/sammorrowdrums/mcp-go/server"
1212
)
1313

1414
func ToolsetEnum(toolsetGroup *toolsets.ToolsetGroup) mcp.PropertyOption {

pkg/github/helper_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"net/http"
66
"testing"
77

8-
"github.com/mark3labs/mcp-go/mcp"
8+
"github.com/sammorrowdrums/mcp-go/mcp"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)

pkg/github/issues.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"github.com/github/github-mcp-server/pkg/translations"
1313
"github.com/go-viper/mapstructure/v2"
1414
"github.com/google/go-github/v69/github"
15-
"github.com/mark3labs/mcp-go/mcp"
16-
"github.com/mark3labs/mcp-go/server"
15+
"github.com/sammorrowdrums/mcp-go/mcp"
16+
"github.com/sammorrowdrums/mcp-go/server"
1717
"github.com/shurcooL/githubv4"
1818
)
1919

pkg/github/notifications.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111

1212
"github.com/github/github-mcp-server/pkg/translations"
1313
"github.com/google/go-github/v69/github"
14-
"github.com/mark3labs/mcp-go/mcp"
15-
"github.com/mark3labs/mcp-go/server"
14+
"github.com/sammorrowdrums/mcp-go/mcp"
15+
"github.com/sammorrowdrums/mcp-go/server"
1616
)
1717

1818
const (

pkg/github/pullrequests.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99

1010
"github.com/go-viper/mapstructure/v2"
1111
"github.com/google/go-github/v69/github"
12-
"github.com/mark3labs/mcp-go/mcp"
13-
"github.com/mark3labs/mcp-go/server"
12+
"github.com/sammorrowdrums/mcp-go/mcp"
13+
"github.com/sammorrowdrums/mcp-go/server"
1414
"github.com/shurcooL/githubv4"
1515

1616
"github.com/github/github-mcp-server/pkg/translations"

pkg/github/repositories.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99

1010
"github.com/github/github-mcp-server/pkg/translations"
1111
"github.com/google/go-github/v69/github"
12-
"github.com/mark3labs/mcp-go/mcp"
13-
"github.com/mark3labs/mcp-go/server"
12+
"github.com/sammorrowdrums/mcp-go/mcp"
13+
"github.com/sammorrowdrums/mcp-go/server"
1414
)
1515

1616
func GetCommit(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
@@ -132,6 +132,7 @@ func ListCommits(getClient GetClientFn, t translations.TranslationHelperFunc) (t
132132
}
133133

134134
client, err := getClient(ctx)
135+
135136
if err != nil {
136137
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
137138
}

pkg/github/repository_completions.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/google/go-github/v69/github"
9+
"github.com/sammorrowdrums/mcp-go/mcp"
10+
)
11+
12+
// RepositoryResourceCompletionHandler returns a CompletionHandlerFunc for repository resource completions.
13+
func RepositoryResourceCompletionHandler(getClient GetClientFn) func(ctx context.Context, req mcp.CompleteRequest) (*mcp.CompleteResult, error) {
14+
return func(ctx context.Context, req mcp.CompleteRequest) (*mcp.CompleteResult, error) {
15+
ref, ok := req.Params.Ref.(map[string]any)
16+
if !ok || ref["type"] != "ref/resource" {
17+
return nil, nil // Not a resource completion
18+
}
19+
uri, _ := ref["uri"].(string)
20+
argName := req.Params.Argument.Name
21+
argValue := req.Params.Argument.Value
22+
23+
client, err := getClient(ctx)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
var values []string
29+
30+
switch argName {
31+
case "owner":
32+
user, _, err := client.Users.Get(ctx, "")
33+
if err == nil && user.GetLogin() != "" {
34+
values = append(values, user.GetLogin())
35+
}
36+
orgs, _, _ := client.Organizations.List(ctx, "", nil)
37+
for _, org := range orgs {
38+
values = append(values, org.GetLogin())
39+
}
40+
case "repo":
41+
// print the whole mcp complete request for debugging
42+
fmt.Printf("MCP Complete Request: %+v\n", req)
43+
44+
fmt.Printf("URI: %s\n", uri)
45+
owner := getArgFromURI(uri, "owner")
46+
if owner != "" {
47+
repos, _, err := client.Search.Repositories(ctx, fmt.Sprintf("user:%s", owner), &github.SearchOptions{ListOptions: github.ListOptions{PerPage: 100}})
48+
if err != nil || repos == nil {
49+
break
50+
}
51+
for _, repo := range repos.Repositories {
52+
if argValue == "" || strings.Contains(repo.GetName(), argValue) {
53+
values = append(values, repo.GetName())
54+
}
55+
}
56+
}
57+
case "branch":
58+
owner := getArgFromURI(uri, "owner")
59+
repo := getArgFromURI(uri, "repo")
60+
if owner != "" && repo != "" {
61+
branches, _, _ := client.Repositories.ListBranches(ctx, owner, repo, nil)
62+
for _, branch := range branches {
63+
if argValue == "" || strings.Contains(branch.GetName(), argValue) {
64+
values = append(values, branch.GetName())
65+
}
66+
}
67+
}
68+
case "sha":
69+
owner := getArgFromURI(uri, "owner")
70+
repo := getArgFromURI(uri, "repo")
71+
if owner != "" && repo != "" {
72+
commits, _, _ := client.Repositories.ListCommits(ctx, owner, repo, nil)
73+
for _, commit := range commits {
74+
sha := commit.GetSHA()
75+
if argValue == "" || strings.HasPrefix(sha, argValue) {
76+
values = append(values, sha)
77+
}
78+
}
79+
}
80+
case "tag":
81+
owner := getArgFromURI(uri, "owner")
82+
repo := getArgFromURI(uri, "repo")
83+
if owner != "" && repo != "" {
84+
tags, _, _ := client.Repositories.ListTags(ctx, owner, repo, nil)
85+
for _, tag := range tags {
86+
if argValue == "" || strings.Contains(tag.GetName(), argValue) {
87+
values = append(values, tag.GetName())
88+
}
89+
}
90+
}
91+
case "prNumber":
92+
owner := getArgFromURI(uri, "owner")
93+
repo := getArgFromURI(uri, "repo")
94+
if owner != "" && repo != "" {
95+
prs, _, _ := client.PullRequests.List(ctx, owner, repo, nil)
96+
for _, pr := range prs {
97+
num := fmt.Sprintf("%d", pr.GetNumber())
98+
if argValue == "" || strings.HasPrefix(num, argValue) {
99+
values = append(values, num)
100+
}
101+
}
102+
}
103+
case "path":
104+
owner := getArgFromURI(uri, "owner")
105+
repo := getArgFromURI(uri, "repo")
106+
refVal := getArgFromURI(uri, "branch")
107+
if refVal == "" {
108+
refVal = getArgFromURI(uri, "sha")
109+
}
110+
if refVal == "" {
111+
refVal = getArgFromURI(uri, "tag")
112+
}
113+
if refVal == "" {
114+
refVal = "main"
115+
}
116+
if owner != "" && repo != "" {
117+
contents, dirContents, _, _ := client.Repositories.GetContents(ctx, owner, repo, "", &github.RepositoryContentGetOptions{Ref: refVal})
118+
if dirContents != nil {
119+
for _, entry := range dirContents {
120+
if argValue == "" || strings.HasPrefix(entry.GetName(), argValue) {
121+
values = append(values, entry.GetName())
122+
}
123+
}
124+
} else if contents != nil {
125+
if argValue == "" || strings.HasPrefix(contents.GetName(), argValue) {
126+
values = append(values, contents.GetName())
127+
}
128+
}
129+
}
130+
}
131+
132+
if len(values) > 100 {
133+
values = values[:100]
134+
}
135+
136+
return &mcp.CompleteResult{
137+
Completion: struct {
138+
Values []string `json:"values"`
139+
Total int `json:"total,omitempty"`
140+
HasMore bool `json:"hasMore,omitempty"`
141+
}{
142+
Values: values,
143+
Total: len(values),
144+
HasMore: false,
145+
},
146+
}, nil
147+
}
148+
}
149+
150+
func getArgFromURI(uri, name string) string {
151+
trimmed := strings.TrimPrefix(uri, "repo://")
152+
parts := strings.Split(trimmed, "/")
153+
if name == "owner" && len(parts) > 0 && parts[0] != "" {
154+
return parts[0]
155+
}
156+
if name == "repo" && len(parts) > 1 && parts[1] != "" {
157+
return parts[1]
158+
}
159+
return ""
160+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/google/go-github/v69/github"
8+
"github.com/sammorrowdrums/mcp-go/mcp"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
// Add more fake methods as needed for testing
13+
func TestRepositoryResourceCompletionHandler_Owner(t *testing.T) {
14+
// Stub getClient to return a fake client with a user and orgs
15+
getClient := func(ctx context.Context) (*github.Client, error) {
16+
client := github.NewClient(nil)
17+
// You can use github's testing helpers or mock the methods as needed
18+
return client, nil
19+
}
20+
21+
handler := RepositoryResourceCompletionHandler(getClient)
22+
request := mcp.CompleteRequest{}
23+
request.Params.Ref = map[string]any{"type": "ref/resource", "uri": "repo://"}
24+
request.Params.Argument.Name = "owner"
25+
request.Params.Argument.Value = ""
26+
27+
result, err := handler(context.Background(), request)
28+
require.NoError(t, err)
29+
// In a real test, assert on result.Completion.Values
30+
_ = result
31+
}

pkg/github/repository_resource.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313

1414
"github.com/github/github-mcp-server/pkg/translations"
1515
"github.com/google/go-github/v69/github"
16-
"github.com/mark3labs/mcp-go/mcp"
17-
"github.com/mark3labs/mcp-go/server"
16+
"github.com/sammorrowdrums/mcp-go/mcp"
17+
"github.com/sammorrowdrums/mcp-go/server"
1818
)
1919

2020
// GetRepositoryResourceContent defines the resource template and handler for getting repository content.
@@ -66,7 +66,7 @@ func GetRepositoryResourcePrContent(getClient GetClientFn, t translations.Transl
6666
func RepositoryResourceContentsHandler(getClient GetClientFn) func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
6767
return func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
6868
// the matcher will give []string with one element
69-
// https://github.com/mark3labs/mcp-go/pull/54
69+
// https://github.com/sammorrowdrums/mcp-go/pull/54
7070
o, ok := request.Params.Arguments["owner"].([]string)
7171
if !ok || len(o) == 0 {
7272
return nil, errors.New("owner is required")

pkg/github/repository_resource_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77

88
"github.com/github/github-mcp-server/pkg/translations"
99
"github.com/google/go-github/v69/github"
10-
"github.com/mark3labs/mcp-go/mcp"
1110
"github.com/migueleliasweb/go-github-mock/src/mock"
11+
"github.com/sammorrowdrums/mcp-go/mcp"
1212
"github.com/stretchr/testify/require"
1313
)
1414

0 commit comments

Comments
 (0)