Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit90a5d0d

Browse files
authored
Merge branch 'main' into prcomments
2 parents84e6f6a +919a10c commit90a5d0d

18 files changed

+937
-164
lines changed

‎.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
@juruen@sammorrowdrums@williammartin@toby
1+
*@juruen@sammorrowdrums@williammartin@toby

‎README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ automation and interaction capabilities for developers and tools.
1515
##Prerequisites
1616

1717
1. To run the server in a container, you will need to have[Docker](https://www.docker.com/) installed.
18-
2.[Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
18+
2. Once Docker is installed, you will also need to ensure Docker is running.
19+
3. Lastly you will need to[Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
1920
The MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the[documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)).
2021

2122

@@ -310,6 +311,17 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
310311
-`comment_id`: The unique identifier of the comment to reply to (number, required)
311312
-`body`: The text of the reply comment (string, required)
312313

314+
-**update_pull_request** - Update an existing pull request in a GitHub repository
315+
316+
-`owner`: Repository owner (string, required)
317+
-`repo`: Repository name (string, required)
318+
-`pullNumber`: Pull request number to update (number, required)
319+
-`title`: New title (string, optional)
320+
-`body`: New description (string, optional)
321+
-`state`: New state ('open' or 'closed') (string, optional)
322+
-`base`: New base branch name (string, optional)
323+
-`maintainer_can_modify`: Allow maintainer edits (boolean, optional)
324+
313325
###Repositories
314326

315327
-**create_or_update_file** - Create or update a single file in a repository
@@ -365,14 +377,21 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
365377
-`branch`: New branch name (string, required)
366378
-`sha`: SHA to create branch from (string, required)
367379

368-
-**list_commits** -Gets commits of a branch in a repository
380+
-**list_commits** -Get a list of commits of a branch in a repository
369381
-`owner`: Repository owner (string, required)
370382
-`repo`: Repository name (string, required)
371383
-`sha`: Branch name, tag, or commit SHA (string, optional)
372384
-`path`: Only commits containing this file path (string, optional)
373385
-`page`: Page number (number, optional)
374386
-`perPage`: Results per page (number, optional)
375387

388+
-**get_commit** - Get details for a commit from a repository
389+
-`owner`: Repository owner (string, required)
390+
-`repo`: Repository name (string, required)
391+
-`sha`: Commit SHA, branch name, or tag name (string, required)
392+
-`page`: Page number, for files in the commit (number, optional)
393+
-`perPage`: Results per page, for files in the commit (number, optional)
394+
376395
###Search
377396

378397
-**search_code** - Search for code across GitHub repositories

‎cmd/github-mcp-server/main.go

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package main
22

33
import (
4-
"bytes"
54
"context"
6-
"encoding/json"
75
"fmt"
86
"io"
97
stdlog"log"
@@ -41,7 +39,6 @@ var (
4139
logFile:=viper.GetString("log-file")
4240
readOnly:=viper.GetBool("read-only")
4341
exportTranslations:=viper.GetBool("export-translations")
44-
prettyPrintJSON:=viper.GetBool("pretty-print-json")
4542
logger,err:=initLogger(logFile)
4643
iferr!=nil {
4744
stdlog.Fatal("Failed to initialize logger:",err)
@@ -52,7 +49,6 @@ var (
5249
logger:logger,
5350
logCommands:logCommands,
5451
exportTranslations:exportTranslations,
55-
prettyPrintJSON:prettyPrintJSON,
5652
}
5753
iferr:=runStdioServer(cfg);err!=nil {
5854
stdlog.Fatal("failed to run stdio server:",err)
@@ -70,15 +66,13 @@ func init() {
7066
rootCmd.PersistentFlags().Bool("enable-command-logging",false,"When enabled, the server will log all command requests and responses to the log file")
7167
rootCmd.PersistentFlags().Bool("export-translations",false,"Save translations to a JSON file")
7268
rootCmd.PersistentFlags().String("gh-host","","Specify the GitHub hostname (for GitHub Enterprise etc.)")
73-
rootCmd.PersistentFlags().Bool("pretty-print-json",false,"Pretty print JSON output")
7469

7570
// Bind flag to viper
7671
_=viper.BindPFlag("read-only",rootCmd.PersistentFlags().Lookup("read-only"))
7772
_=viper.BindPFlag("log-file",rootCmd.PersistentFlags().Lookup("log-file"))
7873
_=viper.BindPFlag("enable-command-logging",rootCmd.PersistentFlags().Lookup("enable-command-logging"))
7974
_=viper.BindPFlag("export-translations",rootCmd.PersistentFlags().Lookup("export-translations"))
8075
_=viper.BindPFlag("gh-host",rootCmd.PersistentFlags().Lookup("gh-host"))
81-
_=viper.BindPFlag("pretty-print-json",rootCmd.PersistentFlags().Lookup("pretty-print-json"))
8276

8377
// Add subcommands
8478
rootCmd.AddCommand(stdioCmd)
@@ -112,20 +106,6 @@ type runConfig struct {
112106
logger*log.Logger
113107
logCommandsbool
114108
exportTranslationsbool
115-
prettyPrintJSONbool
116-
}
117-
118-
// JSONPrettyPrintWriter is a Writer that pretty prints input to indented JSON
119-
typeJSONPrettyPrintWriterstruct {
120-
writer io.Writer
121-
}
122-
123-
func (jJSONPrettyPrintWriter)Write(p []byte) (nint,errerror) {
124-
varprettyJSON bytes.Buffer
125-
iferr:=json.Indent(&prettyJSON,p,"","\t");err!=nil {
126-
return0,err
127-
}
128-
returnj.writer.Write(prettyJSON.Bytes())
129109
}
130110

131111
funcrunStdioServer(cfgrunConfig)error {
@@ -157,8 +137,11 @@ func runStdioServer(cfg runConfig) error {
157137

158138
t,dumpTranslations:=translations.TranslationHelper()
159139

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

164147
stdLogger:=stdlog.New(cfg.logger.Writer(),"stdioserver",0)
@@ -179,9 +162,6 @@ func runStdioServer(cfg runConfig) error {
179162
in,out=loggedIO,loggedIO
180163
}
181164

182-
ifcfg.prettyPrintJSON {
183-
out=JSONPrettyPrintWriter{writer:out}
184-
}
185165
errC<-stdioServer.Listen(ctx,in,out)
186166
}()
187167

‎pkg/github/code_scanning.go

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

16-
funcGetCodeScanningAlert(client*github.Client,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
16+
funcGetCodeScanningAlert(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
1717
returnmcp.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
returnmcp.NewToolResultError(err.Error()),nil
4444
}
4545

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

69-
funcListCodeScanningAlerts(client*github.Client,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
74+
funcListCodeScanningAlerts(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
7075
returnmcp.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
returnmcp.NewToolResultError(err.Error()),nil
111116
}
112117

118+
client,err:=getClient(ctx)
119+
iferr!=nil {
120+
returnnil,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
iferr!=nil {
115124
returnnil,fmt.Errorf("failed to list alerts: %w",err)

‎pkg/github/code_scanning_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
funcTest_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
funcTest_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)

‎pkg/github/helper_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,115 @@ func getTextResult(t *testing.T, result *mcp.CallToolResult) mcp.TextContent {
9393
assert.Equal(t,"text",textContent.Type)
9494
returntextContent
9595
}
96+
97+
funcTestOptionalParamOK(t*testing.T) {
98+
tests:= []struct {
99+
namestring
100+
argsmap[string]interface{}
101+
paramNamestring
102+
expectedValinterface{}
103+
expectedOkbool
104+
expectErrorbool
105+
errorMsgstring
106+
}{
107+
{
108+
name:"present and correct type (string)",
109+
args:map[string]interface{}{"myParam":"hello"},
110+
paramName:"myParam",
111+
expectedVal:"hello",
112+
expectedOk:true,
113+
expectError:false,
114+
},
115+
{
116+
name:"present and correct type (bool)",
117+
args:map[string]interface{}{"myParam":true},
118+
paramName:"myParam",
119+
expectedVal:true,
120+
expectedOk:true,
121+
expectError:false,
122+
},
123+
{
124+
name:"present and correct type (number)",
125+
args:map[string]interface{}{"myParam":float64(123)},
126+
paramName:"myParam",
127+
expectedVal:float64(123),
128+
expectedOk:true,
129+
expectError:false,
130+
},
131+
{
132+
name:"present but wrong type (string expected, got bool)",
133+
args:map[string]interface{}{"myParam":true},
134+
paramName:"myParam",
135+
expectedVal:"",// Zero value for string
136+
expectedOk:true,// ok is true because param exists
137+
expectError:true,
138+
errorMsg:"parameter myParam is not of type string, is bool",
139+
},
140+
{
141+
name:"present but wrong type (bool expected, got string)",
142+
args:map[string]interface{}{"myParam":"true"},
143+
paramName:"myParam",
144+
expectedVal:false,// Zero value for bool
145+
expectedOk:true,// ok is true because param exists
146+
expectError:true,
147+
errorMsg:"parameter myParam is not of type bool, is string",
148+
},
149+
{
150+
name:"parameter not present",
151+
args:map[string]interface{}{"anotherParam":"value"},
152+
paramName:"myParam",
153+
expectedVal:"",// Zero value for string
154+
expectedOk:false,
155+
expectError:false,
156+
},
157+
}
158+
159+
for_,tc:=rangetests {
160+
t.Run(tc.name,func(t*testing.T) {
161+
request:=createMCPRequest(tc.args)
162+
163+
// Test with string type assertion
164+
if_,isString:=tc.expectedVal.(string);isString||tc.errorMsg=="parameter myParam is not of type string, is bool" {
165+
val,ok,err:=OptionalParamOK[string](request,tc.paramName)
166+
iftc.expectError {
167+
require.Error(t,err)
168+
assert.Contains(t,err.Error(),tc.errorMsg)
169+
assert.Equal(t,tc.expectedOk,ok)// Check ok even on error
170+
assert.Equal(t,tc.expectedVal,val)// Check zero value on error
171+
}else {
172+
require.NoError(t,err)
173+
assert.Equal(t,tc.expectedOk,ok)
174+
assert.Equal(t,tc.expectedVal,val)
175+
}
176+
}
177+
178+
// Test with bool type assertion
179+
if_,isBool:=tc.expectedVal.(bool);isBool||tc.errorMsg=="parameter myParam is not of type bool, is string" {
180+
val,ok,err:=OptionalParamOK[bool](request,tc.paramName)
181+
iftc.expectError {
182+
require.Error(t,err)
183+
assert.Contains(t,err.Error(),tc.errorMsg)
184+
assert.Equal(t,tc.expectedOk,ok)// Check ok even on error
185+
assert.Equal(t,tc.expectedVal,val)// Check zero value on error
186+
}else {
187+
require.NoError(t,err)
188+
assert.Equal(t,tc.expectedOk,ok)
189+
assert.Equal(t,tc.expectedVal,val)
190+
}
191+
}
192+
193+
// Test with float64 type assertion (for number case)
194+
if_,isFloat:=tc.expectedVal.(float64);isFloat {
195+
val,ok,err:=OptionalParamOK[float64](request,tc.paramName)
196+
iftc.expectError {
197+
// This case shouldn't happen for float64 in the defined tests
198+
require.Fail(t,"Unexpected error case for float64")
199+
}else {
200+
require.NoError(t,err)
201+
assert.Equal(t,tc.expectedOk,ok)
202+
assert.Equal(t,tc.expectedVal,val)
203+
}
204+
}
205+
})
206+
}
207+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp