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

Feat/list branches#204

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

Closed
Closed
Show file tree
Hide file tree
Changes fromall commits
Commits
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
85 changes: 62 additions & 23 deletionsREADME.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,9 +16,39 @@ automation and interaction capabilities for developers and tools.

1. To run the server in a container, you will need to have [Docker](https://www.docker.com/) installed.
2. [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
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)).


The MCP server requires specific permissions for different tools. Here are the required permissions for each tool:

### User Tools
- **get_me** - Get details of the authenticated user
- Required permissions: `read:user`

### Issues Tools
- **get_issue**, **get_issue_comments**, **list_issues** - Read issue data
- Required permissions: `repo` (for private repos) or no permissions (for public repos)

- **create_issue**, **add_issue_comment**, **update_issue** - Create/modify issues
- Required permissions: `repo` (for private repos) or `public_repo` (for public repos)

### Pull Request Tools
- **get_pull_request**, **list_pull_requests**, **get_pull_request_files**, **get_pull_request_status**, **get_pull_request_comments**, **get_pull_request_reviews** - Read PR data
- Required permissions: `repo` (for private repos) or no permissions (for public repos)

- **merge_pull_request**, **update_pull_request_branch**, **create_pull_request_review**, **create_pull_request** - Create/modify PRs
- Required permissions: `repo` (for private repos) or `public_repo` (for public repos)

### Repository Tools
- **search_repositories** - Search repositories
- Required permissions: No permissions required for public repos, `repo` for private repos

- **get_file_contents**, **list_commits**, **list_branches** - Read repository data
- Required permissions: `repo` (for private repos) or no permissions (for public repos)

- **create_or_update_file**, **push_files**, **create_repository** - Create/modify repository content
- Required permissions: `repo` (for private repos) or `public_repo` (for public repos)

### Search Tools
- **search_issues** - Search issues and pull requests
- Required permissions: No permissions required for public data, `repo` for private data

## Installation

Expand DownExpand Up@@ -144,23 +174,24 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description

- **get_me** - Get details of the authenticated user
- No parameters required
- Required permissions: `read:user`

### Issues

- **get_issue** - Gets the contents of an issue within a repository

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `issue_number`: Issue number (number, required)

- **get_issue_comments** - Get comments for a GitHub issue

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `issue_number`: Issue number (number, required)

- **create_issue** - Create a new issue in a GitHub repository

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `title`: Issue title (string, required)
Expand All@@ -169,14 +200,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `labels`: Labels to apply to this issue (string[], optional)

- **add_issue_comment** - Add a comment to an issue

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `issue_number`: Issue number (number, required)
- `body`: Comment text (string, required)

- **list_issues** - List and filter repository issues

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `state`: Filter by state ('open', 'closed', 'all') (string, optional)
Expand All@@ -188,7 +219,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `perPage`: Results per page (number, optional)

- **update_issue** - Update an existing issue in a GitHub repository

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `issue_number`: Issue number to update (number, required)
Expand All@@ -209,23 +240,25 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
### Pull Requests

- **get_pull_request** - Get details of a specific pull request

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `pullNumber`: Pull request number (number, required)

- **list_pull_requests** - List and filter repository pull requests

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `state`: PR state (string, optional)
- `sort`: Sort field (string, optional)
- `direction`: Sort direction (string, optional)
- `state`: Filter by state ('open', 'closed', 'all') (string, optional)
- `head`: Filter by head user/org and branch (string, optional)
- `base`: Filter by base branch (string, optional)
- `sort`: Sort by ('created', 'updated', 'popularity', 'long-running') (string, optional)
- `direction`: Sort direction ('asc', 'desc') (string, optional)
- `perPage`: Results per page (number, optional)
- `page`: Page number (number, optional)

- **merge_pull_request** - Merge a pull request

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `pullNumber`: Pull request number (number, required)
Expand All@@ -234,7 +267,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `merge_method`: Merge method (string, optional)

- **get_pull_request_files** - Get the list of files changed in a pull request

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `pullNumber`: Pull request number (number, required)
Expand DownExpand Up@@ -287,10 +320,10 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `draft`: Create as draft PR (boolean, optional)
- `maintainer_can_modify`: Allow maintainer edits (boolean, optional)

###Repositories
###Repository

- **create_or_update_file** - Create or update a single file in a repository

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `path`: File path (string, required)
Expand All@@ -300,34 +333,34 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `sha`: File SHA if updating (string, optional)

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

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `branch`: Branch to push to (string, required)
- `files`: Files to push, each with path and content (array, required)
- `message`: Commit message (string, required)

- **search_repositories** - Search for GitHub repositories

- Required permissions: No permissions required for public repos, `repo` for private repos
- `query`: Search query (string, required)
- `sort`: Sort field (string, optional)
- `order`: Sort order (string, optional)
- `page`: Page number (number, optional)
- `perPage`: Results per page (number, optional)

- **create_repository** - Create a new GitHub repository

- Required permissions: `repo` (private repos) or `public_repo` (public repos)
- `name`: Repository name (string, required)
- `description`: Repository description (string, optional)
- `private`: Whether the repository is private (boolean, optional)
- `autoInit`: Auto-initialize with README (boolean, optional)

- **get_file_contents** - Get contents of a file or directory

- Required permissions: `repo` (private repos) or none (public repos)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `path`: File path (string, required)
- `ref`: Git reference (string, optional)
- `ref`: Git reference (branch, tag, commit) (string, optional)

- **fork_repository** - Fork a repository

Expand All@@ -350,6 +383,12 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
- `page`: Page number (number, optional)
- `perPage`: Results per page (number, 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)

### Search

- **search_code** - Search for code across GitHub repositories
Expand Down
52 changes: 52 additions & 0 deletionspkg/github/repositories.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -600,3 +600,55 @@ func pushFiles(client *github.Client, t translations.TranslationHelperFunc) (too
return mcp.NewToolResultText(string(r)), nil
}
}

// ListBranches creates a tool to list branches in a repository.
func ListBranches(client *github.Client, 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.Description("Repository owner"),
mcp.Required(),
),
mcp.WithString("repo",
mcp.Description("Repository name"),
mcp.Required(),
),
withPagination(),
),
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := requiredParam[string](request, "owner")
if err != nil {
return nil, err
}

repo, err := requiredParam[string](request, "repo")
if err != nil {
return nil, err
}

pagination, err := optionalPaginationParams(request)
if err != nil {
return nil, err
}

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

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() }()

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

return mcp.NewToolResultText(string(r)), nil
}
}
115 changes: 115 additions & 0 deletionspkg/github/repositories_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1293,3 +1293,118 @@ func Test_PushFiles(t *testing.T) {
})
}
}

func Test_ListBranches(t *testing.T) {
// Verify tool definition once
mockClient := github.NewClient(nil)
tool, _ := listBranches(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")},
},
}

// Define test cases
tests := []struct {
name string
mockedClient *http.Client
requestArgs map[string]interface{}
expectError bool
expectedErrMsg string
}{
{
name: "success",
mockedClient: mock.NewMockedHTTPClient(
mock.WithRequestMatch(
mock.GetReposBranchesByOwnerByRepo,
mockBranches,
),
),
requestArgs: map[string]interface{}{
"owner": "owner",
"repo": "repo",
},
expectError: false,
},
{
name: "missing owner",
mockedClient: mock.NewMockedHTTPClient(),
requestArgs: map[string]interface{}{
"repo": "repo",
},
expectError: false,
expectedErrMsg: "missing required parameter: owner",
},
{
name: "missing repo",
mockedClient: mock.NewMockedHTTPClient(),
requestArgs: map[string]interface{}{
"owner": "owner",
},
expectError: false,
expectedErrMsg: "missing required parameter: repo",
},
{
name: "repository not found",
mockedClient: mock.NewMockedHTTPClient(
mock.WithRequestMatchHandler(
mock.GetReposBranchesByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
}),
),
),
requestArgs: map[string]interface{}{
"owner": "owner",
"repo": "nonexistent-repo",
},
expectError: true,
expectedErrMsg: "failed to list branches",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := github.NewClient(tt.mockedClient)
_, handler := listBranches(client, translations.NullTranslationHelper)

// Create call request using helper function
request := createMCPRequest(tt.requestArgs)

// Call handler
result, err := handler(context.Background(), request)

if tt.expectError {
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErrMsg)
} else {
if tt.expectedErrMsg != "" {
assert.NotNil(t, result)
textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, tt.expectedErrMsg)
} else {
assert.NoError(t, err)
assert.NotNil(t, result)
textContent := getTextResult(t, result)
assert.NotEmpty(t, textContent.Text)
}
}
})
}
}
1 change: 1 addition & 0 deletionspkg/github/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -59,6 +59,7 @@ func NewServer(client *github.Client, version string, readOnly bool, t translati
s.AddTool(searchRepositories(client, t))
s.AddTool(getFileContents(client, t))
s.AddTool(listCommits(client, t))
s.AddTool(listBranches(client, t))
if !readOnly {
s.AddTool(createOrUpdateFile(client, t))
s.AddTool(createRepository(client, t))
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp