Skip to content

Commit 3c39808

Browse files
refactor: remove dynamic toolsets and deprecated closure constructor
Dynamic toolset discovery (the meta-tools enable_toolset, list_available_toolsets, get_toolset_tools and the --dynamic-toolsets / GITHUB_DYNAMIC_TOOLSETS switch) was a local-only feature never offered by the remote server. Removing it deletes a meaningful chunk of branching, configuration surface and tests for a path no longer in active use. The deprecated closure-based NewServerToolWithDeps generic constructor was only kept around for the dynamic tool registration path and is removed together with it. Going forward there are exactly two constructors: - NewServerTool — raw mcp.ToolHandler, no closure, no unmarshalling - NewServerToolWithContextHandler[In, Out] — typed handler, deps via context Inventory methods that only existed for the dynamic path (ToolsForToolset, IsToolsetEnabled, EnableToolset, EnabledToolsetIDs) are removed. ResolvedEnabledToolsets loses its dynamic flag. Also strips dynamic references from the README, server configuration docs, copilot-instructions, mcp-diff workflow, and conformance-test script. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 272d160 commit 3c39808

24 files changed

Lines changed: 51 additions & 942 deletions

.github/copilot-instructions.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ All workflows run on push/PR unless noted. Located in `.github/workflows/`:
243243
- **GITHUB_HOST** - For GitHub Enterprise Server (prefix with `https://`)
244244
- **GITHUB_TOOLSETS** - Comma-separated toolset list (overrides --toolsets flag)
245245
- **GITHUB_READ_ONLY** - Set to "1" for read-only mode
246-
- **GITHUB_DYNAMIC_TOOLSETS** - Set to "1" for dynamic toolset discovery
247246
- **UPDATE_TOOLSNAPS** - Set to "true" when running tests to update snapshots
248247
- **GITHUB_MCP_SERVER_E2E_TOKEN** - Token for e2e tests
249248
- **GITHUB_MCP_SERVER_E2E_DEBUG** - Set to "true" for in-process e2e debugging
@@ -273,7 +272,7 @@ server.json - MCP server registry metadata
273272
`cmd/github-mcp-server/main.go` - Uses cobra for CLI, viper for config, supports:
274273
- `stdio` command (default) - MCP stdio transport
275274
- `generate-docs` command - Documentation generation
276-
- Flags: --toolsets, --read-only, --dynamic-toolsets, --gh-host, --log-file
275+
- Flags: --toolsets, --read-only, --gh-host, --log-file
277276

278277
## Important Reminders
279278

.github/workflows/mcp-diff.yml

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ jobs:
3434
[
3535
{"name": "default", "args": ""},
3636
{"name": "read-only", "args": "--read-only"},
37-
{"name": "dynamic-toolsets", "args": "--dynamic-toolsets"},
38-
{"name": "read-only+dynamic", "args": "--read-only --dynamic-toolsets"},
3937
{"name": "toolsets-repos", "args": "--toolsets=repos"},
4038
{"name": "toolsets-issues", "args": "--toolsets=issues"},
4139
{"name": "toolsets-context", "args": "--toolsets=context"},
@@ -45,20 +43,7 @@ jobs:
4543
{"name": "toolsets-all", "args": "--toolsets=all"},
4644
{"name": "tools-get_me", "args": "--tools=get_me"},
4745
{"name": "tools-get_me,list_issues", "args": "--tools=get_me,list_issues"},
48-
{"name": "toolsets-repos+read-only", "args": "--toolsets=repos --read-only"},
49-
{"name": "toolsets-all+dynamic", "args": "--toolsets=all --dynamic-toolsets"},
50-
{"name": "toolsets-repos+dynamic", "args": "--toolsets=repos --dynamic-toolsets"},
51-
{"name": "toolsets-repos,issues+dynamic", "args": "--toolsets=repos,issues --dynamic-toolsets"},
52-
{
53-
"name": "dynamic-tool-calls",
54-
"args": "--dynamic-toolsets",
55-
"custom_messages": [
56-
{"id": 10, "name": "list_toolsets_before", "message": {"jsonrpc": "2.0", "id": 10, "method": "tools/call", "params": {"name": "list_available_toolsets", "arguments": {}}}},
57-
{"id": 11, "name": "get_toolset_tools", "message": {"jsonrpc": "2.0", "id": 11, "method": "tools/call", "params": {"name": "get_toolset_tools", "arguments": {"toolset": "repos"}}}},
58-
{"id": 12, "name": "enable_toolset", "message": {"jsonrpc": "2.0", "id": 12, "method": "tools/call", "params": {"name": "enable_toolset", "arguments": {"toolset": "repos"}}}},
59-
{"id": 13, "name": "list_toolsets_after", "message": {"jsonrpc": "2.0", "id": 13, "method": "tools/call", "params": {"name": "list_available_toolsets", "arguments": {}}}}
60-
]
61-
}
46+
{"name": "toolsets-repos+read-only", "args": "--toolsets=repos --read-only"}
6247
]
6348
6449
- name: Add interpretation note

README.md

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ The environment variable `GITHUB_TOOLSETS` takes precedence over the command lin
424424

425425
#### Specifying Individual Tools
426426

427-
You can also configure specific tools using the `--tools` flag. Tools can be used independently or combined with toolsets and dynamic toolsets discovery for fine-grained control.
427+
You can also configure specific tools using the `--tools` flag. Tools can be used independently or combined with toolsets for fine-grained control.
428428

429429
1. **Using Command Line Argument**:
430430

@@ -446,17 +446,9 @@ You can also configure specific tools using the `--tools` flag. Tools can be use
446446

447447
This registers all tools from `repos` and `issues` toolsets, plus `get_gist`.
448448

449-
4. **Combining with Dynamic Toolsets** (additive):
450-
451-
```bash
452-
github-mcp-server --tools get_file_contents --dynamic-toolsets
453-
```
454-
455-
This registers `get_file_contents` plus the dynamic toolset tools (`enable_toolset`, `list_available_toolsets`, `get_toolset_tools`).
456-
457449
**Important Notes:**
458450

459-
- Tools, toolsets, and dynamic toolsets can all be used together
451+
- Tools and toolsets can be used together
460452
- Read-only mode takes priority: write tools are skipped if `--read-only` is set, even if explicitly requested via `--tools`
461453
- Tool names must match exactly (e.g., `get_file_contents`, not `getFileContents`). Invalid tool names will cause the server to fail at startup with an error message
462454
- When tools are renamed, old names are preserved as aliases for backward compatibility. See [Tool Renaming](docs/tool-renaming.md) for details.
@@ -1462,29 +1454,6 @@ The following sets of tools are available:
14621454

14631455
</details>
14641456

1465-
## Dynamic Tool Discovery
1466-
1467-
**Note**: This feature is currently in beta and is not available in the Remote GitHub MCP Server. Please test it out and let us know if you encounter any issues.
1468-
1469-
Instead of starting with all tools enabled, you can turn on dynamic toolset discovery. Dynamic toolsets allow the MCP host to list and enable toolsets in response to a user prompt. This should help to avoid situations where the model gets confused by the sheer number of tools available.
1470-
1471-
### Using Dynamic Tool Discovery
1472-
1473-
When using the binary, you can pass the `--dynamic-toolsets` flag.
1474-
1475-
```bash
1476-
./github-mcp-server --dynamic-toolsets
1477-
```
1478-
1479-
When using Docker, you can pass the toolsets as environment variables:
1480-
1481-
```bash
1482-
docker run -i --rm \
1483-
-e GITHUB_PERSONAL_ACCESS_TOKEN=<your-token> \
1484-
-e GITHUB_DYNAMIC_TOOLSETS=1 \
1485-
ghcr.io/github/github-mcp-server
1486-
```
1487-
14881457
## Read-Only Mode
14891458

14901459
To run the server in read-only mode, you can use the `--read-only` flag. This will only offer read-only tools, preventing any modifications to repositories, issues, pull requests, etc.

cmd/github-mcp-server/generate_docs.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ func generateToolsetsDoc(i *inventory.Inventory) string {
145145
fmt.Fprintf(&buf, "| %s | `context` | **Strongly recommended**: Tools that provide context about the current user and GitHub context you are operating in |\n", contextIcon)
146146

147147
// AvailableToolsets() returns toolsets that have tools, sorted by ID
148-
// Exclude context (custom description above) and dynamic (internal only)
149-
for _, ts := range i.AvailableToolsets("context", "dynamic") {
148+
// Exclude context (custom description above)
149+
for _, ts := range i.AvailableToolsets("context") {
150150
icon := octiconImg(ts.Icon)
151151
fmt.Fprintf(&buf, "| %s | `%s` | %s |\n", icon, ts.ID, ts.Description)
152152
}
@@ -346,8 +346,8 @@ func generateRemoteToolsetsDoc() string {
346346
fmt.Fprintf(&buf, "| %s<br>`all` | All available GitHub MCP tools | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%%7B%%22type%%22%%3A%%20%%22http%%22%%2C%%22url%%22%%3A%%20%%22https%%3A%%2F%%2Fapi.githubcopilot.com%%2Fmcp%%2F%%22%%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%%7B%%22type%%22%%3A%%20%%22http%%22%%2C%%22url%%22%%3A%%20%%22https%%3A%%2F%%2Fapi.githubcopilot.com%%2Fmcp%%2Freadonly%%22%%7D) |\n", allIcon)
347347

348348
// AvailableToolsets() returns toolsets that have tools, sorted by ID
349-
// Exclude context (handled separately) and dynamic (internal only)
350-
for _, ts := range r.AvailableToolsets("context", "dynamic") {
349+
// Exclude context (handled separately)
350+
for _, ts := range r.AvailableToolsets("context") {
351351
idStr := string(ts.ID)
352352

353353
apiURL := fmt.Sprintf("https://api.githubcopilot.com/mcp/x/%s", idStr)

cmd/github-mcp-server/main.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ var (
8585
EnabledToolsets: enabledToolsets,
8686
EnabledTools: enabledTools,
8787
EnabledFeatures: enabledFeatures,
88-
DynamicToolsets: viper.GetBool("dynamic_toolsets"),
8988
ReadOnly: viper.GetBool("read-only"),
9089
ExportTranslations: viper.GetBool("export-translations"),
9190
EnableCommandLogging: viper.GetBool("enable-command-logging"),
@@ -144,7 +143,6 @@ var (
144143
ReadOnly: viper.GetBool("read-only"),
145144
EnabledToolsets: enabledToolsets,
146145
EnabledTools: enabledTools,
147-
DynamicToolsets: viper.GetBool("dynamic_toolsets"),
148146
ExcludeTools: excludeTools,
149147
InsidersMode: viper.GetBool("insiders"),
150148
}
@@ -165,7 +163,6 @@ func init() {
165163
rootCmd.PersistentFlags().StringSlice("tools", nil, "Comma-separated list of specific tools to enable")
166164
rootCmd.PersistentFlags().StringSlice("exclude-tools", nil, "Comma-separated list of tool names to disable regardless of other settings")
167165
rootCmd.PersistentFlags().StringSlice("features", nil, "Comma-separated list of feature flags to enable")
168-
rootCmd.PersistentFlags().Bool("dynamic-toolsets", false, "Enable dynamic toolsets")
169166
rootCmd.PersistentFlags().Bool("read-only", false, "Restrict the server to read-only operations")
170167
rootCmd.PersistentFlags().String("log-file", "", "Path to log file")
171168
rootCmd.PersistentFlags().Bool("enable-command-logging", false, "When enabled, the server will log all command requests and responses to the log file")
@@ -187,7 +184,6 @@ func init() {
187184
_ = viper.BindPFlag("tools", rootCmd.PersistentFlags().Lookup("tools"))
188185
_ = viper.BindPFlag("exclude_tools", rootCmd.PersistentFlags().Lookup("exclude-tools"))
189186
_ = viper.BindPFlag("features", rootCmd.PersistentFlags().Lookup("features"))
190-
_ = viper.BindPFlag("dynamic_toolsets", rootCmd.PersistentFlags().Lookup("dynamic-toolsets"))
191187
_ = viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only"))
192188
_ = viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file"))
193189
_ = viper.BindPFlag("enable-command-logging", rootCmd.PersistentFlags().Lookup("enable-command-logging"))

docs/installation-guides/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,5 @@ If you encounter issues:
104104
After installation, you may want to explore:
105105
- **Toolsets**: Enable/disable specific GitHub API capabilities
106106
- **Read-Only Mode**: Restrict to read-only operations
107-
- **Dynamic Tool Discovery**: Enable tools on-demand
108107
- **Lockdown Mode**: Hide public issue details created by users without push access
109108

docs/server-configuration.md

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ We currently support the following ways in which the GitHub MCP Server can be co
1111
| Individual Tools | `X-MCP-Tools` header | `--tools` flag or `GITHUB_TOOLS` env var |
1212
| Exclude Tools | `X-MCP-Exclude-Tools` header | `--exclude-tools` flag or `GITHUB_EXCLUDE_TOOLS` env var |
1313
| Read-Only Mode | `X-MCP-Readonly` header or `/readonly` URL | `--read-only` flag or `GITHUB_READ_ONLY` env var |
14-
| Dynamic Mode | Not available | `--dynamic-toolsets` flag or `GITHUB_DYNAMIC_TOOLSETS` env var |
1514
| Lockdown Mode | `X-MCP-Lockdown` header | `--lockdown-mode` flag or `GITHUB_LOCKDOWN_MODE` env var |
1615
| Insiders Mode | `X-MCP-Insiders` header or `/insiders` URL | `--insiders` flag or `GITHUB_INSIDERS` env var |
1716
| Feature Flags | `X-MCP-Features` header | `--features` flag |
@@ -24,7 +23,7 @@ We currently support the following ways in which the GitHub MCP Server can be co
2423

2524
## How Configuration Works
2625

27-
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.
26+
All configuration options are **composable**: you can combine toolsets, individual tools, excluded tools, read-only mode and lockdown mode in any way that suits your workflow.
2827

2928
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.
3029

@@ -287,59 +286,6 @@ When active, this mode will disable all tools that are not read-only even if the
287286
288287
---
289288

290-
### Dynamic Discovery (Local Only)
291-
292-
**Best for:** Letting the LLM discover and enable toolsets as needed.
293-
294-
Starts with only discovery tools (`enable_toolset`, `list_available_toolsets`, `get_toolset_tools`), then expands on demand.
295-
296-
<table>
297-
<tr><th>Local Server Only</th></tr>
298-
<tr valign="top">
299-
<td>
300-
301-
```json
302-
{
303-
"type": "stdio",
304-
"command": "go",
305-
"args": [
306-
"run",
307-
"./cmd/github-mcp-server",
308-
"stdio",
309-
"--dynamic-toolsets"
310-
],
311-
"env": {
312-
"GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
313-
}
314-
}
315-
```
316-
317-
**With some tools pre-enabled:**
318-
```json
319-
{
320-
"type": "stdio",
321-
"command": "go",
322-
"args": [
323-
"run",
324-
"./cmd/github-mcp-server",
325-
"stdio",
326-
"--dynamic-toolsets",
327-
"--tools=get_me,search_code"
328-
],
329-
"env": {
330-
"GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
331-
}
332-
}
333-
```
334-
335-
</td>
336-
</tr>
337-
</table>
338-
339-
When both dynamic mode and specific tools are enabled in the server configuration, the server will start with the 3 dynamic tools + the specified tools.
340-
341-
---
342-
343289
### Lockdown Mode
344290

345291
**Best for:** Public repositories where you want to limit content from users without push access.
@@ -521,7 +467,6 @@ See [Scope Filtering](./scope-filtering.md) for details on how filtering works w
521467
| Server fails to start | Invalid tool name in `--tools` or `X-MCP-Tools` | Check tool name spelling; use exact names from [Tools list](../README.md#tools) |
522468
| Write tools not working | Read-only mode enabled | Remove `--read-only` flag or `X-MCP-Readonly` header |
523469
| Tools missing | Toolset not enabled | Add the required toolset or specific tool |
524-
| Dynamic tools not available | Using remote server | Dynamic mode is available in the local MCP server only |
525470

526471
---
527472

docs/toolsets-and-icons.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ icons := octicons.Icons("repo")
161161
| Labels | `tag` |
162162
| Stargazers | `star` |
163163
| Notifications | `bell` |
164-
| Dynamic | `tools` |
165164
| Copilot | `copilot` |
166165
| Support Search | `book` |
167166

internal/ghmcp/server.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func NewStdioMCPServer(ctx context.Context, cfg github.MCPServerConfig) (*mcp.Se
153153
inventoryBuilder := github.NewInventory(cfg.Translator).
154154
WithDeprecatedAliases(github.DeprecatedToolAliases).
155155
WithReadOnly(cfg.ReadOnly).
156-
WithToolsets(github.ResolvedEnabledToolsets(cfg.DynamicToolsets, cfg.EnabledToolsets, cfg.EnabledTools)).
156+
WithToolsets(github.ResolvedEnabledToolsets(cfg.EnabledToolsets, cfg.EnabledTools)).
157157
WithTools(github.CleanTools(cfg.EnabledTools)).
158158
WithExcludeTools(cfg.ExcludeTools).
159159
WithServerInstructions().
@@ -210,10 +210,6 @@ type StdioServerConfig struct {
210210
// Items with FeatureFlagEnable matching an entry in this list will be available
211211
EnabledFeatures []string
212212

213-
// Whether to enable dynamic toolsets
214-
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#dynamic-tool-discovery
215-
DynamicToolsets bool
216-
217213
// ReadOnly indicates if we should only register read-only tools
218214
ReadOnly bool
219215

@@ -267,7 +263,7 @@ func RunStdioServer(cfg StdioServerConfig) error {
267263
slogHandler = slog.NewTextHandler(logOutput, &slog.HandlerOptions{Level: slog.LevelInfo})
268264
}
269265
logger := slog.New(slogHandler)
270-
logger.Info("starting server", "version", cfg.Version, "host", cfg.Host, "dynamicToolsets", cfg.DynamicToolsets, "readOnly", cfg.ReadOnly, "lockdownEnabled", cfg.LockdownMode)
266+
logger.Info("starting server", "version", cfg.Version, "host", cfg.Host, "readOnly", cfg.ReadOnly, "lockdownEnabled", cfg.LockdownMode)
271267

272268
// Fetch token scopes for scope-based tool filtering (PAT tokens only)
273269
// Only classic PATs (ghp_ prefix) return OAuth scopes via X-OAuth-Scopes header.
@@ -292,7 +288,6 @@ func RunStdioServer(cfg StdioServerConfig) error {
292288
EnabledToolsets: cfg.EnabledToolsets,
293289
EnabledTools: cfg.EnabledTools,
294290
EnabledFeatures: cfg.EnabledFeatures,
295-
DynamicToolsets: cfg.DynamicToolsets,
296291
ReadOnly: cfg.ReadOnly,
297292
Translator: t,
298293
ContentWindowSize: cfg.ContentWindowSize,

0 commit comments

Comments
 (0)