Skip to content

Commit 7d4ae59

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/agent-skills-v2
2 parents 09ea2f9 + 64a49f3 commit 7d4ae59

120 files changed

Lines changed: 13375 additions & 1097 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
# https://github.com/docker/login-action
6161
- name: Log into registry ${{ env.REGISTRY }}
6262
if: github.event_name != 'pull_request'
63-
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
63+
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
6464
with:
6565
registry: ${{ env.REGISTRY }}
6666
username: ${{ github.actor }}

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ COPY ui/ ./ui/
77
RUN mkdir -p ./pkg/github/ui_dist && \
88
cd ui && npm run build
99

10-
FROM golang:1.25.12-alpine@sha256:56961d79ea8129efddcc0b8643fd8a5416b4e6228cfd477e3fd61deb2672c587 AS build
10+
FROM golang:1.25.13-alpine@sha256:1e0126852075c9c60731c8ba49088448b91f63e2aed97ca9d1a9791622a05946 AS build
1111
ARG VERSION="dev"
1212

1313
# Set the working directory
@@ -35,7 +35,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \
3535
-o /bin/github-mcp-server ./cmd/github-mcp-server
3636

3737
# Make a stage to run the app
38-
FROM gcr.io/distroless/base-debian12@sha256:348dac1808083ccc3366399d6db835875b4eaf7c9b694783f5a3f353c4b58a28
38+
FROM gcr.io/distroless/base-debian12@sha256:76b3162a31477bca4a245b836c624f4c4a1a3705e99b9003907d992bec2c4bca
3939

4040
# Add required MCP server annotation
4141
LABEL io.modelcontextprotocol.server.name="io.github.github/github-mcp-server"

README.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ To keep your GitHub PAT secure and reusable across different MCP hosts:
247247
The flag `--gh-host` and the environment variable `GITHUB_HOST` can be used to set
248248
the hostname for GitHub Enterprise Server or GitHub Enterprise Cloud with data residency.
249249

250-
- For GitHub Enterprise Server, prefix the hostname with the `https://` URI scheme, as it otherwise defaults to `http://`, which GitHub Enterprise Server does not support.
250+
- For GitHub Enterprise Server, prefix the hostname with the `https://` URI scheme. HTTPS is required and enforced: non-HTTPS hosts are refused so that credentials are never sent over cleartext (the only exception is a loopback host such as `http://localhost` for local development).
251251
- For GitHub Enterprise Cloud with data residency, use `https://YOURSUBDOMAIN.ghe.com` as the hostname.
252252

253253
``` json
@@ -895,7 +895,7 @@ The following sets of tools are available:
895895
- **add_issue_comment** - Add comment to issue or pull request
896896
- **Required OAuth Scopes**: `repo`
897897
- `body`: Comment content. Required unless reaction is provided. (string, optional)
898-
- `comment_id`: The numeric ID of the issue or pull request comment to react to. Use this for reactions to comments; omit it to react to the issue or pull request itself. Cannot be combined with body. (number, optional)
898+
- `comment_id`: The numeric ID of the issue or pull request comment to react to. Use this for reactions to comments; omit it to react to the issue or pull request itself. Cannot be combined with body. (integer, optional)
899899
- `issue_number`: Issue or pull request number to comment on or react to. (number, required)
900900
- `owner`: Repository owner (string, required)
901901
- `reaction`: Emoji reaction to add. Required unless body is provided. (string, optional)
@@ -912,7 +912,7 @@ The following sets of tools are available:
912912
- `issue_number`: The number of the issue (number, required)
913913
- `method`: The read operation to perform on a single issue.
914914
Options are:
915-
1. get - Get issue details. Also returns best-effort hierarchy flags (`has_parent`, `has_children`); `parent` and `sub_issues_summary` are optional relationship summaries.
915+
1. get - Get issue details. Also returns best-effort hierarchy flags (`has_parent`, `has_children`); `parent` and `sub_issues_summary` are optional relationship summaries, and `closed_by_pull_requests` summarizes the pull requests configured to close the issue as `total_count` plus up to 5 `references`.
916916
2. get_comments - Get issue comments.
917917
3. get_sub_issues - Get sub-issues (children) of the issue.
918918
4. get_parent - Get the parent issue, if this issue is a sub-issue of another.
@@ -927,7 +927,7 @@ The following sets of tools are available:
927927
- **Required OAuth Scopes**: `repo`
928928
- `assignees`: Usernames to assign to this issue (string[], optional)
929929
- `body`: Issue body content (string, optional)
930-
- `duplicate_of`: Issue number that this issue is a duplicate of. Only used when state_reason is 'duplicate'. (number, optional)
930+
- `duplicate_of`: Issue number that this issue is a duplicate of. Required when state_reason is 'duplicate'. (number, optional)
931931
- `issue_fields`: Issue field values to set or clear. Each item requires 'field_name' and exactly one of 'value', 'field_option_name', or 'delete: true'. (object[], optional)
932932
- `issue_number`: Issue number to update (number, optional)
933933
- `labels`: Labels to apply to this issue (string[], optional)
@@ -942,7 +942,7 @@ The following sets of tools are available:
942942
- `state`: New state (string, optional)
943943
- `state_reason`: Reason for the state change. Ignored unless state is changed. (string, optional)
944944
- `title`: Issue title (string, optional)
945-
- `type`: Type of this issue. Only use if issue types are enabled for this repository. Use list_issue_types tool to get valid type values for this repository or its owner organization. If the repository doesn't support issue types, omit this parameter. (string, optional)
945+
- `type`: Type of this issue. For updates, pass null to remove the current type. Only use if issue types are enabled for this repository. Use list_issue_types to get valid type values for this repository or its owner organization. If the repository doesn't support issue types, omit this parameter. (string | null, optional)
946946

947947
- **list_issue_fields** - List issue fields
948948
- **Required OAuth Scopes (any of)**: `repo`, `read:org`
@@ -977,7 +977,7 @@ The following sets of tools are available:
977977
- `owner`: Optional repository owner. If provided with repo, only issues for this repository are listed. (string, optional)
978978
- `page`: Page number for pagination (min 1) (number, optional)
979979
- `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
980-
- `query`: Search query using GitHub issues search syntax (string, required)
980+
- `query`: The search query, as natural language. When the user gives alternative wordings, include them as plain words rather than joining them with OR. (string, required)
981981
- `repo`: Optional repository name. If provided with owner, only issues for this repository are listed. (string, optional)
982982
- `sort`: Sort field by number of matches of categories, defaults to best match (string, optional)
983983

@@ -1100,6 +1100,7 @@ The following sets of tools are available:
11001100
- `owner_type`: Owner type (user or org). If not provided, will be automatically detected. (string, optional)
11011101
- `project_number`: The project's number. (number, optional)
11021102
- `status_update_id`: The node ID of the project status update. Required for 'get_project_status_update' method. (string, optional)
1103+
- `view_id`: The node ID of the project view. Required for 'get_project_view' method. (string, optional)
11031104

11041105
- **projects_list** - List GitHub Projects resources
11051106
- **Required OAuth Scopes**: `read:project`
@@ -1112,13 +1113,14 @@ The following sets of tools are available:
11121113
- `owner`: The owner (user or organization login). The name is not case sensitive. (string, required)
11131114
- `owner_type`: Owner type (user or org). If not provided, will automatically try both. (string, optional)
11141115
- `per_page`: Results per page (max 50) (number, optional)
1115-
- `project_number`: The project's number. Required for 'list_project_fields', 'list_project_items', and 'list_project_status_updates' methods. (number, optional)
1116+
- `project_number`: The project's number. Required for 'list_project_fields', 'list_project_items', 'list_project_views', and 'list_project_status_updates' methods. (number, optional)
11161117
- `query`: Filter/query string. For list_projects: filter by title text and state (e.g. "roadmap is:open"). For list_project_items: advanced filtering using GitHub's project filtering syntax. (string, optional)
11171118

11181119
- **projects_write** - Manage GitHub Projects
11191120
- **Required OAuth Scopes**: `project`
11201121
- `body`: The body of the status update (markdown). Used for 'create_project_status_update' method. (string, optional)
11211122
- `field_name`: The name of the iteration field (e.g. 'Sprint'). Required for 'create_iteration_field' method. (string, optional)
1123+
- `filter`: Saved view filter; omit on update to preserve it, or pass null to clear it. (string | null, optional)
11221124
- `issue_number`: The issue number. Required for 'add_project_item' when item_type is 'issue'. Also accepted by 'update_project_item' to resolve the item by issue number (combine with item_owner and item_repo). (number, optional)
11231125
- `item_id`: The project item ID. Required for 'delete_project_item'. For 'update_project_item', provide either item_id, or (item_owner + item_repo + issue_number) to resolve the item by issue. (number, optional)
11241126
- `item_owner`: The owner (user or organization) of the repository containing the issue or pull request. Required for 'add_project_item' method. Also accepted by 'update_project_item' when resolving the item by issue number. (string, optional)
@@ -1127,7 +1129,9 @@ The following sets of tools are available:
11271129
- `items`: The items to update with the top-level 'updated_field'. Required for 'update_project_items'; prefer it over calling 'update_project_item' in a loop. Each entry must match exactly one reference variant: 'node_id', numeric 'item_id', or 'item_owner' + 'item_repo' + 'issue_number'. Limit: 50 items per call. (object[], optional)
11281130
- `iteration_duration`: Duration in days for iterations of the field (e.g. 7 for weekly, 14 for bi-weekly). Required for 'create_iteration_field' method. (number, optional)
11291131
- `iterations`: Custom iterations for 'create_iteration_field' method. Only set this when you need iterations with varying durations, breaks between them, or specific titles. Otherwise omit it: GitHub auto-creates three iterations of 'iteration_duration' days starting on 'start_date', which is the right choice for most cases. (object[], optional)
1132+
- `layout`: View layout; required when creating a view. (string, optional)
11301133
- `method`: The method to execute (string, required)
1134+
- `name`: View name; required when creating a view. (string, optional)
11311135
- `owner`: The project owner (user or organization login). The name is not case sensitive. (string, required)
11321136
- `owner_type`: Owner type (user or org). Required for 'create_project' method. If not provided for other methods, will be automatically detected. (string, optional)
11331137
- `project_number`: The project's number. Required for all methods except 'create_project'. (number, optional)
@@ -1137,6 +1141,9 @@ The following sets of tools are available:
11371141
- `target_date`: The target date of the status update in YYYY-MM-DD format. Used for 'create_project_status_update' method. (string, optional)
11381142
- `title`: The project title. Required for 'create_project' method. (string, optional)
11391143
- `updated_field`: The field/value to apply, using {"id": 123, "value": ...} or {"name": "Status", "value": ...}; null clears the field. Required for 'update_project_item' and 'update_project_items', where one top-level field/value applies to every item in a batch. For 'update_project_item' SINGLE_SELECT fields, the name form accepts option names; the ID form expects an option ID. (object, optional)
1144+
- `view_id`: Project view node ID for update or delete; must belong to owner/project_number. (string, optional)
1145+
- `visible_field_names`: Ordered project field names to show on create or replace on update; omit on update to preserve, or pass [] to reset. Mutually exclusive with visible_fields. Roadmap accepts only []. (string[], optional)
1146+
- `visible_fields`: Ordered project field database IDs to show on create or replace on update; omit on update to preserve, or pass [] to reset. Mutually exclusive with visible_field_names. Roadmap accepts only []. (string[], optional)
11401147

11411148
</details>
11421149

@@ -1278,6 +1285,7 @@ The following sets of tools are available:
12781285

12791286
- **create_or_update_file** - Create or update file
12801287
- **Required OAuth Scopes**: `repo`
1288+
- `allow_symlink_write`: Set true to update a symbolic link itself; content must be its new target path. (boolean, optional)
12811289
- `branch`: Branch to create/update the file in (string, required)
12821290
- `content`: Content of the file, exactly as it should appear once written. Do not base64-encode it; this server does that before calling the REST API. (string, required)
12831291
- `message`: Commit message (string, required)
@@ -1302,6 +1310,11 @@ The following sets of tools are available:
13021310
- `path`: Path to the file to delete (string, required)
13031311
- `repo`: Repository name (string, required)
13041312

1313+
- **delete_repository** - Delete repository
1314+
- **Required OAuth Scopes (all required)**: `delete_repo`, `repo`
1315+
- `owner`: Repository owner (username or organization) (string, required)
1316+
- `repo`: Repository name (string, required)
1317+
13051318
- **fork_repository** - Fork repository
13061319
- **Required OAuth Scopes**: `repo`
13071320
- `organization`: Organization to fork to (string, optional)
@@ -1601,6 +1614,10 @@ docker run -i --rm \
16011614

16021615
Lockdown mode limits the content that the server will surface from public repositories. When enabled, the server checks whether the author of each item has push access to the repository. Private repositories are unaffected, and collaborators keep full access to their own content.
16031616

1617+
Lockdown mode is a best-effort content filter intended to reduce the risk of prompt injection from untrusted repository content (issues, pull requests, comments, commits, etc.). It is **not** an authorization boundary: it does not change what the underlying GitHub credential can read or write, and content withheld from a filtered tool response may still be reachable through other tools or direct GitHub API access with the same credential.
1618+
1619+
As an intentional exception, content authored by a small set of trusted bot accounts (currently `github-actions[bot]` and `copilot`) is always treated as safe, regardless of push access. This avoids filtering routine automation output (e.g. CI-generated commits or comments) that would otherwise be withheld under lockdown mode.
1620+
16041621
```bash
16051622
./github-mcp-server --lockdown-mode
16061623
```
@@ -1614,12 +1631,17 @@ docker run -i --rm \
16141631
ghcr.io/github/github-mcp-server
16151632
```
16161633

1634+
In HTTP mode, this flag (or `GITHUB_LOCKDOWN_MODE`) is an upper bound: the `X-MCP-Lockdown` request header can enable lockdown mode when the operator has not, but it cannot disable lockdown mode the operator has already enabled. See the [Server Configuration Guide](docs/server-configuration.md#lockdown-mode) for details.
1635+
16171636
The behavior of lockdown mode depends on the tool invoked.
16181637

16191638
Following tools will return an error when the author lacks the push access:
16201639

16211640
- `issue_read:get`
16221641
- `pull_request_read:get`
1642+
- `pull_request_read:get_diff`
1643+
- `pull_request_read:get_files`
1644+
- `pull_request_read:get_commits`
16231645

16241646
Following tools will filter out content from users lacking the push access:
16251647

cmd/github-mcp-server/generate_docs.go

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,13 @@ func writeToolDoc(buf *strings.Builder, tool inventory.ServerTool) {
221221

222222
// OAuth scopes if present
223223
if len(tool.RequiredScopes) > 0 {
224-
// Scope filtering uses "any of" semantics (see scopes.HasRequiredScopes),
225-
// so when multiple required scopes are listed, render them as alternatives
226-
// rather than implying all are required.
227224
scopeList := "`" + strings.Join(tool.RequiredScopes, "`, `") + "`"
228-
if len(tool.RequiredScopes) > 1 {
225+
switch {
226+
case len(tool.RequiredScopeGroups) > 1:
227+
fmt.Fprintf(buf, " - **Required OAuth Scopes (all required)**: %s\n", scopeList)
228+
case len(tool.RequiredScopes) > 1:
229229
fmt.Fprintf(buf, " - **Required OAuth Scopes (any of)**: %s\n", scopeList)
230-
} else {
230+
default:
231231
fmt.Fprintf(buf, " - **Required OAuth Scopes**: %s\n", scopeList)
232232
}
233233

@@ -273,19 +273,7 @@ func writeToolDoc(buf *strings.Builder, tool inventory.ServerTool) {
273273
requiredStr = "required"
274274
}
275275

276-
var typeStr string
277-
278-
// Get the type and description
279-
switch prop.Type {
280-
case "array":
281-
if prop.Items != nil {
282-
typeStr = prop.Items.Type + "[]"
283-
} else {
284-
typeStr = "array"
285-
}
286-
default:
287-
typeStr = prop.Type
288-
}
276+
typeStr := schemaTypeString(prop)
289277

290278
// Indent any continuation lines in the description to maintain markdown formatting
291279
description := indentMultilineDescription(prop.Description, " ")
@@ -300,6 +288,40 @@ func writeToolDoc(buf *strings.Builder, tool inventory.ServerTool) {
300288
}
301289
}
302290

291+
func schemaTypeString(schema *jsonschema.Schema) string {
292+
switch {
293+
case schema.Type == "array":
294+
if schema.Items != nil {
295+
return schema.Items.Type + "[]"
296+
}
297+
return "array"
298+
case schema.Type != "":
299+
return schema.Type
300+
case len(schema.Types) > 0:
301+
return strings.Join(schema.Types, " | ")
302+
}
303+
304+
var union []*jsonschema.Schema
305+
switch {
306+
case len(schema.AnyOf) > 0:
307+
union = schema.AnyOf
308+
case len(schema.OneOf) > 0:
309+
union = schema.OneOf
310+
default:
311+
// A schema without type constraints accepts any value.
312+
return "any"
313+
}
314+
315+
types := make([]string, 0, len(union))
316+
for _, member := range union {
317+
memberType := schemaTypeString(member)
318+
if !slices.Contains(types, memberType) {
319+
types = append(types, memberType)
320+
}
321+
}
322+
return strings.Join(types, " | ")
323+
}
324+
303325
// scopesEqual checks if two scope slices contain the same elements (order-independent)
304326
func scopesEqual(a, b []string) bool {
305327
if len(a) != len(b) {

0 commit comments

Comments
 (0)