Skip to content

Commit d0e6c0b

Browse files
Merge branch 'main' into mcp-ui-apps-advanced
2 parents 5de74d8 + dc3ee11 commit d0e6c0b

26 files changed

+1151
-112
lines changed

.github/prompts/bug-report-review.prompt.yml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,38 @@ messages:
55
66
Your job is to analyze bug reports and assess their completeness.
77
8+
**CRITICAL: Detect unfilled templates**
9+
- Flag issues containing unmodified template text like "A clear and concise description of what the bug is"
10+
- Flag placeholder values like "Type this '...'" or "View the output '....'" that haven't been replaced
11+
- Flag generic/meaningless titles (e.g., random words, test content)
12+
- These are ALWAYS "Missing Details" even if the template structure is present
13+
814
Analyze the issue for these key elements:
9-
1. Clear description of the problem
15+
1. Clear description of the problem (not template text)
1016
2. Affected version (from running `docker run -i --rm ghcr.io/github/github-mcp-server ./github-mcp-server --version`)
11-
3. Steps to reproduce the behavior
12-
4. Expected vs actual behavior
17+
3. Steps to reproduce the behavior (actual steps, not placeholders)
18+
4. Expected vs actual behavior (real descriptions, not template text)
1319
5. Relevant logs (if applicable)
1420
1521
Provide ONE of these assessments:
1622
1723
### AI Assessment: Ready for Review
18-
Use when the bug report has most required information and can be triaged by a maintainer.
24+
Use when the bug report has actual information in required fields and can be triaged by a maintainer.
1925
2026
### AI Assessment: Missing Details
21-
Use when critical information is missing (no reproduction steps, no version info, unclear problem description).
27+
Use when:
28+
- Template text has not been replaced with actual content
29+
- Critical information is missing (no reproduction steps, no version info, unclear problem description)
30+
- The title is meaningless or spam-like
31+
- Placeholder text remains in any section
32+
33+
When marking as Missing Details, recommend adding the "waiting-for-reply" label.
2234
2335
### AI Assessment: Unsure
2436
Use when you cannot determine the completeness of the report.
2537
2638
After your assessment header, provide a brief explanation of your rating.
27-
If details are missing, note which specific sections need more information.
39+
If details are missing, be specific about which sections contain template text or need actual information.
2840
- role: user
2941
content: "{{input}}"
3042
model: openai/gpt-4o-mini

.github/prompts/default-issue-review.prompt.yml

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,47 @@ messages:
55
66
Your job is to analyze new issues and help categorize them.
77
8+
**CRITICAL: Detect invalid or incomplete submissions**
9+
- Flag issues with unmodified template text (e.g., "A clear and concise description...")
10+
- Flag placeholder values that haven't been replaced (e.g., "Type this '...'", "....", "XXX")
11+
- Flag meaningless, spam-like, or test titles (e.g., random words, nonsensical content)
12+
- Flag empty or nearly empty issues
13+
- These are ALWAYS "Missing Details" or "Invalid" depending on severity
14+
815
Analyze the issue to determine:
9-
1. Is this a bug report, feature request, question, or something else?
10-
2. Is the issue clear and well-described?
16+
1. Is this a bug report, feature request, question, documentation issue, or something else?
17+
2. Is the issue clear and well-described with actual content (not template text)?
1118
3. Does it contain enough information for maintainers to act on?
19+
4. Is this potentially spam, a test issue, or completely invalid?
1220
1321
Provide ONE of these assessments:
1422
1523
### AI Assessment: Ready for Review
16-
Use when the issue is clear, well-described, and contains enough context for maintainers to understand and act on it.
24+
Use when the issue is clear, well-described with actual content, and contains enough context for maintainers to understand and act on it.
1725
1826
### AI Assessment: Missing Details
19-
Use when the issue is unclear, lacks context, or needs more information to be actionable.
27+
Use when:
28+
- Template text has not been replaced with actual content
29+
- The issue is unclear or lacks context
30+
- Critical information is missing to make it actionable
31+
- The title is vague but the issue seems legitimate
32+
33+
When marking as Missing Details, recommend adding the "waiting-for-reply" label.
34+
35+
### AI Assessment: Invalid
36+
Use when:
37+
- The issue appears to be spam or test content
38+
- The title is completely meaningless and body has no useful information
39+
- This doesn't relate to the GitHub MCP Server project at all
40+
41+
When marking as Invalid, recommend adding the "invalid" label and consider closing.
2042
2143
### AI Assessment: Unsure
2244
Use when you cannot determine the nature or completeness of the issue.
2345
2446
After your assessment header, provide a brief explanation including:
25-
- What type of issue this appears to be (bug, feature request, question, etc.)
47+
- What type of issue this appears to be (bug, feature request, question, invalid, etc.)
48+
- Which specific sections contain template text or need actual information
2649
- What additional information might be helpful if any
2750
- role: user
2851
content: "{{input}}"

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:20-alpine AS ui-build
1+
FROM node:20-alpine@sha256:09e2b3d9726018aecf269bd35325f46bf75046a643a66d28360ec71132750ec8 AS ui-build
22
WORKDIR /app
33
COPY ui/package*.json ./ui/
44
RUN cd ui && npm ci
@@ -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.7-alpine AS build
10+
FROM golang:1.25.7-alpine@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4ced AS build
1111
ARG VERSION="dev"
1212

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

3232
# Make a stage to run the app
33-
FROM gcr.io/distroless/base-debian12
33+
FROM gcr.io/distroless/base-debian12@sha256:937c7eaaf6f3f2d38a1f8c4aeff326f0c56e4593ea152e9e8f74d976dde52f56
3434

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

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -983,9 +983,10 @@ The following sets of tools are available:
983983
- `fields`: Specific list of field IDs to include in the response when getting a project item (e.g. ["102589", "985201", "169875"]). If not provided, only the title field is included. Only used for 'get_project_item' method. (string[], optional)
984984
- `item_id`: The item's ID. Required for 'get_project_item' method. (number, optional)
985985
- `method`: The method to execute (string, required)
986-
- `owner`: The owner (user or organization login). The name is not case sensitive. (string, required)
986+
- `owner`: The owner (user or organization login). The name is not case sensitive. (string, optional)
987987
- `owner_type`: Owner type (user or org). If not provided, will be automatically detected. (string, optional)
988-
- `project_number`: The project's number. (number, required)
988+
- `project_number`: The project's number. (number, optional)
989+
- `status_update_id`: The node ID of the project status update. Required for 'get_project_status_update' method. (string, optional)
989990

990991
- **projects_list** - List GitHub Projects resources
991992
- **Required OAuth Scopes**: `read:project`
@@ -997,11 +998,12 @@ The following sets of tools are available:
997998
- `owner`: The owner (user or organization login). The name is not case sensitive. (string, required)
998999
- `owner_type`: Owner type (user or org). If not provided, will automatically try both. (string, optional)
9991000
- `per_page`: Results per page (max 50) (number, optional)
1000-
- `project_number`: The project's number. Required for 'list_project_fields' and 'list_project_items' methods. (number, optional)
1001+
- `project_number`: The project's number. Required for 'list_project_fields', 'list_project_items', and 'list_project_status_updates' methods. (number, optional)
10011002
- `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)
10021003

10031004
- **projects_write** - Modify GitHub Project items
10041005
- **Required OAuth Scopes**: `project`
1006+
- `body`: The body of the status update (markdown). Used for 'create_project_status_update' method. (string, optional)
10051007
- `issue_number`: The issue number (use when item_type is 'issue' for 'add_project_item' method). Provide either issue_number or pull_request_number. (number, optional)
10061008
- `item_id`: The project item ID. Required for 'update_project_item' and 'delete_project_item' methods. (number, optional)
10071009
- `item_owner`: The owner (user or organization) of the repository containing the issue or pull request. Required for 'add_project_item' method. (string, optional)
@@ -1012,6 +1014,9 @@ The following sets of tools are available:
10121014
- `owner_type`: Owner type (user or org). If not provided, will be automatically detected. (string, optional)
10131015
- `project_number`: The project's number. (number, required)
10141016
- `pull_request_number`: The pull request number (use when item_type is 'pull_request' for 'add_project_item' method). Provide either issue_number or pull_request_number. (number, optional)
1017+
- `start_date`: The start date of the status update in YYYY-MM-DD format. Used for 'create_project_status_update' method. (string, optional)
1018+
- `status`: The status of the project. Used for 'create_project_status_update' method. (string, optional)
1019+
- `target_date`: The target date of the status update in YYYY-MM-DD format. Used for 'create_project_status_update' method. (string, optional)
10151020
- `updated_field`: Object consisting of the ID of the project field to update and the new value for the field. To clear the field, set value to null. Example: {"id": 123456, "value": "New Value"}. Required for 'update_project_item' method. (object, optional)
10161021

10171022
</details>

cmd/github-mcp-server/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ var (
6161
}
6262
}
6363

64+
// Parse excluded tools (similar to tools)
65+
var excludeTools []string
66+
if viper.IsSet("exclude_tools") {
67+
if err := viper.UnmarshalKey("exclude_tools", &excludeTools); err != nil {
68+
return fmt.Errorf("failed to unmarshal exclude-tools: %w", err)
69+
}
70+
}
71+
6472
// Parse enabled features (similar to toolsets)
6573
var enabledFeatures []string
6674
if viper.IsSet("features") {
@@ -85,6 +93,7 @@ var (
8593
ContentWindowSize: viper.GetInt("content-window-size"),
8694
LockdownMode: viper.GetBool("lockdown-mode"),
8795
InsidersMode: viper.GetBool("insiders"),
96+
ExcludeTools: excludeTools,
8897
RepoAccessCacheTTL: &ttl,
8998
}
9099
return ghmcp.RunStdioServer(stdioServerConfig)
@@ -126,6 +135,7 @@ func init() {
126135
// Add global flags that will be shared by all commands
127136
rootCmd.PersistentFlags().StringSlice("toolsets", nil, github.GenerateToolsetsHelp())
128137
rootCmd.PersistentFlags().StringSlice("tools", nil, "Comma-separated list of specific tools to enable")
138+
rootCmd.PersistentFlags().StringSlice("exclude-tools", nil, "Comma-separated list of tool names to disable regardless of other settings")
129139
rootCmd.PersistentFlags().StringSlice("features", nil, "Comma-separated list of feature flags to enable")
130140
rootCmd.PersistentFlags().Bool("dynamic-toolsets", false, "Enable dynamic toolsets")
131141
rootCmd.PersistentFlags().Bool("read-only", false, "Restrict the server to read-only operations")
@@ -147,6 +157,7 @@ func init() {
147157
// Bind flag to viper
148158
_ = viper.BindPFlag("toolsets", rootCmd.PersistentFlags().Lookup("toolsets"))
149159
_ = viper.BindPFlag("tools", rootCmd.PersistentFlags().Lookup("tools"))
160+
_ = viper.BindPFlag("exclude_tools", rootCmd.PersistentFlags().Lookup("exclude-tools"))
150161
_ = viper.BindPFlag("features", rootCmd.PersistentFlags().Lookup("features"))
151162
_ = viper.BindPFlag("dynamic_toolsets", rootCmd.PersistentFlags().Lookup("dynamic-toolsets"))
152163
_ = viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only"))

docs/server-configuration.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ We currently support the following ways in which the GitHub MCP Server can be co
99
|---------------|---------------|--------------|
1010
| Toolsets | `X-MCP-Toolsets` header or `/x/{toolset}` URL | `--toolsets` flag or `GITHUB_TOOLSETS` env var |
1111
| Individual Tools | `X-MCP-Tools` header | `--tools` flag or `GITHUB_TOOLS` env var |
12+
| Exclude Tools | `X-MCP-Exclude-Tools` header | `--exclude-tools` flag or `GITHUB_EXCLUDE_TOOLS` env var |
1213
| Read-Only Mode | `X-MCP-Readonly` header or `/readonly` URL | `--read-only` flag or `GITHUB_READ_ONLY` env var |
1314
| Dynamic Mode | Not available | `--dynamic-toolsets` flag or `GITHUB_DYNAMIC_TOOLSETS` env var |
1415
| Lockdown Mode | `X-MCP-Lockdown` header | `--lockdown-mode` flag or `GITHUB_LOCKDOWN_MODE` env var |
@@ -20,10 +21,12 @@ We currently support the following ways in which the GitHub MCP Server can be co
2021

2122
## How Configuration Works
2223

23-
All configuration options are **composable**: you can combine toolsets, individual tools, dynamic discovery, read-only mode and lockdown mode in any way that suits your workflow.
24+
All configuration options are **composable**: you can combine toolsets, individual tools, excluded tools, dynamic discovery, read-only mode and lockdown mode in any way that suits your workflow.
2425

2526
Note: **read-only** mode acts as a strict security filter that takes precedence over any other configuration, by disabling write tools even when explicitly requested.
2627

28+
Note: **excluded tools** takes precedence over toolsets and individual tools — listed tools are always excluded, even if their toolset is enabled or they are explicitly added via `--tools` / `X-MCP-Tools`.
29+
2730
---
2831

2932
## Configuration Examples
@@ -170,6 +173,56 @@ Enable entire toolsets, then add individual tools from toolsets you don't want f
170173

171174
---
172175

176+
### Excluding Specific Tools
177+
178+
**Best for:** Users who want to enable a broad toolset but need to exclude specific tools for security, compliance, or to prevent undesired behavior.
179+
180+
Listed tools are removed regardless of any other configuration — even if their toolset is enabled or they are individually added.
181+
182+
<table>
183+
<tr><th>Remote Server</th><th>Local Server</th></tr>
184+
<tr valign="top">
185+
<td>
186+
187+
```json
188+
{
189+
"type": "http",
190+
"url": "https://api.githubcopilot.com/mcp/",
191+
"headers": {
192+
"X-MCP-Toolsets": "pull_requests",
193+
"X-MCP-Exclude-Tools": "create_pull_request,merge_pull_request"
194+
}
195+
}
196+
```
197+
198+
</td>
199+
<td>
200+
201+
```json
202+
{
203+
"type": "stdio",
204+
"command": "go",
205+
"args": [
206+
"run",
207+
"./cmd/github-mcp-server",
208+
"stdio",
209+
"--toolsets=pull_requests",
210+
"--exclude-tools=create_pull_request,merge_pull_request"
211+
],
212+
"env": {
213+
"GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
214+
}
215+
}
216+
```
217+
218+
</td>
219+
</tr>
220+
</table>
221+
222+
**Result:** All pull request tools except `create_pull_request` and `merge_pull_request` — the user gets read and review tools only.
223+
224+
---
225+
173226
### Read-Only Mode
174227

175228
**Best for:** Security conscious users who want to ensure the server won't allow operations that modify issues, pull requests, repositories etc.

internal/ghmcp/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ func NewStdioMCPServer(ctx context.Context, cfg github.MCPServerConfig) (*mcp.Se
135135
WithReadOnly(cfg.ReadOnly).
136136
WithToolsets(github.ResolvedEnabledToolsets(cfg.DynamicToolsets, cfg.EnabledToolsets, cfg.EnabledTools)).
137137
WithTools(github.CleanTools(cfg.EnabledTools)).
138+
WithExcludeTools(cfg.ExcludeTools).
138139
WithServerInstructions().
139140
WithFeatureChecker(featureChecker).
140141
WithInsidersMode(cfg.InsidersMode)
@@ -214,6 +215,11 @@ type StdioServerConfig struct {
214215
// InsidersMode indicates if we should enable experimental features
215216
InsidersMode bool
216217

218+
// ExcludeTools is a list of tool names to disable regardless of other settings.
219+
// These tools will be excluded even if their toolset is enabled or they are
220+
// explicitly listed in EnabledTools.
221+
ExcludeTools []string
222+
217223
// RepoAccessCacheTTL overrides the default TTL for repository access cache entries.
218224
RepoAccessCacheTTL *time.Duration
219225
}
@@ -271,6 +277,7 @@ func RunStdioServer(cfg StdioServerConfig) error {
271277
ContentWindowSize: cfg.ContentWindowSize,
272278
LockdownMode: cfg.LockdownMode,
273279
InsidersMode: cfg.InsidersMode,
280+
ExcludeTools: cfg.ExcludeTools,
274281
Logger: logger,
275282
RepoAccessTTL: cfg.RepoAccessCacheTTL,
276283
TokenScopes: tokenScopes,

pkg/buffer/buffer.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ const maxLineSize = 10 * 1024 * 1024
3232
// If the response contains more lines than maxJobLogLines, only the most recent lines are kept.
3333
// Lines exceeding maxLineSize are truncated with a marker.
3434
func ProcessResponseAsRingBufferToEnd(httpResp *http.Response, maxJobLogLines int) (string, int, *http.Response, error) {
35+
if maxJobLogLines <= 0 {
36+
maxJobLogLines = 500
37+
}
3538
if maxJobLogLines > 100000 {
3639
maxJobLogLines = 100000
3740
}

pkg/context/request.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ func IsInsidersMode(ctx context.Context) bool {
8282
return false
8383
}
8484

85+
// excludeToolsCtxKey is a context key for excluded tools
86+
type excludeToolsCtxKey struct{}
87+
88+
// WithExcludeTools adds the excluded tools to the context
89+
func WithExcludeTools(ctx context.Context, tools []string) context.Context {
90+
return context.WithValue(ctx, excludeToolsCtxKey{}, tools)
91+
}
92+
93+
// GetExcludeTools retrieves the excluded tools from the context
94+
func GetExcludeTools(ctx context.Context) []string {
95+
if tools, ok := ctx.Value(excludeToolsCtxKey{}).([]string); ok {
96+
return tools
97+
}
98+
return nil
99+
}
100+
85101
// headerFeaturesCtxKey is a context key for raw header feature flags
86102
type headerFeaturesCtxKey struct{}
87103

pkg/github/__toolsnaps__/projects_get.snap

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"enum": [
2727
"get_project",
2828
"get_project_field",
29-
"get_project_item"
29+
"get_project_item",
30+
"get_project_status_update"
3031
],
3132
"type": "string"
3233
},
@@ -45,12 +46,14 @@
4546
"project_number": {
4647
"description": "The project's number.",
4748
"type": "number"
49+
},
50+
"status_update_id": {
51+
"description": "The node ID of the project status update. Required for 'get_project_status_update' method.",
52+
"type": "string"
4853
}
4954
},
5055
"required": [
51-
"method",
52-
"owner",
53-
"project_number"
56+
"method"
5457
],
5558
"type": "object"
5659
},

0 commit comments

Comments
 (0)