Skip to content

Commit 5c20811

Browse files
Merge branch 'main' into flip-actions-tool-ff-to-default
2 parents eb8da41 + d4da526 commit 5c20811

20 files changed

+506
-63
lines changed

.github/pull_request_template.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ Fixes #
3333
- [ ] Auth / permissions considered
3434
- [ ] Data exposure, filtering, or token/size limits considered
3535

36+
## Tool renaming
37+
- [ ] I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
38+
- [ ] I have added the new tool aliases in `deprecated_tool_aliases.go`
39+
- [ ] I am not renaming tools as part of this PR
40+
41+
Note: if you're renaming tools, you *must* add the tool aliases. For more information on how to do so, please refer to the [official docs](https://github.com/github/github-mcp-server/blob/main/docs/tool-renaming.md).
42+
3643
## Lint & tests
3744
<!-- Check what you ran. If not run, explain briefly. -->
3845
- [ ] Linted locally with `./script/lint`

.github/workflows/code-scanning.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ env:
1414
jobs:
1515
analyze:
1616
name: Analyze (${{ matrix.language }})
17+
# Only run on the main repository, not on forks
18+
if: github.repository == 'github/github-mcp-server'
1719
runs-on: ${{ fromJSON(matrix.runner) }}
1820
permissions:
1921
actions: read
@@ -46,6 +48,9 @@ jobs:
4648
queries: "" # Default query suite
4749
packs: github/ccr-${{ matrix.language }}-queries
4850
config: |
51+
paths-ignore:
52+
- third-party
53+
- third-party-licenses.*.md
4954
default-setup:
5055
org:
5156
model-packs: [ ${{ github.event.inputs.code_scanning_codeql_packs }} ]

.github/workflows/docker-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
# multi-platform images and export cache
5555
# https://github.com/docker/setup-buildx-action
5656
- name: Set up Docker Buildx
57-
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
57+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
5858

5959
# Login against a Docker registry except on PR
6060
# https://github.com/docker/login-action
@@ -70,7 +70,7 @@ jobs:
7070
# https://github.com/docker/metadata-action
7171
- name: Extract Docker metadata
7272
id: meta
73-
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
73+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
7474
with:
7575
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
7676
tags: |
Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
# Create a github action that runs the license check script and fails if it exits with a non-zero status
1+
# Automatically fix license files on PRs that need updates
2+
# Tries to auto-commit the fix, or comments with instructions if push fails
23

34
name: License Check
4-
on: [push, pull_request]
5+
on:
6+
pull_request:
7+
branches:
8+
- main # Only run when PR targets main
9+
paths:
10+
- "**.go"
11+
- go.mod
12+
- go.sum
13+
- ".github/licenses.tmpl"
14+
- "script/licenses*"
15+
- "third-party-licenses.*.md"
16+
- "third-party/**"
517
permissions:
6-
contents: read
18+
contents: write
19+
pull-requests: write
720

821
jobs:
922
license-check:
@@ -12,10 +25,85 @@ jobs:
1225
steps:
1326
- name: Check out code
1427
uses: actions/checkout@v6
28+
with:
29+
ref: ${{ github.head_ref }}
1530

1631
- name: Set up Go
1732
uses: actions/setup-go@v6
1833
with:
1934
go-version-file: "go.mod"
20-
- name: check licenses
21-
run: ./script/licenses-check
35+
36+
# actions/setup-go does not setup the installed toolchain to be preferred over the system install,
37+
# which causes go-licenses to raise "Package ... does not have module info" errors.
38+
# For more information, https://github.com/google/go-licenses/issues/244#issuecomment-1885098633
39+
- name: Regenerate licenses
40+
env:
41+
CI: "true"
42+
run: |
43+
export GOROOT=$(go env GOROOT)
44+
export PATH=${GOROOT}/bin:$PATH
45+
./script/licenses
46+
47+
- name: Check for changes
48+
id: changes
49+
continue-on-error: true
50+
run: script/licenses-check
51+
52+
- name: Commit and push fixes
53+
if: steps.changes.outcome == 'failure'
54+
continue-on-error: true
55+
id: push
56+
run: |
57+
git config user.name "github-actions[bot]"
58+
git config user.email "github-actions[bot]@users.noreply.github.com"
59+
git add third-party-licenses.*.md third-party/
60+
git commit -m "chore: regenerate license files" -m "Auto-generated by license-check workflow"
61+
git push
62+
63+
- name: Check if already commented
64+
if: steps.changes.outcome == 'failure' && steps.push.outcome == 'failure'
65+
id: check_comment
66+
uses: actions/github-script@v7
67+
with:
68+
script: |
69+
const { data: comments } = await github.rest.issues.listComments({
70+
owner: context.repo.owner,
71+
repo: context.repo.repo,
72+
issue_number: context.issue.number
73+
});
74+
75+
const alreadyCommented = comments.some(comment =>
76+
comment.user.login === 'github-actions[bot]' &&
77+
comment.body.includes('## ⚠️ License files need updating')
78+
);
79+
80+
core.setOutput('already_commented', alreadyCommented ? 'true' : 'false');
81+
82+
- name: Comment with instructions if cannot push
83+
if: steps.changes.outcome == 'failure' && steps.push.outcome == 'failure' && steps.check_comment.outputs.already_commented == 'false'
84+
uses: actions/github-script@v7
85+
with:
86+
script: |
87+
await github.rest.issues.createComment({
88+
owner: context.repo.owner,
89+
repo: context.repo.repo,
90+
issue_number: context.issue.number,
91+
body: `## ⚠️ License files need updating
92+
93+
The license files are out of date. I tried to fix them automatically but don't have permission to push to this branch.
94+
95+
**Please run:**
96+
\`\`\`bash
97+
script/licenses
98+
git add third-party-licenses.*.md third-party/
99+
git commit -m "chore: regenerate license files"
100+
git push
101+
\`\`\`
102+
103+
Alternatively, enable "Allow edits by maintainers" in the PR settings so I can fix it automatically.`
104+
});
105+
106+
- name: Fail check if changes needed
107+
if: steps.changes.outcome == 'failure'
108+
run: exit 1
109+

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ When using Docker, you can pass the toolsets as environment variables:
393393
```bash
394394
docker run -i --rm \
395395
-e GITHUB_PERSONAL_ACCESS_TOKEN=<your-token> \
396-
-e GITHUB_TOOLSETS="repos,issues,pull_requests,actions,code_security,experiments" \
396+
-e GITHUB_TOOLSETS="repos,issues,pull_requests,actions,code_security" \
397397
ghcr.io/github/github-mcp-server
398398
```
399399

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ go 1.24.0
44

55
require (
66
github.com/google/go-github/v79 v79.0.0
7-
github.com/google/jsonschema-go v0.3.0
7+
github.com/google/jsonschema-go v0.4.2
88
github.com/josephburnett/jd v1.9.2
99
github.com/microcosm-cc/bluemonday v1.0.27
1010
github.com/migueleliasweb/go-github-mock v1.3.0
1111
github.com/muesli/cache2go v0.0.0-20221011235721-518229cd8021
12-
github.com/spf13/cobra v1.10.1
12+
github.com/spf13/cobra v1.10.2
1313
github.com/spf13/viper v1.21.0
1414
github.com/stretchr/testify v1.11.1
1515
)
@@ -37,7 +37,7 @@ require (
3737
github.com/go-viper/mapstructure/v2 v2.4.0
3838
github.com/google/go-querystring v1.1.0 // indirect
3939
github.com/inconshreveable/mousetrap v1.1.0 // indirect
40-
github.com/modelcontextprotocol/go-sdk v1.2.0-pre.1
40+
github.com/modelcontextprotocol/go-sdk v1.2.0
4141
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
4242
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
4343
github.com/rogpeppe/go-internal v1.13.1 // indirect

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ github.com/google/go-github/v79 v79.0.0 h1:MdodQojuFPBhmtwHiBcIGLw/e/wei2PvFX9nd
2828
github.com/google/go-github/v79 v79.0.0/go.mod h1:OAFbNhq7fQwohojb06iIIQAB9CBGYLq999myfUFnrS4=
2929
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
3030
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
31-
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
32-
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
31+
github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8=
32+
github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
3333
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
3434
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
3535
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@@ -57,8 +57,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
5757
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
5858
github.com/migueleliasweb/go-github-mock v1.3.0 h1:2sVP9JEMB2ubQw1IKto3/fzF51oFC6eVWOOFDgQoq88=
5959
github.com/migueleliasweb/go-github-mock v1.3.0/go.mod h1:ipQhV8fTcj/G6m7BKzin08GaJ/3B5/SonRAkgrk0zCY=
60-
github.com/modelcontextprotocol/go-sdk v1.2.0-pre.1 h1:14+JrlEIFvUmbu5+iJzWPLk8CkpvegfKr42oXyjp3O4=
61-
github.com/modelcontextprotocol/go-sdk v1.2.0-pre.1/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
60+
github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s=
61+
github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
6262
github.com/muesli/cache2go v0.0.0-20221011235721-518229cd8021 h1:31Y+Yu373ymebRdJN1cWLLooHH8xAr0MhKTEJGV/87g=
6363
github.com/muesli/cache2go v0.0.0-20221011235721-518229cd8021/go.mod h1:WERUkUryfUWlrHnFSO/BEUZ+7Ns8aZy7iVOGewxKzcc=
6464
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -82,8 +82,8 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
8282
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
8383
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
8484
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
85-
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
86-
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
85+
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
86+
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
8787
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
8888
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
8989
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=

pkg/errors/error.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package errors
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67

78
"github.com/github/github-mcp-server/pkg/utils"
89
"github.com/google/go-github/v79/github"
@@ -44,10 +45,29 @@ func (e *GitHubGraphQLError) Error() string {
4445
return fmt.Errorf("%s: %w", e.Message, e.Err).Error()
4546
}
4647

48+
type GitHubRawAPIError struct {
49+
Message string `json:"message"`
50+
Response *http.Response `json:"-"`
51+
Err error `json:"-"`
52+
}
53+
54+
func newGitHubRawAPIError(message string, resp *http.Response, err error) *GitHubRawAPIError {
55+
return &GitHubRawAPIError{
56+
Message: message,
57+
Response: resp,
58+
Err: err,
59+
}
60+
}
61+
62+
func (e *GitHubRawAPIError) Error() string {
63+
return fmt.Errorf("%s: %w", e.Message, e.Err).Error()
64+
}
65+
4766
type GitHubErrorKey struct{}
4867
type GitHubCtxErrors struct {
4968
api []*GitHubAPIError
5069
graphQL []*GitHubGraphQLError
70+
raw []*GitHubRawAPIError
5171
}
5272

5373
// ContextWithGitHubErrors updates or creates a context with a pointer to GitHub error information (to be used by middleware).
@@ -59,6 +79,7 @@ func ContextWithGitHubErrors(ctx context.Context) context.Context {
5979
// If the context already has GitHubCtxErrors, we just empty the slices to start fresh
6080
val.api = []*GitHubAPIError{}
6181
val.graphQL = []*GitHubGraphQLError{}
82+
val.raw = []*GitHubRawAPIError{}
6283
} else {
6384
// If not, we create a new GitHubCtxErrors and set it in the context
6485
ctx = context.WithValue(ctx, GitHubErrorKey{}, &GitHubCtxErrors{})
@@ -83,6 +104,14 @@ func GetGitHubGraphQLErrors(ctx context.Context) ([]*GitHubGraphQLError, error)
83104
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
84105
}
85106

107+
// GetGitHubRawAPIErrors retrieves the slice of GitHubRawAPIErrors from the context.
108+
func GetGitHubRawAPIErrors(ctx context.Context) ([]*GitHubRawAPIError, error) {
109+
if val, ok := ctx.Value(GitHubErrorKey{}).(*GitHubCtxErrors); ok {
110+
return val.raw, nil // return the slice of raw API errors from the context
111+
}
112+
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
113+
}
114+
86115
func NewGitHubAPIErrorToCtx(ctx context.Context, message string, resp *github.Response, err error) (context.Context, error) {
87116
apiErr := newGitHubAPIError(message, resp, err)
88117
if ctx != nil {
@@ -107,6 +136,15 @@ func addGitHubGraphQLErrorToContext(ctx context.Context, err *GitHubGraphQLError
107136
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
108137
}
109138

139+
func addRawAPIErrorToContext(ctx context.Context, err *GitHubRawAPIError) (context.Context, error) {
140+
if val, ok := ctx.Value(GitHubErrorKey{}).(*GitHubCtxErrors); ok {
141+
val.raw = append(val.raw, err)
142+
return ctx, nil
143+
}
144+
145+
return nil, fmt.Errorf("context does not contain GitHubCtxErrors")
146+
}
147+
110148
// NewGitHubAPIErrorResponse returns an mcp.NewToolResultError and retains the error in the context for access via middleware
111149
func NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github.Response, err error) *mcp.CallToolResult {
112150
apiErr := newGitHubAPIError(message, resp, err)
@@ -125,6 +163,15 @@ func NewGitHubGraphQLErrorResponse(ctx context.Context, message string, err erro
125163
return utils.NewToolResultErrorFromErr(message, err)
126164
}
127165

166+
// NewGitHubRawAPIErrorResponse returns an mcp.NewToolResultError and retains the error in the context for access via middleware
167+
func NewGitHubRawAPIErrorResponse(ctx context.Context, message string, resp *http.Response, err error) *mcp.CallToolResult {
168+
rawErr := newGitHubRawAPIError(message, resp, err)
169+
if ctx != nil {
170+
_, _ = addRawAPIErrorToContext(ctx, rawErr) // Explicitly ignore error for graceful handling
171+
}
172+
return utils.NewToolResultErrorFromErr(message, err)
173+
}
174+
128175
// NewGitHubAPIStatusErrorResponse handles cases where the API call succeeds (err == nil)
129176
// but returns an unexpected HTTP status code. It creates a synthetic error from the
130177
// status code and response body, then records it in context for observability tracking.

0 commit comments

Comments
 (0)