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

Commit919a10c

Browse files
authored
Add tool for getting a single commit (includes stats, files) (#216)
* Add tool for getting a commit* Split mock back out, use RepositoryCommit with Files/Stats
1 parent651a3aa commit919a10c

File tree

4 files changed

+206
-1
lines changed

4 files changed

+206
-1
lines changed

‎README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,21 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
354354
-`branch`: New branch name (string, required)
355355
-`sha`: SHA to create branch from (string, required)
356356

357-
-**list_commits** -Gets commits of a branch in a repository
357+
-**list_commits** -Get a list of commits of a branch in a repository
358358
-`owner`: Repository owner (string, required)
359359
-`repo`: Repository name (string, required)
360360
-`sha`: Branch name, tag, or commit SHA (string, optional)
361361
-`path`: Only commits containing this file path (string, optional)
362362
-`page`: Page number (number, optional)
363363
-`perPage`: Results per page (number, optional)
364364

365+
-**get_commit** - Get details for a commit from a repository
366+
-`owner`: Repository owner (string, required)
367+
-`repo`: Repository name (string, required)
368+
-`sha`: Commit SHA, branch name, or tag name (string, required)
369+
-`page`: Page number, for files in the commit (number, optional)
370+
-`perPage`: Results per page, for files in the commit (number, optional)
371+
365372
###Search
366373

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

‎pkg/github/repositories.go

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

16+
funcGetCommit(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
17+
returnmcp.NewTool("get_commit",
18+
mcp.WithDescription(t("TOOL_GET_COMMITS_DESCRIPTION","Get details for a commit from a GitHub repository")),
19+
mcp.WithString("owner",
20+
mcp.Required(),
21+
mcp.Description("Repository owner"),
22+
),
23+
mcp.WithString("repo",
24+
mcp.Required(),
25+
mcp.Description("Repository name"),
26+
),
27+
mcp.WithString("sha",
28+
mcp.Required(),
29+
mcp.Description("Commit SHA, branch name, or tag name"),
30+
),
31+
WithPagination(),
32+
),
33+
func(ctx context.Context,request mcp.CallToolRequest) (*mcp.CallToolResult,error) {
34+
owner,err:=requiredParam[string](request,"owner")
35+
iferr!=nil {
36+
returnmcp.NewToolResultError(err.Error()),nil
37+
}
38+
repo,err:=requiredParam[string](request,"repo")
39+
iferr!=nil {
40+
returnmcp.NewToolResultError(err.Error()),nil
41+
}
42+
sha,err:=requiredParam[string](request,"sha")
43+
iferr!=nil {
44+
returnmcp.NewToolResultError(err.Error()),nil
45+
}
46+
pagination,err:=OptionalPaginationParams(request)
47+
iferr!=nil {
48+
returnmcp.NewToolResultError(err.Error()),nil
49+
}
50+
51+
opts:=&github.ListOptions{
52+
Page:pagination.page,
53+
PerPage:pagination.perPage,
54+
}
55+
56+
client,err:=getClient(ctx)
57+
iferr!=nil {
58+
returnnil,fmt.Errorf("failed to get GitHub client: %w",err)
59+
}
60+
commit,resp,err:=client.Repositories.GetCommit(ctx,owner,repo,sha,opts)
61+
iferr!=nil {
62+
returnnil,fmt.Errorf("failed to get commit: %w",err)
63+
}
64+
deferfunc() {_=resp.Body.Close() }()
65+
66+
ifresp.StatusCode!=200 {
67+
body,err:=io.ReadAll(resp.Body)
68+
iferr!=nil {
69+
returnnil,fmt.Errorf("failed to read response body: %w",err)
70+
}
71+
returnmcp.NewToolResultError(fmt.Sprintf("failed to get commit: %s",string(body))),nil
72+
}
73+
74+
r,err:=json.Marshal(commit)
75+
iferr!=nil {
76+
returnnil,fmt.Errorf("failed to marshal response: %w",err)
77+
}
78+
79+
returnmcp.NewToolResultText(string(r)),nil
80+
}
81+
}
82+
1683
// ListCommits creates a tool to get commits of a branch in a repository.
1784
funcListCommits(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
1885
returnmcp.NewTool("list_commits",

‎pkg/github/repositories_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,136 @@ func Test_CreateBranch(t *testing.T) {
475475
}
476476
}
477477

478+
funcTest_GetCommit(t*testing.T) {
479+
// Verify tool definition once
480+
mockClient:=github.NewClient(nil)
481+
tool,_:=GetCommit(stubGetClientFn(mockClient),translations.NullTranslationHelper)
482+
483+
assert.Equal(t,"get_commit",tool.Name)
484+
assert.NotEmpty(t,tool.Description)
485+
assert.Contains(t,tool.InputSchema.Properties,"owner")
486+
assert.Contains(t,tool.InputSchema.Properties,"repo")
487+
assert.Contains(t,tool.InputSchema.Properties,"sha")
488+
assert.ElementsMatch(t,tool.InputSchema.Required, []string{"owner","repo","sha"})
489+
490+
mockCommit:=&github.RepositoryCommit{
491+
SHA:github.Ptr("abc123def456"),
492+
Commit:&github.Commit{
493+
Message:github.Ptr("First commit"),
494+
Author:&github.CommitAuthor{
495+
Name:github.Ptr("Test User"),
496+
Email:github.Ptr("test@example.com"),
497+
Date:&github.Timestamp{Time:time.Now().Add(-48*time.Hour)},
498+
},
499+
},
500+
Author:&github.User{
501+
Login:github.Ptr("testuser"),
502+
},
503+
HTMLURL:github.Ptr("https://github.com/owner/repo/commit/abc123def456"),
504+
Stats:&github.CommitStats{
505+
Additions:github.Ptr(10),
506+
Deletions:github.Ptr(2),
507+
Total:github.Ptr(12),
508+
},
509+
Files: []*github.CommitFile{
510+
{
511+
Filename:github.Ptr("file1.go"),
512+
Status:github.Ptr("modified"),
513+
Additions:github.Ptr(10),
514+
Deletions:github.Ptr(2),
515+
Changes:github.Ptr(12),
516+
Patch:github.Ptr("@@ -1,2 +1,10 @@"),
517+
},
518+
},
519+
}
520+
// This one currently isn't defined in the mock package we're using.
521+
varmockEndpointPattern= mock.EndpointPattern{
522+
Pattern:"/repos/{owner}/{repo}/commits/{sha}",
523+
Method:"GET",
524+
}
525+
526+
tests:= []struct {
527+
namestring
528+
mockedClient*http.Client
529+
requestArgsmap[string]interface{}
530+
expectErrorbool
531+
expectedCommit*github.RepositoryCommit
532+
expectedErrMsgstring
533+
}{
534+
{
535+
name:"successful commit fetch",
536+
mockedClient:mock.NewMockedHTTPClient(
537+
mock.WithRequestMatchHandler(
538+
mockEndpointPattern,
539+
mockResponse(t,http.StatusOK,mockCommit),
540+
),
541+
),
542+
requestArgs:map[string]interface{}{
543+
"owner":"owner",
544+
"repo":"repo",
545+
"sha":"abc123def456",
546+
},
547+
expectError:false,
548+
expectedCommit:mockCommit,
549+
},
550+
{
551+
name:"commit fetch fails",
552+
mockedClient:mock.NewMockedHTTPClient(
553+
mock.WithRequestMatchHandler(
554+
mockEndpointPattern,
555+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
556+
w.WriteHeader(http.StatusNotFound)
557+
_,_=w.Write([]byte(`{"message": "Not Found"}`))
558+
}),
559+
),
560+
),
561+
requestArgs:map[string]interface{}{
562+
"owner":"owner",
563+
"repo":"repo",
564+
"sha":"nonexistent-sha",
565+
},
566+
expectError:true,
567+
expectedErrMsg:"failed to get commit",
568+
},
569+
}
570+
571+
for_,tc:=rangetests {
572+
t.Run(tc.name,func(t*testing.T) {
573+
// Setup client with mock
574+
client:=github.NewClient(tc.mockedClient)
575+
_,handler:=GetCommit(stubGetClientFn(client),translations.NullTranslationHelper)
576+
577+
// Create call request
578+
request:=createMCPRequest(tc.requestArgs)
579+
580+
// Call handler
581+
result,err:=handler(context.Background(),request)
582+
583+
// Verify results
584+
iftc.expectError {
585+
require.Error(t,err)
586+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
587+
return
588+
}
589+
590+
require.NoError(t,err)
591+
592+
// Parse the result and get the text content if no error
593+
textContent:=getTextResult(t,result)
594+
595+
// Unmarshal and verify the result
596+
varreturnedCommit github.RepositoryCommit
597+
err=json.Unmarshal([]byte(textContent.Text),&returnedCommit)
598+
require.NoError(t,err)
599+
600+
assert.Equal(t,*tc.expectedCommit.SHA,*returnedCommit.SHA)
601+
assert.Equal(t,*tc.expectedCommit.Commit.Message,*returnedCommit.Commit.Message)
602+
assert.Equal(t,*tc.expectedCommit.Author.Login,*returnedCommit.Author.Login)
603+
assert.Equal(t,*tc.expectedCommit.HTMLURL,*returnedCommit.HTMLURL)
604+
})
605+
}
606+
}
607+
478608
funcTest_ListCommits(t*testing.T) {
479609
// Verify tool definition once
480610
mockClient:=github.NewClient(nil)

‎pkg/github/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func NewServer(getClient GetClientFn, version string, readOnly bool, t translati
6161
// Add GitHub tools - Repositories
6262
s.AddTool(SearchRepositories(getClient,t))
6363
s.AddTool(GetFileContents(getClient,t))
64+
s.AddTool(GetCommit(getClient,t))
6465
s.AddTool(ListCommits(getClient,t))
6566
if!readOnly {
6667
s.AddTool(CreateOrUpdateFile(getClient,t))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp