Skip to content

Commit 3ec8699

Browse files
chore: groundwork for multi-user to server
1 parent 86fbc85 commit 3ec8699

15 files changed

+287
-143
lines changed

Diff for: cmd/github-mcp-server/main.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,11 @@ func runStdioServer(cfg runConfig) error {
137137

138138
t, dumpTranslations := translations.TranslationHelper()
139139

140+
getClient := func(_ context.Context) (*gogithub.Client, error) {
141+
return ghClient, nil // closing over client
142+
}
140143
// Create
141-
ghServer := github.NewServer(ghClient, version, cfg.readOnly, t)
144+
ghServer := github.NewServer(getClient, version, cfg.readOnly, t)
142145
stdioServer := server.NewStdioServer(ghServer)
143146

144147
stdLogger := stdlog.New(cfg.logger.Writer(), "stdioserver", 0)

Diff for: pkg/github/code_scanning.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/mark3labs/mcp-go/server"
1414
)
1515

16-
func GetCodeScanningAlert(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
16+
func GetCodeScanningAlert(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
1717
return mcp.NewTool("get_code_scanning_alert",
1818
mcp.WithDescription(t("TOOL_GET_CODE_SCANNING_ALERT_DESCRIPTION", "Get details of a specific code scanning alert in a GitHub repository.")),
1919
mcp.WithString("owner",
@@ -43,6 +43,11 @@ func GetCodeScanningAlert(client *github.Client, t translations.TranslationHelpe
4343
return mcp.NewToolResultError(err.Error()), nil
4444
}
4545

46+
client, err := getClient(ctx)
47+
if err != nil {
48+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
49+
}
50+
4651
alert, resp, err := client.CodeScanning.GetAlert(ctx, owner, repo, int64(alertNumber))
4752
if err != nil {
4853
return nil, fmt.Errorf("failed to get alert: %w", err)
@@ -66,7 +71,7 @@ func GetCodeScanningAlert(client *github.Client, t translations.TranslationHelpe
6671
}
6772
}
6873

69-
func ListCodeScanningAlerts(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
74+
func ListCodeScanningAlerts(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
7075
return mcp.NewTool("list_code_scanning_alerts",
7176
mcp.WithDescription(t("TOOL_LIST_CODE_SCANNING_ALERTS_DESCRIPTION", "List code scanning alerts in a GitHub repository.")),
7277
mcp.WithString("owner",
@@ -110,6 +115,10 @@ func ListCodeScanningAlerts(client *github.Client, t translations.TranslationHel
110115
return mcp.NewToolResultError(err.Error()), nil
111116
}
112117

118+
client, err := getClient(ctx)
119+
if err != nil {
120+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
121+
}
113122
alerts, resp, err := client.CodeScanning.ListAlertsForRepo(ctx, owner, repo, &github.AlertListOptions{Ref: ref, State: state, Severity: severity})
114123
if err != nil {
115124
return nil, fmt.Errorf("failed to list alerts: %w", err)

Diff for: pkg/github/code_scanning_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
func Test_GetCodeScanningAlert(t *testing.T) {
1717
// Verify tool definition once
1818
mockClient := github.NewClient(nil)
19-
tool, _ := GetCodeScanningAlert(mockClient, translations.NullTranslationHelper)
19+
tool, _ := GetCodeScanningAlert(stubGetClientFn(mockClient), translations.NullTranslationHelper)
2020

2121
assert.Equal(t, "get_code_scanning_alert", tool.Name)
2222
assert.NotEmpty(t, tool.Description)
@@ -82,7 +82,7 @@ func Test_GetCodeScanningAlert(t *testing.T) {
8282
t.Run(tc.name, func(t *testing.T) {
8383
// Setup client with mock
8484
client := github.NewClient(tc.mockedClient)
85-
_, handler := GetCodeScanningAlert(client, translations.NullTranslationHelper)
85+
_, handler := GetCodeScanningAlert(stubGetClientFn(client), translations.NullTranslationHelper)
8686

8787
// Create call request
8888
request := createMCPRequest(tc.requestArgs)
@@ -118,7 +118,7 @@ func Test_GetCodeScanningAlert(t *testing.T) {
118118
func Test_ListCodeScanningAlerts(t *testing.T) {
119119
// Verify tool definition once
120120
mockClient := github.NewClient(nil)
121-
tool, _ := ListCodeScanningAlerts(mockClient, translations.NullTranslationHelper)
121+
tool, _ := ListCodeScanningAlerts(stubGetClientFn(mockClient), translations.NullTranslationHelper)
122122

123123
assert.Equal(t, "list_code_scanning_alerts", tool.Name)
124124
assert.NotEmpty(t, tool.Description)
@@ -201,7 +201,7 @@ func Test_ListCodeScanningAlerts(t *testing.T) {
201201
t.Run(tc.name, func(t *testing.T) {
202202
// Setup client with mock
203203
client := github.NewClient(tc.mockedClient)
204-
_, handler := ListCodeScanningAlerts(client, translations.NullTranslationHelper)
204+
_, handler := ListCodeScanningAlerts(stubGetClientFn(client), translations.NullTranslationHelper)
205205

206206
// Create call request
207207
request := createMCPRequest(tc.requestArgs)

Diff for: pkg/github/issues.go

+35-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
// GetIssue creates a tool to get details of a specific issue in a GitHub repository.
18-
func GetIssue(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
18+
func GetIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
1919
return mcp.NewTool("get_issue",
2020
mcp.WithDescription(t("TOOL_GET_ISSUE_DESCRIPTION", "Get details of a specific issue in a GitHub repository")),
2121
mcp.WithString("owner",
@@ -45,6 +45,10 @@ func GetIssue(client *github.Client, t translations.TranslationHelperFunc) (tool
4545
return mcp.NewToolResultError(err.Error()), nil
4646
}
4747

48+
client, err := getClient(ctx)
49+
if err != nil {
50+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
51+
}
4852
issue, resp, err := client.Issues.Get(ctx, owner, repo, issueNumber)
4953
if err != nil {
5054
return nil, fmt.Errorf("failed to get issue: %w", err)
@@ -69,7 +73,7 @@ func GetIssue(client *github.Client, t translations.TranslationHelperFunc) (tool
6973
}
7074

7175
// AddIssueComment creates a tool to add a comment to an issue.
72-
func AddIssueComment(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
76+
func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
7377
return mcp.NewTool("add_issue_comment",
7478
mcp.WithDescription(t("TOOL_ADD_ISSUE_COMMENT_DESCRIPTION", "Add a comment to an existing issue")),
7579
mcp.WithString("owner",
@@ -111,6 +115,10 @@ func AddIssueComment(client *github.Client, t translations.TranslationHelperFunc
111115
Body: github.Ptr(body),
112116
}
113117

118+
client, err := getClient(ctx)
119+
if err != nil {
120+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
121+
}
114122
createdComment, resp, err := client.Issues.CreateComment(ctx, owner, repo, issueNumber, comment)
115123
if err != nil {
116124
return nil, fmt.Errorf("failed to create comment: %w", err)
@@ -135,7 +143,7 @@ func AddIssueComment(client *github.Client, t translations.TranslationHelperFunc
135143
}
136144

137145
// SearchIssues creates a tool to search for issues and pull requests.
138-
func SearchIssues(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
146+
func SearchIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
139147
return mcp.NewTool("search_issues",
140148
mcp.WithDescription(t("TOOL_SEARCH_ISSUES_DESCRIPTION", "Search for issues and pull requests across GitHub repositories")),
141149
mcp.WithString("q",
@@ -191,6 +199,10 @@ func SearchIssues(client *github.Client, t translations.TranslationHelperFunc) (
191199
},
192200
}
193201

202+
client, err := getClient(ctx)
203+
if err != nil {
204+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
205+
}
194206
result, resp, err := client.Search.Issues(ctx, query, opts)
195207
if err != nil {
196208
return nil, fmt.Errorf("failed to search issues: %w", err)
@@ -215,7 +227,7 @@ func SearchIssues(client *github.Client, t translations.TranslationHelperFunc) (
215227
}
216228

217229
// CreateIssue creates a tool to create a new issue in a GitHub repository.
218-
func CreateIssue(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
230+
func CreateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
219231
return mcp.NewTool("create_issue",
220232
mcp.WithDescription(t("TOOL_CREATE_ISSUE_DESCRIPTION", "Create a new issue in a GitHub repository")),
221233
mcp.WithString("owner",
@@ -305,6 +317,10 @@ func CreateIssue(client *github.Client, t translations.TranslationHelperFunc) (t
305317
Milestone: milestoneNum,
306318
}
307319

320+
client, err := getClient(ctx)
321+
if err != nil {
322+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
323+
}
308324
issue, resp, err := client.Issues.Create(ctx, owner, repo, issueRequest)
309325
if err != nil {
310326
return nil, fmt.Errorf("failed to create issue: %w", err)
@@ -329,7 +345,7 @@ func CreateIssue(client *github.Client, t translations.TranslationHelperFunc) (t
329345
}
330346

331347
// ListIssues creates a tool to list and filter repository issues
332-
func ListIssues(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
348+
func ListIssues(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
333349
return mcp.NewTool("list_issues",
334350
mcp.WithDescription(t("TOOL_LIST_ISSUES_DESCRIPTION", "List issues in a GitHub repository with filtering options")),
335351
mcp.WithString("owner",
@@ -419,6 +435,10 @@ func ListIssues(client *github.Client, t translations.TranslationHelperFunc) (to
419435
opts.PerPage = int(perPage)
420436
}
421437

438+
client, err := getClient(ctx)
439+
if err != nil {
440+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
441+
}
422442
issues, resp, err := client.Issues.ListByRepo(ctx, owner, repo, opts)
423443
if err != nil {
424444
return nil, fmt.Errorf("failed to list issues: %w", err)
@@ -443,7 +463,7 @@ func ListIssues(client *github.Client, t translations.TranslationHelperFunc) (to
443463
}
444464

445465
// UpdateIssue creates a tool to update an existing issue in a GitHub repository.
446-
func UpdateIssue(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
466+
func UpdateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
447467
return mcp.NewTool("update_issue",
448468
mcp.WithDescription(t("TOOL_UPDATE_ISSUE_DESCRIPTION", "Update an existing issue in a GitHub repository")),
449469
mcp.WithString("owner",
@@ -557,6 +577,10 @@ func UpdateIssue(client *github.Client, t translations.TranslationHelperFunc) (t
557577
issueRequest.Milestone = &milestoneNum
558578
}
559579

580+
client, err := getClient(ctx)
581+
if err != nil {
582+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
583+
}
560584
updatedIssue, resp, err := client.Issues.Edit(ctx, owner, repo, issueNumber, issueRequest)
561585
if err != nil {
562586
return nil, fmt.Errorf("failed to update issue: %w", err)
@@ -581,7 +605,7 @@ func UpdateIssue(client *github.Client, t translations.TranslationHelperFunc) (t
581605
}
582606

583607
// GetIssueComments creates a tool to get comments for a GitHub issue.
584-
func GetIssueComments(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
608+
func GetIssueComments(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
585609
return mcp.NewTool("get_issue_comments",
586610
mcp.WithDescription(t("TOOL_GET_ISSUE_COMMENTS_DESCRIPTION", "Get comments for a GitHub issue")),
587611
mcp.WithString("owner",
@@ -632,6 +656,10 @@ func GetIssueComments(client *github.Client, t translations.TranslationHelperFun
632656
},
633657
}
634658

659+
client, err := getClient(ctx)
660+
if err != nil {
661+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
662+
}
635663
comments, resp, err := client.Issues.ListComments(ctx, owner, repo, issueNumber, opts)
636664
if err != nil {
637665
return nil, fmt.Errorf("failed to get issue comments: %w", err)

Diff for: pkg/github/issues_test.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
func Test_GetIssue(t *testing.T) {
1919
// Verify tool definition once
2020
mockClient := github.NewClient(nil)
21-
tool, _ := GetIssue(mockClient, translations.NullTranslationHelper)
21+
tool, _ := GetIssue(stubGetClientFn(mockClient), translations.NullTranslationHelper)
2222

2323
assert.Equal(t, "get_issue", tool.Name)
2424
assert.NotEmpty(t, tool.Description)
@@ -82,7 +82,7 @@ func Test_GetIssue(t *testing.T) {
8282
t.Run(tc.name, func(t *testing.T) {
8383
// Setup client with mock
8484
client := github.NewClient(tc.mockedClient)
85-
_, handler := GetIssue(client, translations.NullTranslationHelper)
85+
_, handler := GetIssue(stubGetClientFn(client), translations.NullTranslationHelper)
8686

8787
// Create call request
8888
request := createMCPRequest(tc.requestArgs)
@@ -114,7 +114,7 @@ func Test_GetIssue(t *testing.T) {
114114
func Test_AddIssueComment(t *testing.T) {
115115
// Verify tool definition once
116116
mockClient := github.NewClient(nil)
117-
tool, _ := AddIssueComment(mockClient, translations.NullTranslationHelper)
117+
tool, _ := AddIssueComment(stubGetClientFn(mockClient), translations.NullTranslationHelper)
118118

119119
assert.Equal(t, "add_issue_comment", tool.Name)
120120
assert.NotEmpty(t, tool.Description)
@@ -185,7 +185,7 @@ func Test_AddIssueComment(t *testing.T) {
185185
t.Run(tc.name, func(t *testing.T) {
186186
// Setup client with mock
187187
client := github.NewClient(tc.mockedClient)
188-
_, handler := AddIssueComment(client, translations.NullTranslationHelper)
188+
_, handler := AddIssueComment(stubGetClientFn(client), translations.NullTranslationHelper)
189189

190190
// Create call request
191191
request := mcp.CallToolRequest{
@@ -237,7 +237,7 @@ func Test_AddIssueComment(t *testing.T) {
237237
func Test_SearchIssues(t *testing.T) {
238238
// Verify tool definition once
239239
mockClient := github.NewClient(nil)
240-
tool, _ := SearchIssues(mockClient, translations.NullTranslationHelper)
240+
tool, _ := SearchIssues(stubGetClientFn(mockClient), translations.NullTranslationHelper)
241241

242242
assert.Equal(t, "search_issues", tool.Name)
243243
assert.NotEmpty(t, tool.Description)
@@ -352,7 +352,7 @@ func Test_SearchIssues(t *testing.T) {
352352
t.Run(tc.name, func(t *testing.T) {
353353
// Setup client with mock
354354
client := github.NewClient(tc.mockedClient)
355-
_, handler := SearchIssues(client, translations.NullTranslationHelper)
355+
_, handler := SearchIssues(stubGetClientFn(client), translations.NullTranslationHelper)
356356

357357
// Create call request
358358
request := createMCPRequest(tc.requestArgs)
@@ -393,7 +393,7 @@ func Test_SearchIssues(t *testing.T) {
393393
func Test_CreateIssue(t *testing.T) {
394394
// Verify tool definition once
395395
mockClient := github.NewClient(nil)
396-
tool, _ := CreateIssue(mockClient, translations.NullTranslationHelper)
396+
tool, _ := CreateIssue(stubGetClientFn(mockClient), translations.NullTranslationHelper)
397397

398398
assert.Equal(t, "create_issue", tool.Name)
399399
assert.NotEmpty(t, tool.Description)
@@ -506,7 +506,7 @@ func Test_CreateIssue(t *testing.T) {
506506
t.Run(tc.name, func(t *testing.T) {
507507
// Setup client with mock
508508
client := github.NewClient(tc.mockedClient)
509-
_, handler := CreateIssue(client, translations.NullTranslationHelper)
509+
_, handler := CreateIssue(stubGetClientFn(client), translations.NullTranslationHelper)
510510

511511
// Create call request
512512
request := createMCPRequest(tc.requestArgs)
@@ -567,7 +567,7 @@ func Test_CreateIssue(t *testing.T) {
567567
func Test_ListIssues(t *testing.T) {
568568
// Verify tool definition
569569
mockClient := github.NewClient(nil)
570-
tool, _ := ListIssues(mockClient, translations.NullTranslationHelper)
570+
tool, _ := ListIssues(stubGetClientFn(mockClient), translations.NullTranslationHelper)
571571

572572
assert.Equal(t, "list_issues", tool.Name)
573573
assert.NotEmpty(t, tool.Description)
@@ -698,7 +698,7 @@ func Test_ListIssues(t *testing.T) {
698698
t.Run(tc.name, func(t *testing.T) {
699699
// Setup client with mock
700700
client := github.NewClient(tc.mockedClient)
701-
_, handler := ListIssues(client, translations.NullTranslationHelper)
701+
_, handler := ListIssues(stubGetClientFn(client), translations.NullTranslationHelper)
702702

703703
// Create call request
704704
request := createMCPRequest(tc.requestArgs)
@@ -743,7 +743,7 @@ func Test_ListIssues(t *testing.T) {
743743
func Test_UpdateIssue(t *testing.T) {
744744
// Verify tool definition
745745
mockClient := github.NewClient(nil)
746-
tool, _ := UpdateIssue(mockClient, translations.NullTranslationHelper)
746+
tool, _ := UpdateIssue(stubGetClientFn(mockClient), translations.NullTranslationHelper)
747747

748748
assert.Equal(t, "update_issue", tool.Name)
749749
assert.NotEmpty(t, tool.Description)
@@ -882,7 +882,7 @@ func Test_UpdateIssue(t *testing.T) {
882882
t.Run(tc.name, func(t *testing.T) {
883883
// Setup client with mock
884884
client := github.NewClient(tc.mockedClient)
885-
_, handler := UpdateIssue(client, translations.NullTranslationHelper)
885+
_, handler := UpdateIssue(stubGetClientFn(client), translations.NullTranslationHelper)
886886

887887
// Create call request
888888
request := createMCPRequest(tc.requestArgs)
@@ -1000,7 +1000,7 @@ func Test_ParseISOTimestamp(t *testing.T) {
10001000
func Test_GetIssueComments(t *testing.T) {
10011001
// Verify tool definition once
10021002
mockClient := github.NewClient(nil)
1003-
tool, _ := GetIssueComments(mockClient, translations.NullTranslationHelper)
1003+
tool, _ := GetIssueComments(stubGetClientFn(mockClient), translations.NullTranslationHelper)
10041004

10051005
assert.Equal(t, "get_issue_comments", tool.Name)
10061006
assert.NotEmpty(t, tool.Description)
@@ -1100,7 +1100,7 @@ func Test_GetIssueComments(t *testing.T) {
11001100
t.Run(tc.name, func(t *testing.T) {
11011101
// Setup client with mock
11021102
client := github.NewClient(tc.mockedClient)
1103-
_, handler := GetIssueComments(client, translations.NullTranslationHelper)
1103+
_, handler := GetIssueComments(stubGetClientFn(client), translations.NullTranslationHelper)
11041104

11051105
// Create call request
11061106
request := createMCPRequest(tc.requestArgs)

0 commit comments

Comments
 (0)