8000 Merge pull request #1 from github/juruen/moar-tools · github/github-mcp-server@cc6516c · GitHub
[go: up one dir, main page]

Skip to content

Commit cc6516c

Browse files
authored
Merge pull request #1 from github/juruen/moar-tools
implement more tools
2 parents 901b16a + 22e58fb commit cc6516c

File tree

6 files changed

+1452
-53
lines changed

6 files changed

+1452
-53
lines changed

README.md

Lines changed: 135 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,141 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
1010

1111
## Tools
1212

13-
1. `get_me`
14-
- Return information about the authenticated user
15-
2. `get_issue`
16-
- Get the contents of an issue within a repository.
17-
- Inputs
18-
- `owner` (string): Repository owner
19-
- `repo` (string): Repository name
20-
- `issue_number` (number): Issue number to retrieve
21-
- Returns: Github Issue object & details
13+
### Users
14+
- **get_me** - Get details of the authenticated user
15+
- No parameters required
16+
17+
### Issues
18+
- **get_issue** - Gets the contents of an issue within a repository
19+
- `owner`: Repository owner (string, required)
20+
- `repo`: Repository name (string, required)
21+
- `issue_number`: Issue number (number, required)
22+
23+
- **add_issue_comment** - Add a comment to an issue
24+
- `owner`: Repository owner (string, required)
25+
- `repo`: Repository name (string, required)
26+
- `issue_number`: Issue number (number, required)
27+
- `body`: Comment text (string, required)
28+
29+
- **search_issues** - Search for issues and pull requests
30+
- `query`: Search query (string, required)
31+
- `sort`: Sort field (string, optional)
32+
- `order`: Sort order (string, optional)
33+
- `page`: Page number (number, optional)
34+
- `per_page`: Results per page (number, optional)
35+
36+
### Pull Requests
37+
- **get_pull_request** - Get details of a specific pull request
38+
- `owner`: Repository owner (string, required)
39+
- `repo`: Repository name (string, required)
40+
- `pull_number`: Pull request number (number, required)
41+
42+
- **list_pull_requests** - List and filter repository pull requests
43+
- `owner`: Repository owner (string, required)
44+
- `repo`: Repository name (string, required)
45+
- `state`: PR state (string, optional)
46+
- 57A6 `sort`: Sort field (string, optional)
47+
- `direction`: Sort direction (string, optional)
48+
- `per_page`: Results per page (number, optional)
49+
- `page`: Page number (number, optional)
50+
51+
- **merge_pull_request** - Merge a pull request
52+
- `owner`: Repository owner (string, required)
53+
- `repo`: Repository name (string, required)
54+
- `pull_number`: Pull request number (number, required)
55+
- `commit_title`: Title for the merge commit (string, optional)
56+
- `commit_message`: Message for the merge commit (string, optional)
57+
- `merge_method`: Merge method (string, optional)
58+
59+
- **get_pull_request_files** - Get the list of files changed in a pull request
60+
- `owner`: Repository owner (string, required)
61+
- `repo`: Repository name (string, required)
62+
- `pull_number`: Pull request number (number, required)
63+
64+
- **get_pull_request_status** - Get the combined status of all status checks for a pull request
65+
- `owner`: Repository owner (string, required)
66+
- `repo`: Repository name (string, required)
67+
- `pull_number`: Pull request number (number, required)
68+
69+
- **update_pull_request_branch** - Update a pull request branch with the latest changes from the base branch
70+
- `owner`: Repository owner (string, required)
71+
- `repo`: Repository name (string, required)
72+
- `pull_number`: Pull request number (number, required)
73+
- `expected_head_sha`: The expected SHA of the pull request's HEAD ref (string, optional)
74+
75+
- **get_pull_request_comments** - Get the review comments on a pull request
76+
- `owner`: Repository owner (string, required)
77+
- `repo`: Repository name (string, required)
78+
- `pull_number`: Pull request number (number, required)
79+
80+
- **get_pull_request_reviews** - Get the reviews on a pull request
81+
- `owner`: Repository owner (string, required)
82+
- `repo`: Repository name (string, required)
83+
- `pull_number`: Pull request number (number, required)
84+
85+
### Repositories
86+
- **create_or_update_file** - Create or update a single file in a repository
87+
- `owner`: Repository owner (string, required)
88+
- `repo`: Repository name (string, required)
89+
- `path`: File path (string, required)
90+
- `message`: Commit message (string, required)
91+
- `content`: File content (string, required)
92+
- `branch`: Branch name (string, optional)
93+
- `sha`: File SHA if updating (string, optional)
94+
95+
- **search_repositories** - Search for GitHub repositories
96+
- `query`: Search query (string, required)
97+
- `sort`: Sort field (string, optional)
98+
- `order`: Sort order (string, optional)
99+
- `page`: Page number (number, optional)
100+
- `per_page`: Results per page (number, optional)
101+
102+
- **create_repository** - Create a new GitHub repository
103+
- `name`: Repository name (string, required)
104+
- `description`: Repository description (string, optional)
105+
- `private`: Whether the repository is private (boolean, optional)
106+
- `auto_init`: Auto-initialize with README (boolean, optional)
107+
- `gitignore_template`: Gitignore template name (string, optional)
108+
109+
- **get_file_contents** - Get contents of a file or directory
110+
- `owner`: Repository owner (string, required)
111+
- `repo`: Repository name (string, required)
112+
- `path`: File path (string, required)
113+
- `ref`: Git reference (string, optional)
114+
115+
- **fork_repository** - Fork a repository
116+
- `owner`: Repository owner (string, required)
117+
- `repo`: Repository name (string, required)
118+
- `organization`: Target organization name (string, optional)
119+
120+
- **create_branch** - Create a new branch
121+
- `owner`: Repository owner (string, required)
122+
- `repo`: Repository name (string, required)
123+
- `branch`: New branch name (string, required)
124+
- `sha`: SHA to create branch from (string, required)
125+
126+
- **list_commits** - Gets commits of a branch in a repository
127+
- `owner`: Repository owner (string, required)
128+
- `repo`: Repository name (string, required)
129+
- `sha`: Branch name, tag, or commit SHA (string, optional)
130+
- `path`: Only commits containing this file path (string, optional)
131+
- `page`: Page number (number, optional)
132+
- `per_page`: Results per page (number, optional)
133+
134+
### Search
135+
- **search_code** - Search for code across GitHub repositories
136+
- `query`: Search query (string, required)
137+
- `sort`: Sort field (string, optional)
138+
- `order`: Sort order (string, optional)
139+
- `page`: Page number (number, optional)
140+
- `per_page`: Results per page (number, optional)
141+
142+
- **search_users** - Search for GitHub users
143+
- `query`: Search query (string, required)
144+
- `sort`: Sort field (string, optional)
145+
- `order`: Sort order (string, optional)
146+
- `page`: Page number (number, optional)
147+
- `per_page`: Results per page (number, optional)
22148

23149
## Standard input/output server
24150

pkg/github/issues.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
9+
"github.com/google/go-github/v69/github"
10+
"github.com/mark3labs/mcp-go/mcp"
11+
"github.com/mark3labs/mcp-go/server"
12+
)
13+
14+
// getIssue creates a tool to get details of a specific issue in a GitHub repository.
15+
func getIssue(client *github.Client) (tool mcp.Tool, handler server.ToolHandlerFunc) {
16+
return mcp.NewTool("get_issue",
17+
mcp.WithDescription("Get details of a specific issue in a GitHub repository."),
18+
mcp.WithString("owner",
19+
mcp.Required(),
20+
mcp.Description("The owner of the repository."),
21+
),
22+
mcp.WithString("repo",
23+
mcp.Required(),
24+
mcp.Description("The name of the repository."),
25+
),
26+
mcp.WithNumber("issue_number",
27+
mcp.Required(),
28+
mcp.Description("The number of the issue."),
29+
),
30+
),
31+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
32+
owner := request.Params.Arguments["owner"].(string)
33+
repo := request.Params.Arguments["repo"].(string)
34+
issueNumber := int(request.Params.Arguments["issue_number"].(float64))
35+
36+
issue, resp, err := client.Issues.Get(ctx, owner, repo, issueNumber)
37+
if err != nil {
38+
return nil, fmt.Errorf("failed to get issue: %w", err)
39+
}
40+
defer func() { _ = resp.Body.Close() }()
41+
42+
if resp.StatusCode != 200 {
43+
body, err := io.ReadAll(resp.Body)
44+
if err != nil {
45+
return nil, fmt.Errorf("failed to read response body: %w", err)
46+
}
47+
return mcp.NewToolResultError(fmt.Sprintf("failed to get issue: %s", string(body))), nil
48+
}
49+
50+
r, err := json.Marshal(issue)
51+
if err != nil {
52+
return nil, fmt.Errorf("failed to marshal issue: %w", err)
53+
}
54+
55+
return mcp.NewToolResultText(string(r)), nil
56+
}
57+
}
58+
59+
// addIssueComment creates a tool to add a comment to an issue.
60+
func addIssueComment(client *github.Client) (tool mcp.Tool, handler server.ToolHandlerFunc) {
61+
return mcp.NewTool("add_issue_comment",
62+
mcp.WithDescription("Add a comment to an issue"),
63+
mcp.WithString("owner",
64+
mcp.Required(),
65+
mcp.Description("Repository owner"),
66+
),
67+
mcp.WithString("repo",
68+
mcp.Requir F438 ed(),
69+
mcp.Description("Repository name"),
70+
),
71+
mcp.WithNumber("issue_number",
72+
mcp.Required(),
73+
mcp.Description("Issue number to comment on"),
74+
),
75+
mcp.WithString("body",
76+
mcp.Required(),
77+
mcp.Description("Comment text"),
78+
),
79+
),
80+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
81+
owner := request.Params.Arguments["owner"].(string)
82+
repo := request.Params.Arguments["repo"].(string)
83+
issueNumber := int(request.Params.Arguments["issue_number"].(float64))
84+
body := request.Params.Arguments["body"].(string)
85+
86+
comment := &github.IssueComment{
87+
Body: github.Ptr(body),
88+
}
89+
90+
createdComment, resp, err := client.Issues.CreateComment(ctx, owner, repo, issueNumber, comment)
91+
if err != nil {
92+
return nil, fmt.Errorf("failed to create comment: %w", err)
93+
}
94+
defer func() { _ = resp.Body.Close() }()
95+
96+
if resp.StatusCode != 201 {
97+
body, err := io.ReadAll(resp.Body)
98+
if err != nil {
99+
return nil, fmt.Errorf("failed to read response body: %w", err)
100+
}
101+
return mcp.NewToolResultError(fmt.Sprintf("failed to create comment: %s", string(body))), nil
102+
}
103+
104+
r, err := json.Marshal(createdComment)
105+
if err != nil {
106+
return nil, fmt.Errorf("failed to marshal response: %w", err)
107+
}
108+
109+
return mcp.NewToolResultText(string(r)), nil
110+
}
111+
}
112+
113+
// searchIssues creates a tool to search for issues and pull requests.
114+
func searchIssues(client *github.Client) (tool mcp.Tool, handler server.ToolHandlerFunc) {
115+
return mcp.NewTool("search_issues",
116+
mcp.WithDescription("Search for issues and pull requests"),
117+
mcp.WithString("q",
118+
mcp.Required(),
119+
mcp.Description("Search query using GitHub issues search syntax"),
120+
),
121+
mcp.WithString("sort",
122+
mcp.Description("Sort field (comments, reactions, created, etc.)"),
123+
),
124+
mcp.WithString("order",
125+
mcp.Description("Sort order ('asc' or 'desc')"),
126+
),
127+
mcp.WithNumber("per_page",
128+
mcp.Description("Results per page (max 100)"),
129+
),
130+
mcp.WithNumber("page",
131+
mcp.Description("Page number"),
132+
),
133+
),
134+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
135+
query := request.Params.Arguments["q"].(string)
136+
sort := ""
137+
if s, ok := request.Params.Arguments["sort"].(string); ok {
138+
sort = s
139+
}
140+
order := ""
141+
if o, ok := request.Params.Arguments["order"].(string); ok {
142+
order = o
143+
}
144+
perPage := 30
145+
if pp, ok := request.Params.Arguments["per_page"].(float64); ok {
146+
perPage = int(pp)
147+
}
148+
page := 1
149+
if p, ok := request.Params.Arguments["page"].(float64); ok {
150+
page = int(p)
151+
}
152+
153+
opts := &github.SearchOptions{
154+
Sort: sort,
155+
Order: order,
156+
ListOptions: github.ListOptions{
157+
PerPage: perPage,
158+
Page: page,
159+
},
160+
}
161+
162+
result, resp, err := client.Search.Issues(ctx, query, opts)
163+
if err != nil {
164+
return nil, fmt.Errorf("failed to search issues: %w", err)
165+
}
166+
defer func() { _ = resp.Body.Close() }()
167+
168+
if resp.StatusCode != 200 {
169+
body, err := io.ReadAll(resp.Body)
170+
if err != nil {
171+
return nil, fmt.Errorf("failed to read response body: %w", err)
172+
}
173+
return mcp.NewToolResultError(fmt.Sprintf("failed to search issues: %s", string(body))), nil
174+
}
175+
176+
r, err := json.Marshal(result)
177+
if err != nil {
178+
return nil, fmt.Errorf("failed to marshal response: %w", err)
179+
}
180+
181+
return mcp.NewToolResultText(string(r)), nil
182+
}
183+
}

0 commit comments

Comments
 (0)
0