Skip to content

Commit b67f2e1

Browse files
Merge branch 'main' into add-logging-stack
2 parents 88e323a + 30712de commit b67f2e1

26 files changed

+595
-117
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: 97 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:
@@ -13,9 +26,88 @@ jobs:
1326
- name: Check out code
1427
uses: actions/checkout@v6
1528

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

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ Alternatively, to manually configure VS Code, choose the appropriate JSON block
8181

8282
### Install in other MCP hosts
8383
- **[GitHub Copilot in other IDEs](/docs/installation-guides/install-other-copilot-ides.md)** - Installation for JetBrains, Visual Studio, Eclipse, and Xcode with GitHub Copilot
84-
- **[Claude Applications](/docs/installation-guides/install-claude.md)** - Installation guide for Claude Web, Claude Desktop and Claude Code CLI
84+
- **[Claude Applications](/docs/installation-guides/install-claude.md)** - Installation guide for Claude Desktop and Claude Code CLI
85+
- **[Codex](/docs/installation-guides/install-codex.md)** - Installation guide for Open AI Codex
8586
- **[Cursor](/docs/installation-guides/install-cursor.md)** - Installation guide for Cursor IDE
8687
- **[Windsurf](/docs/installation-guides/install-windsurf.md)** - Installation guide for Windsurf IDE
8788

@@ -131,7 +132,7 @@ GitHub Enterprise Server does not support remote server hosting. Please refer to
131132
### Prerequisites
132133

133134
1. To run the server in a container, you will need to have [Docker](https://www.docker.com/) installed.
134-
2. Once Docker is installed, you will also need to ensure Docker is running. The image is public; if you get errors on pull, you may have an expired token and need to `docker logout ghcr.io`.
135+
2. Once Docker is installed, you will also need to ensure Docker is running. The Docker image is available at `ghcr.io/github/github-mcp-server`. The image is public; if you get errors on pull, you may have an expired token and need to `docker logout ghcr.io`.
135136
3. Lastly you will need to [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
136137
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)).
137138

@@ -393,7 +394,7 @@ When using Docker, you can pass the toolsets as environment variables:
393394
```bash
394395
docker run -i --rm \
395396
-e GITHUB_PERSONAL_ACCESS_TOKEN=<your-token> \
396-
-e GITHUB_TOOLSETS="repos,issues,pull_requests,actions,code_security,experiments" \
397+
-e GITHUB_TOOLSETS="repos,issues,pull_requests,actions,code_security" \
397398
ghcr.io/github/github-mcp-server
398399
```
399400

@@ -509,7 +510,7 @@ The following sets of tools are available:
509510
- `repo`: Repository name (string, required)
510511
- `resource_id`: The unique identifier of the resource. This will vary based on the "method" provided, so ensure you provide the correct ID:
511512
- Do not provide any resource ID for 'list_workflows' method.
512-
- Provide a workflow ID or workflow file name (e.g. ci.yaml) for 'list_workflow_runs' method.
513+
- Provide a workflow ID or workflow file name (e.g. ci.yaml) for 'list_workflow_runs' method, or omit to list all workflow runs in the repository.
513514
- Provide a workflow run ID for 'list_workflow_jobs' and 'list_workflow_run_artifacts' methods.
514515
(string, optional)
515516
- `workflow_jobs_filter`: Filters for workflow jobs. **ONLY** used when method is 'list_workflow_jobs' (object, optional)
@@ -757,7 +758,7 @@ The following sets of tools are available:
757758
- `repo`: Repository name (string, required)
758759

759760
- **assign_copilot_to_issue** - Assign Copilot to issue
760-
- `issueNumber`: Issue number (number, required)
761+
- `issue_number`: Issue number (number, required)
761762
- `owner`: Repository owner (string, required)
762763
- `repo`: Repository name (string, required)
763764

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)