Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3e1fca0

Browse files
authored
Tommy/tool-specific-config-support (#1394)
* add enabledTools to StdioServerConfig* add EnabledTools to MCPServerConfig, and logic to bypass toolset config if present* add logic to register specific tools* update readme* Update to be consistent with:https://docs.google.com/document/d/1tOOBJ4y9xY61QVrO18ymuVt4SO9nV-z2B4ckaL2f9IU/edit?tab=t.0#heading=h.ffto4e5dwzlfspecifically- allow for --tools and dynamic toolset mode together- allow for --tools and --toolsets together* go mod tidy* update* clean up comment* fix* fix* updte* update* clean up
1 parent7cfb354 commit3e1fca0

File tree

5 files changed

+181
-7
lines changed

5 files changed

+181
-7
lines changed

‎README.md‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,38 @@ To specify toolsets you want available to the LLM, you can pass an allow-list in
345345

346346
The environment variable`GITHUB_TOOLSETS` takes precedence over the command line argument if both are provided.
347347

348+
####Specifying Individual Tools
349+
350+
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.
351+
352+
1.**Using Command Line Argument**:
353+
354+
```bash
355+
github-mcp-server --tools get_file_contents,issue_read,create_pull_request
356+
```
357+
358+
2.**Using Environment Variable**:
359+
```bash
360+
GITHUB_TOOLS="get_file_contents,issue_read,create_pull_request" ./github-mcp-server
361+
```
362+
363+
3.**Combining with Toolsets** (additive):
364+
```bash
365+
github-mcp-server --toolsets repos,issues --tools get_gist
366+
```
367+
This registers all tools from`repos` and`issues` toolsets, plus`get_gist`.
368+
369+
4.**Combining with Dynamic Toolsets** (additive):
370+
```bash
371+
github-mcp-server --tools get_file_contents --dynamic-toolsets
372+
```
373+
This registers`get_file_contents` plus the dynamic toolset tools (`enable_toolset`,`list_available_toolsets`,`get_toolset_tools`).
374+
375+
**Important Notes:**
376+
- Tools, toolsets, and dynamic toolsets can all be used together
377+
- Read-only mode takes priority: write tools are skipped if`--read-only` is set, even if explicitly requested via`--tools`
378+
- 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
379+
348380
###Using Toolsets With Docker
349381

350382
When using Docker, you can pass the toolsets as environment variables:
@@ -356,6 +388,25 @@ docker run -i --rm \
356388
ghcr.io/github/github-mcp-server
357389
```
358390

391+
###Using Tools With Docker
392+
393+
When using Docker, you can pass specific tools as environment variables. You can also combine tools with toolsets:
394+
395+
```bash
396+
# Tools only
397+
docker run -i --rm \
398+
-e GITHUB_PERSONAL_ACCESS_TOKEN=<your-token> \
399+
-e GITHUB_TOOLS="get_file_contents,issue_read,create_pull_request" \
400+
ghcr.io/github/github-mcp-server
401+
402+
# Tools combined with toolsets (additive)
403+
docker run -i --rm \
404+
-e GITHUB_PERSONAL_ACCESS_TOKEN=<your-token> \
405+
-e GITHUB_TOOLSETS="repos,issues" \
406+
-e GITHUB_TOOLS="get_gist" \
407+
ghcr.io/github/github-mcp-server
408+
```
409+
359410
###Special toolsets
360411

361412
####"all" toolset

‎cmd/github-mcp-server/main.go‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,14 @@ var (
4646
returnfmt.Errorf("failed to unmarshal toolsets: %w",err)
4747
}
4848

49-
// No passed toolsets configuration means we enable the default toolset
50-
iflen(enabledToolsets)==0 {
49+
// Parse tools (similar to toolsets)
50+
varenabledTools []string
51+
iferr:=viper.UnmarshalKey("tools",&enabledTools);err!=nil {
52+
returnfmt.Errorf("failed to unmarshal tools: %w",err)
53+
}
54+
55+
// If neither toolset config nor tools config is passed we enable the default toolset
56+
iflen(enabledToolsets)==0&&len(enabledTools)==0 {
5157
enabledToolsets= []string{github.ToolsetMetadataDefault.ID}
5258
}
5359

@@ -57,6 +63,7 @@ var (
5763
Host:viper.GetString("host"),
5864
Token:token,
5965
EnabledToolsets:enabledToolsets,
66+
EnabledTools:enabledTools,
6067
DynamicToolsets:viper.GetBool("dynamic_toolsets"),
6168
ReadOnly:viper.GetBool("read-only"),
6269
ExportTranslations:viper.GetBool("export-translations"),
@@ -79,6 +86,7 @@ func init() {
7986

8087
// Add global flags that will be shared by all commands
8188
rootCmd.PersistentFlags().StringSlice("toolsets",nil,github.GenerateToolsetsHelp())
89+
rootCmd.PersistentFlags().StringSlice("tools",nil,"Comma-separated list of specific tools to enable")
8290
rootCmd.PersistentFlags().Bool("dynamic-toolsets",false,"Enable dynamic toolsets")
8391
rootCmd.PersistentFlags().Bool("read-only",false,"Restrict the server to read-only operations")
8492
rootCmd.PersistentFlags().String("log-file","","Path to log file")
@@ -91,6 +99,7 @@ func init() {
9199

92100
// Bind flag to viper
93101
_=viper.BindPFlag("toolsets",rootCmd.PersistentFlags().Lookup("toolsets"))
102+
_=viper.BindPFlag("tools",rootCmd.PersistentFlags().Lookup("tools"))
94103
_=viper.BindPFlag("dynamic_toolsets",rootCmd.PersistentFlags().Lookup("dynamic-toolsets"))
95104
_=viper.BindPFlag("read-only",rootCmd.PersistentFlags().Lookup("read-only"))
96105
_=viper.BindPFlag("log-file",rootCmd.PersistentFlags().Lookup("log-file"))

‎internal/ghmcp/server.go‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ type MCPServerConfig struct {
4040
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#tool-configuration
4141
EnabledToolsets []string
4242

43+
// EnabledTools is a list of specific tools to enable (additive to toolsets)
44+
// When specified, these tools are registered in addition to any specified toolset tools
45+
EnabledTools []string
46+
4347
// Whether to enable dynamic toolsets
4448
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#dynamic-tool-discovery
4549
DynamicToolsetsbool
@@ -182,15 +186,32 @@ func NewMCPServer(cfg MCPServerConfig, logger *slog.Logger) (*server.MCPServer,
182186
github.FeatureFlags{LockdownMode:cfg.LockdownMode},
183187
repoAccessCache,
184188
)
185-
err=tsg.EnableToolsets(enabledToolsets,nil)
186189

187-
iferr!=nil {
188-
returnnil,fmt.Errorf("failed to enable toolsets: %w",err)
190+
// Enable and register toolsets if configured
191+
// This always happens if toolsets are specified, regardless of whether tools are also specified
192+
iflen(enabledToolsets)>0 {
193+
err=tsg.EnableToolsets(enabledToolsets,nil)
194+
iferr!=nil {
195+
returnnil,fmt.Errorf("failed to enable toolsets: %w",err)
196+
}
197+
198+
// Register all mcp functionality with the server
199+
tsg.RegisterAll(ghServer)
189200
}
190201

191-
// Register all mcp functionality with the server
192-
tsg.RegisterAll(ghServer)
202+
// Register specific tools if configured
203+
iflen(cfg.EnabledTools)>0 {
204+
// Clean and validate tool names
205+
enabledTools:=github.CleanTools(cfg.EnabledTools)
193206

207+
// Register the specified tools (additive to any toolsets already enabled)
208+
err=tsg.RegisterSpecificTools(ghServer,enabledTools,cfg.ReadOnly)
209+
iferr!=nil {
210+
returnnil,fmt.Errorf("failed to register tools: %w",err)
211+
}
212+
}
213+
214+
// Register dynamic toolsets if configured (additive to toolsets and tools)
194215
ifcfg.DynamicToolsets {
195216
dynamic:=github.InitDynamicToolset(ghServer,tsg,cfg.Translator)
196217
dynamic.RegisterTools(ghServer)
@@ -213,6 +234,10 @@ type StdioServerConfig struct {
213234
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#tool-configuration
214235
EnabledToolsets []string
215236

237+
// EnabledTools is a list of specific tools to enable (additive to toolsets)
238+
// When specified, these tools are registered in addition to any specified toolset tools
239+
EnabledTools []string
240+
216241
// Whether to enable dynamic toolsets
217242
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#dynamic-tool-discovery
218243
DynamicToolsetsbool
@@ -270,6 +295,7 @@ func RunStdioServer(cfg StdioServerConfig) error {
270295
Host:cfg.Host,
271296
Token:cfg.Token,
272297
EnabledToolsets:cfg.EnabledToolsets,
298+
EnabledTools:cfg.EnabledTools,
273299
DynamicToolsets:cfg.DynamicToolsets,
274300
ReadOnly:cfg.ReadOnly,
275301
Translator:t,

‎pkg/github/tools.go‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,24 @@ func ContainsToolset(tools []string, toCheck string) bool {
524524
}
525525
returnfalse
526526
}
527+
528+
// CleanTools cleans tool names by removing duplicates and trimming whitespace.
529+
// Validation of tool existence is done during registration.
530+
funcCleanTools(toolNames []string) []string {
531+
seen:=make(map[string]bool)
532+
result:=make([]string,0,len(toolNames))
533+
534+
// Remove duplicates and trim whitespace
535+
for_,tool:=rangetoolNames {
536+
trimmed:=strings.TrimSpace(tool)
537+
iftrimmed=="" {
538+
continue
539+
}
540+
if!seen[trimmed] {
541+
seen[trimmed]=true
542+
result=append(result,trimmed)
543+
}
544+
}
545+
546+
returnresult
547+
}

‎pkg/toolsets/toolsets.go‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package toolsets
22

33
import (
44
"fmt"
5+
"os"
6+
"strings"
57

68
"github.com/mark3labs/mcp-go/mcp"
79
"github.com/mark3labs/mcp-go/server"
@@ -263,3 +265,68 @@ func (tg *ToolsetGroup) GetToolset(name string) (*Toolset, error) {
263265
}
264266
returntoolset,nil
265267
}
268+
269+
typeToolDoesNotExistErrorstruct {
270+
Namestring
271+
}
272+
273+
func (e*ToolDoesNotExistError)Error()string {
274+
returnfmt.Sprintf("tool %s does not exist",e.Name)
275+
}
276+
277+
funcNewToolDoesNotExistError(namestring)*ToolDoesNotExistError {
278+
return&ToolDoesNotExistError{Name:name}
279+
}
280+
281+
// FindToolByName searches all toolsets (enabled or disabled) for a tool by name.
282+
// Returns the tool, its parent toolset name, and an error if not found.
283+
func (tg*ToolsetGroup)FindToolByName(toolNamestring) (*server.ServerTool,string,error) {
284+
fortoolsetName,toolset:=rangetg.Toolsets {
285+
// Check read tools
286+
for_,tool:=rangetoolset.readTools {
287+
iftool.Tool.Name==toolName {
288+
return&tool,toolsetName,nil
289+
}
290+
}
291+
// Check write tools
292+
for_,tool:=rangetoolset.writeTools {
293+
iftool.Tool.Name==toolName {
294+
return&tool,toolsetName,nil
295+
}
296+
}
297+
}
298+
returnnil,"",NewToolDoesNotExistError(toolName)
299+
}
300+
301+
// RegisterSpecificTools registers only the specified tools.
302+
// Respects read-only mode (skips write tools if readOnly=true).
303+
// Returns error if any tool is not found.
304+
func (tg*ToolsetGroup)RegisterSpecificTools(s*server.MCPServer,toolNames []string,readOnlybool)error {
305+
varskippedTools []string
306+
for_,toolName:=rangetoolNames {
307+
tool,_,err:=tg.FindToolByName(toolName)
308+
iferr!=nil {
309+
returnfmt.Errorf("tool %s not found: %w",toolName,err)
310+
}
311+
312+
// Check if it's a write tool and we're in read-only mode
313+
iftool.Tool.Annotations.ReadOnlyHint!=nil {
314+
isWriteTool:=!*tool.Tool.Annotations.ReadOnlyHint
315+
ifisWriteTool&&readOnly {
316+
// Skip write tools in read-only mode
317+
skippedTools=append(skippedTools,toolName)
318+
continue
319+
}
320+
}
321+
322+
// Register the tool
323+
s.AddTool(tool.Tool,tool.Handler)
324+
}
325+
326+
// Log skipped write tools if any
327+
iflen(skippedTools)>0 {
328+
fmt.Fprintf(os.Stderr,"Write tools skipped due to read-only mode: %s\n",strings.Join(skippedTools,", "))
329+
}
330+
331+
returnnil
332+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp