Skip to content

Commit bee75ab

Browse files
authored
Merge branch 'main' into main
2 parents 8e72b1b + 7ab5d96 commit bee75ab

23 files changed

+780
-331
lines changed

.github/workflows/code-scanning.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: "CodeQL"
2+
run-name: ${{ github.event.inputs.code_scanning_run_name }}
3+
on: [push, pull_request, workflow_dispatch]
4+
5+
concurrency:
6+
group: ${{ github.workflow }}-${{ github.ref }}
7+
cancel-in-progress: true
8+
9+
env:
10+
CODE_SCANNING_REF: ${{ github.event.inputs.code_scanning_ref }}
11+
CODE_SCANNING_BASE_BRANCH: ${{ github.event.inputs.code_scanning_base_branch }}
12+
CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH: ${{ github.event.inputs.code_scanning_is_analyzing_default_branch }}
13+
14+
jobs:
15+
analyze:
16+
name: Analyze (${{ matrix.language }})
17+
runs-on: ${{ fromJSON(matrix.runner) }}
18+
permissions:
19+
actions: read
20+
contents: read
21+
packages: read
22+
security-events: write
23+
continue-on-error: false
24+
strategy:
25+
fail-fast: false
26+
matrix:
27+
include:
28+
- language: actions
29+
category: /language:actions
30+
build-mode: none
31+
runner: '["ubuntu-22.04"]'
32+
- language: go
33+
category: /language:go
34+
build-mode: autobuild
35+
runner: '["ubuntu-22.04"]'
36+
steps:
37+
- name: Checkout repository
38+
uses: actions/checkout@v4
39+
40+
- name: Initialize CodeQL
41+
uses: github/codeql-action/init@v3
42+
with:
43+
languages: ${{ matrix.language }}
44+
build-mode: ${{ matrix.build-mode }}
45+
dependency-caching: ${{ runner.environment == 'github-hosted' }}
46+
queries: "" # Default query suite
47+
packs: github/ccr-${{ matrix.language }}-queries
48+
config: |
49+
default-setup:
50+
org:
51+
model-packs: [ ${{ github.event.inputs.code_scanning_codeql_packs }} ]
52+
threat-models: [ ]
53+
- name: Setup proxy for registries
54+
id: proxy
55+
uses: github/codeql-action/start-proxy@v3
56+
with:
57+
registries_credentials: ${{ secrets.GITHUB_REGISTRIES_PROXY }}
58+
language: ${{ matrix.language }}
59+
60+
- name: Configure
61+
uses: github/codeql-action/resolve-environment@v3
62+
id: resolve-environment
63+
with:
64+
language: ${{ matrix.language }}
65+
- name: Setup Go
66+
uses: actions/setup-go@v5
67+
if: matrix.language == 'go' && fromJSON(steps.resolve-environment.outputs.environment).configuration.go.version
68+
with:
69+
go-version: ${{ fromJSON(steps.resolve-environment.outputs.environment).configuration.go.version }}
70+
cache: false
71+
72+
- name: Autobuild
73+
uses: github/codeql-action/autobuild@v3
74+
75+
- name: Perform CodeQL Analysis
76+
uses: github/codeql-action/analyze@v3
77+
env:
78+
CODEQL_PROXY_HOST: ${{ steps.proxy.outputs.proxy_host }}
79+
CODEQL_PROXY_PORT: ${{ steps.proxy.outputs.proxy_port }}
80+
CODEQL_PROXY_CA_CERTIFICATE: ${{ steps.proxy.outputs.proxy_ca_certificate }}
81+
with:
82+
category: ${{ matrix.category }}

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
153153
- `repo`: Repository name (string, required)
154154
- `issue_number`: Issue number (number, required)
155155

156+
- **get_issue_comments** - Get comments for a GitHub issue
157+
158+
- `owner`: Repository owner (string, required)
159+
- `repo`: Repository name (string, required)
160+
- `issue_number`: Issue number (number, required)
161+
156162
- **create_issue** - Create a new issue in a GitHub repository
157163

158164
- `owner`: Repository owner (string, required)
@@ -198,7 +204,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
198204
- `sort`: Sort field (string, optional)
199205
- `order`: Sort order (string, optional)
200206
- `page`: Page number (number, optional)
201-
- `per_page`: Results per page (number, optional)
207+
- `perPage`: Results per page (number, optional)
202208

203209
### Pull Requests
204210

@@ -266,7 +272,9 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
266272
- `body`: Review comment text (string, optional)
267273
- `event`: Review action ('APPROVE', 'REQUEST_CHANGES', 'COMMENT') (string, required)
268274
- `commitId`: SHA of commit to review (string, optional)
269-
- `comments`: Line-specific comments array of objects, each object with path (string), position (number), and body (string) (array, optional)
275+
- `comments`: Line-specific comments array of objects to place comments on pull request changes (array, optional)
276+
- For inline comments: provide `path`, `position` (or `line`), and `body`
277+
- For multi-line comments: provide `path`, `start_line`, `line`, optional `side`/`start_side`, and `body`
270278

271279
- **create_pull_request** - Create a new pull request
272280

cmd/github-mcp-server/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func runStdioServer(cfg runConfig) error {
158158
t, dumpTranslations := translations.TranslationHelper()
159159

160160
// Create
161-
ghServer := github.NewServer(ghClient, cfg.readOnly, t)
161+
ghServer := github.NewServer(ghClient, version, cfg.readOnly, t)
162162
stdioServer := server.NewStdioServer(ghServer)
163163

164164
stdLogger := stdlog.New(cfg.logger.Writer(), "stdioserver", 0)

cmd/mcpcurl/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Available Commands:
5050
fork_repository Fork a GitHub repository to your account or specified organization
5151
get_file_contents Get the contents of a file or directory from a GitHub repository
5252
get_issue Get details of a specific issue in a GitHub repository.
53+
get_issue_comments Get comments for a GitHub issue
5354
list_commits Get list of commits of a branch in a GitHub repository
5455
list_issues List issues in a GitHub repository with filtering options
5556
push_files Push multiple files to a GitHub repository in a single commit

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module github.com/github/github-mcp-server
33
go 1.23.7
44

55
require (
6-
github.com/aws/smithy-go v1.22.3
76
github.com/docker/docker v28.0.4+incompatible
87
github.com/google/go-cmp v0.7.0
98
github.com/google/go-github/v69 v69.2.0

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
22
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
33
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
44
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
5-
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
6-
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
75
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
86
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
97
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=

pkg/github/issues.go

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,7 @@ func searchIssues(client *github.Client, t translations.TranslationHelperFunc) (
162162
mcp.Description("Sort order ('asc' or 'desc')"),
163163
mcp.Enum("asc", "desc"),
164164
),
165-
mcp.WithNumber("per_page",
166-
mcp.Description("Results per page (max 100)"),
167-
mcp.Min(1),
168-
mcp.Max(100),
169-
),
170-
mcp.WithNumber("page",
171-
mcp.Description("Page number"),
172-
mcp.Min(1),
173-
),
165+
withPagination(),
174166
),
175167
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
176168
query, err := requiredParam[string](request, "q")
@@ -185,11 +177,7 @@ func searchIssues(client *github.Client, t translations.TranslationHelperFunc) (
185177
if err != nil {
186178
return mcp.NewToolResultError(err.Error()), nil
187179
}
188-
perPage, err := optionalIntParamWithDefault(request, "per_page", 30)
189-
if err != nil {
190-
return mcp.NewToolResultError(err.Error()), nil
191-
}
192-
page, err := optionalIntParamWithDefault(request, "page", 1)
180+
pagination, err := optionalPaginationParams(request)
193181
if err != nil {
194182
return mcp.NewToolResultError(err.Error()), nil
195183
}
@@ -198,8 +186,8 @@ func searchIssues(client *github.Client, t translations.TranslationHelperFunc) (
198186
Sort: sort,
199187
Order: order,
200188
ListOptions: github.ListOptions{
201-
PerPage: perPage,
202-
Page: page,
189+
PerPage: pagination.perPage,
190+
Page: pagination.page,
203191
},
204192
}
205193

@@ -375,12 +363,7 @@ func listIssues(client *github.Client, t translations.TranslationHelperFunc) (to
375363
mcp.WithString("since",
376364
mcp.Description("Filter by date (ISO 8601 timestamp)"),
377365
),
378-
mcp.WithNumber("page",
379-
mcp.Description("Page number"),
380-
),
381-
mcp.WithNumber("per_page",
382-
mcp.Description("Results per page"),
383-
),
366+
withPagination(),
384367
),
385368
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
386369
owner, err := requiredParam[string](request, "owner")
@@ -432,7 +415,7 @@ func listIssues(client *github.Client, t translations.TranslationHelperFunc) (to
432415
opts.Page = int(page)
433416
}
434417

435-
if perPage, ok := request.Params.Arguments["per_page"].(float64); ok {
418+
if perPage, ok := request.Params.Arguments["perPage"].(float64); ok {
436419
opts.PerPage = int(perPage)
437420
}
438421

@@ -597,6 +580,81 @@ func updateIssue(client *github.Client, t translations.TranslationHelperFunc) (t
597580
}
598581
}
599582

583+
// getIssueComments creates a tool to get comments for a GitHub issue.
584+
func getIssueComments(client *github.Client, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
585+
return mcp.NewTool("get_issue_comments",
586+
mcp.WithDescription(t("TOOL_GET_ISSUE_COMMENTS_DESCRIPTION", "Get comments for a GitHub issue")),
587+
mcp.WithString("owner",
588+
mcp.Required(),
589+
mcp.Description("Repository owner"),
590+
),
591+
mcp.WithString("repo",
592+
mcp.Required(),
593+
mcp.Description("Repository name"),
594+
),
595+
mcp.WithNumber("issue_number",
596+
mcp.Required(),
597+
mcp.Description("Issue number"),
598+
),
599+
mcp.WithNumber("page",
600+
mcp.Description("Page number"),
601+
),
602+
mcp.WithNumber("per_page",
603+
mcp.Description("Number of records per page"),
604+
),
605+
),
606+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
607+
owner, err := requiredParam[string](request, "owner")
608+
if err != nil {
609+
return mcp.NewToolResultError(err.Error()), nil
610+
}
611+
repo, err := requiredParam[string](request, "repo")
612+
if err != nil {
613+
return mcp.NewToolResultError(err.Error()), nil
614+
}
615+
issueNumber, err := requiredInt(request, "issue_number")
616+
if err != nil {
617+
return mcp.NewToolResultError(err.Error()), nil
618+
}
619+
page, err := optionalIntParamWithDefault(request, "page", 1)
620+
if err != nil {
621+
return mcp.NewToolResultError(err.Error()), nil
622+
}
623+
perPage, err := optionalIntParamWithDefault(request, "per_page", 30)
624+
if err != nil {
625+
return mcp.NewToolResultError(err.Error()), nil
626+
}
627+
628+
opts := &github.IssueListCommentsOptions{
629+
ListOptions: github.ListOptions{
630+
Page: page,
631+
PerPage: perPage,
632+
},
633+
}
634+
635+
comments, resp, err := client.Issues.ListComments(ctx, owner, repo, issueNumber, opts)
636+
if err != nil {
637+
return nil, fmt.Errorf("failed to get issue comments: %w", err)
638+
}
639+
defer func() { _ = resp.Body.Close() }()
640+
641+
if resp.StatusCode != http.StatusOK {
642+
body, err := io.ReadAll(resp.Body)
643+
if err != nil {
644+
return nil, fmt.Errorf("failed to read response body: %w", err)
645+
}
646+
return mcp.NewToolResultError(fmt.Sprintf("failed to get issue comments: %s", string(body))), nil
647+
}
648+
649+
r, err := json.Marshal(comments)
650+
if err != nil {
651+
return nil, fmt.Errorf("failed to marshal response: %w", err)
652+
}
653+
654+
return mcp.NewToolResultText(string(r)), nil
655+
}
656+
}
657+
600658
// parseISOTimestamp parses an ISO 8601 timestamp string into a time.Time object.
601659
// Returns the parsed time or an error if parsing fails.
602660
// Example formats supported: "2023-01-15T14:30:00Z", "2023-01-15"

0 commit comments

Comments
 (0)