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

Add ability to view branches for a repo #141#205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
juruen merged 10 commits intogithub:mainfromaryasoni98:issues-141
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
10 commits
Select commitHold shift + click to select a range
69e37b5
Add ability to view branches for a repo #141
aryasoni98Apr 9, 2025
f8ff466
Update ListBranches to use GetClientFn and resolve merge conflicts
aryasoni98Apr 10, 2025
629922e
fix: update ListBranches test to use InputSchema and correct translat…
aryasoni98Apr 10, 2025
64cde12
fix: update ListBranches test to use InputSchema and correct translat…
aryasoni98Apr 10, 2025
b274df9
fix: update ListBranches test to handle errors in tool result
aryasoni98Apr 10, 2025
99060d7
fix: replace deprecated github.String with github.Ptr
aryasoni98Apr 10, 2025
ff13c14
Merge branch 'main' into issues-141
aryasoni98Apr 11, 2025
3e52cc6
Merge branch 'main' of github.com:aryasoni98/github-mcp-server into i…
aryasoni98Apr 11, 2025
266677d
docs: add list_branches tool documentation to README
aryasoni98Apr 11, 2025
f04c46b
Merge branch 'issues-141' of github.com:aryasoni98/github-mcp-server …
aryasoni98Apr 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletionsREADME.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -311,6 +311,13 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `branch`: Branch name (string, optional)
- `sha`: File SHA if updating (string, optional)

- **list_branches** - List branches in a GitHub repository

- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `page`: Page number (number, optional)
- `perPage`: Results per page (number, optional)

- **push_files** - Push multiple files in a single commit

- `owner`: Repository owner (string, required)
Expand Down
63 changes: 63 additions & 0 deletionspkg/github/repositories.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -150,6 +150,69 @@ func ListCommits(getClient GetClientFn, t translations.TranslationHelperFunc) (t
}
}

// ListBranches creates a tool to list branches in a GitHub repository.
func ListBranches(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
return mcp.NewTool("list_branches",
mcp.WithDescription(t("TOOL_LIST_BRANCHES_DESCRIPTION", "List branches in a GitHub repository")),
mcp.WithString("owner",
mcp.Required(),
mcp.Description("Repository owner"),
),
mcp.WithString("repo",
mcp.Required(),
mcp.Description("Repository name"),
),
WithPagination(),
),
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := requiredParam[string](request, "owner")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
repo, err := requiredParam[string](request, "repo")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
pagination, err := OptionalPaginationParams(request)
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}

opts := &github.BranchListOptions{
ListOptions: github.ListOptions{
Page: pagination.page,
PerPage: pagination.perPage,
},
}

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

branches, resp, err := client.Repositories.ListBranches(ctx, owner, repo, opts)
if err != nil {
return nil, fmt.Errorf("failed to list branches: %w", err)
}
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
return mcp.NewToolResultError(fmt.Sprintf("failed to list branches: %s", string(body))), nil
}

r, err := json.Marshal(branches)
if err != nil {
return nil, fmt.Errorf("failed to marshal response: %w", err)
}

return mcp.NewToolResultText(string(r)), nil
}
}

// CreateOrUpdateFile creates a tool to create or update a file in a GitHub repository.
func CreateOrUpdateFile(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
return mcp.NewTool("create_or_update_file",
Expand Down
110 changes: 110 additions & 0 deletionspkg/github/repositories_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1423,3 +1423,113 @@ func Test_PushFiles(t *testing.T) {
})
}
}

func Test_ListBranches(t *testing.T) {
// Verify tool definition once
mockClient := github.NewClient(nil)
tool, _ := ListBranches(stubGetClientFn(mockClient), translations.NullTranslationHelper)

assert.Equal(t, "list_branches", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "page")
assert.Contains(t, tool.InputSchema.Properties, "perPage")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})

// Setup mock branches for success case
mockBranches := []*github.Branch{
{
Name: github.Ptr("main"),
Commit: &github.RepositoryCommit{SHA: github.Ptr("abc123")},
},
{
Name: github.Ptr("develop"),
Commit: &github.RepositoryCommit{SHA: github.Ptr("def456")},
},
}

// Test cases
tests := []struct {
name string
args map[string]interface{}
mockResponses []mock.MockBackendOption
wantErr bool
errContains string
}{
{
name: "success",
args: map[string]interface{}{
"owner": "owner",
"repo": "repo",
"page": float64(2),
},
mockResponses: []mock.MockBackendOption{
mock.WithRequestMatch(
mock.GetReposBranchesByOwnerByRepo,
mockBranches,
),
},
wantErr: false,
},
{
name: "missing owner",
args: map[string]interface{}{
"repo": "repo",
},
mockResponses: []mock.MockBackendOption{},
wantErr: false,
errContains: "missing required parameter: owner",
},
{
name: "missing repo",
args: map[string]interface{}{
"owner": "owner",
},
mockResponses: []mock.MockBackendOption{},
wantErr: false,
errContains: "missing required parameter: repo",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create mock client
mockClient := github.NewClient(mock.NewMockedHTTPClient(tt.mockResponses...))
_, handler := ListBranches(stubGetClientFn(mockClient), translations.NullTranslationHelper)

// Create request
request := createMCPRequest(tt.args)

// Call handler
result, err := handler(context.Background(), request)
if tt.wantErr {
require.Error(t, err)
if tt.errContains != "" {
assert.Contains(t, err.Error(), tt.errContains)
}
return
}

require.NoError(t, err)
require.NotNil(t, result)

if tt.errContains != "" {
textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, tt.errContains)
return
}

textContent := getTextResult(t, result)
require.NotEmpty(t, textContent.Text)

// Verify response
var branches []*github.Branch
err = json.Unmarshal([]byte(textContent.Text), &branches)
require.NoError(t, err)
assert.Len(t, branches, 2)
assert.Equal(t, "main", *branches[0].Name)
assert.Equal(t, "develop", *branches[1].Name)
})
}
}
1 change: 1 addition & 0 deletionspkg/github/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,7 @@ func NewServer(getClient GetClientFn, version string, readOnly bool, t translati
s.AddTool(GetFileContents(getClient, t))
s.AddTool(GetCommit(getClient, t))
s.AddTool(ListCommits(getClient, t))
s.AddTool(ListBranches(getClient, t))
if !readOnly {
s.AddTool(CreateOrUpdateFile(getClient, t))
s.AddTool(CreateRepository(getClient, t))
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp