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

Commit30ce29b

Browse files
feat: partition tools by product/feature
1 parent651a3aa commit30ce29b

File tree

5 files changed

+540
-49
lines changed

5 files changed

+540
-49
lines changed

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import (
77
stdlog"log"
88
"os"
99
"os/signal"
10+
"strings"
1011
"syscall"
1112

1213
"github.com/github/github-mcp-server/pkg/github"
1314
iolog"github.com/github/github-mcp-server/pkg/log"
15+
"github.com/github/github-mcp-server/pkg/toolsets"
1416
"github.com/github/github-mcp-server/pkg/translations"
1517
gogithub"github.com/google/go-github/v69/github"
1618
"github.com/mark3labs/mcp-go/server"
@@ -43,12 +45,19 @@ var (
4345
iferr!=nil {
4446
stdlog.Fatal("Failed to initialize logger:",err)
4547
}
48+
enabledToolsets:=viper.GetStringSlice("features")
49+
features,err:=initToolsets(enabledToolsets)
50+
iferr!=nil {
51+
stdlog.Fatal("Failed to initialize features:",err)
52+
}
53+
4654
logCommands:=viper.GetBool("enable-command-logging")
4755
cfg:=runConfig{
4856
readOnly:readOnly,
4957
logger:logger,
5058
logCommands:logCommands,
5159
exportTranslations:exportTranslations,
60+
features:features,
5261
}
5362
iferr:=runStdioServer(cfg);err!=nil {
5463
stdlog.Fatal("failed to run stdio server:",err)
@@ -57,17 +66,53 @@ var (
5766
}
5867
)
5968

69+
funcinitToolsets(passedToolsets []string) (*toolsets.ToolsetGroup,error) {
70+
// Create a new toolset group
71+
fs:=toolsets.NewToolsetGroup()
72+
73+
// Define all available features with their default state (disabled)
74+
fs.AddToolset("repos","Repository related tools",false)
75+
fs.AddToolset("issues","Issues related tools",false)
76+
fs.AddToolset("search","Search related tools",false)
77+
fs.AddToolset("pull_requests","Pull request related tools",false)
78+
fs.AddToolset("code_security","Code security related tools",false)
79+
fs.AddToolset("experiments","Experimental features that are not considered stable yet",false)
80+
81+
// fs.AddFeature("actions", "GitHub Actions related tools", false)
82+
// fs.AddFeature("projects", "GitHub Projects related tools", false)
83+
// fs.AddFeature("secret_protection", "Secret protection related tools", false)
84+
// fs.AddFeature("gists", "Gist related tools", false)
85+
86+
// Env gets precedence over command line flags
87+
ifenvFeats:=os.Getenv("GITHUB_FEATURES");envFeats!="" {
88+
passedToolsets= []string{}
89+
// Split envFeats by comma, trim whitespace, and add to the slice
90+
for_,feature:=rangestrings.Split(envFeats,",") {
91+
passedToolsets=append(passedToolsets,strings.TrimSpace(feature))
92+
}
93+
}
94+
95+
// Enable the requested features
96+
iferr:=fs.EnableToolsets(passedToolsets);err!=nil {
97+
returnnil,err
98+
}
99+
100+
returnfs,nil
101+
}
102+
60103
funcinit() {
61104
cobra.OnInitialize(initConfig)
62105

63106
// Add global flags that will be shared by all commands
107+
rootCmd.PersistentFlags().StringSlice("features", []string{"repos","issues","pull_requests","search"},"A comma separated list of groups of tools to enable, defaults to issues/repos/search")
64108
rootCmd.PersistentFlags().Bool("read-only",false,"Restrict the server to read-only operations")
65109
rootCmd.PersistentFlags().String("log-file","","Path to log file")
66110
rootCmd.PersistentFlags().Bool("enable-command-logging",false,"When enabled, the server will log all command requests and responses to the log file")
67111
rootCmd.PersistentFlags().Bool("export-translations",false,"Save translations to a JSON file")
68112
rootCmd.PersistentFlags().String("gh-host","","Specify the GitHub hostname (for GitHub Enterprise etc.)")
69113

70114
// Bind flag to viper
115+
_=viper.BindPFlag("features",rootCmd.PersistentFlags().Lookup("features"))
71116
_=viper.BindPFlag("read-only",rootCmd.PersistentFlags().Lookup("read-only"))
72117
_=viper.BindPFlag("log-file",rootCmd.PersistentFlags().Lookup("log-file"))
73118
_=viper.BindPFlag("enable-command-logging",rootCmd.PersistentFlags().Lookup("enable-command-logging"))
@@ -106,6 +151,7 @@ type runConfig struct {
106151
logger*log.Logger
107152
logCommandsbool
108153
exportTranslationsbool
154+
features*toolsets.ToolsetGroup
109155
}
110156

111157
funcrunStdioServer(cfgrunConfig)error {
@@ -141,7 +187,7 @@ func runStdioServer(cfg runConfig) error {
141187
returnghClient,nil// closing over client
142188
}
143189
// Create
144-
ghServer:=github.NewServer(getClient,version,cfg.readOnly,t)
190+
ghServer:=github.NewServer(getClient,cfg.features,version,cfg.readOnly,t)
145191
stdioServer:=server.NewStdioServer(ghServer)
146192

147193
stdLogger:=stdlog.New(cfg.logger.Writer(),"stdioserver",0)

‎pkg/github/server.go

Lines changed: 106 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"net/http"
1010

11+
"github.com/github/github-mcp-server/pkg/toolsets"
1112
"github.com/github/github-mcp-server/pkg/translations"
1213
"github.com/google/go-github/v69/github"
1314
"github.com/mark3labs/mcp-go/mcp"
@@ -17,69 +18,84 @@ import (
1718
typeGetClientFnfunc(context.Context) (*github.Client,error)
1819

1920
// NewServer creates a new GitHub MCP server with the specified GH client and logger.
20-
funcNewServer(getClientGetClientFn,versionstring,readOnlybool,t translations.TranslationHelperFunc)*server.MCPServer {
21+
funcNewServer(getClientGetClientFn,toolsetGroup*toolsets.ToolsetGroup,versionstring,readOnlybool,t translations.TranslationHelperFunc)*server.MCPServer {
2122
// Create a new MCP server
2223
s:=server.NewMCPServer(
2324
"github-mcp-server",
2425
version,
2526
server.WithResourceCapabilities(true,true),
2627
server.WithLogging())
2728

28-
// Add GitHub Resources
29-
s.AddResourceTemplate(GetRepositoryResourceContent(getClient,t))
30-
s.AddResourceTemplate(GetRepositoryResourceBranchContent(getClient,t))
31-
s.AddResourceTemplate(GetRepositoryResourceCommitContent(getClient,t))
32-
s.AddResourceTemplate(GetRepositoryResourceTagContent(getClient,t))
33-
s.AddResourceTemplate(GetRepositoryResourcePrContent(getClient,t))
34-
35-
// Add GitHub tools - Issues
36-
s.AddTool(GetIssue(getClient,t))
37-
s.AddTool(SearchIssues(getClient,t))
38-
s.AddTool(ListIssues(getClient,t))
39-
s.AddTool(GetIssueComments(getClient,t))
40-
if!readOnly {
41-
s.AddTool(CreateIssue(getClient,t))
42-
s.AddTool(AddIssueComment(getClient,t))
43-
s.AddTool(UpdateIssue(getClient,t))
29+
// Add GitHub tools - Users
30+
s.AddTool(GetMe(getClient,t))// GetMe is always exposed and not part of configurable features
31+
32+
iftoolsetGroup.IsEnabled("repos") {
33+
// Add GitHub Repository Resources
34+
s.AddResourceTemplate(GetRepositoryResourceContent(getClient,t))
35+
s.AddResourceTemplate(GetRepositoryResourceBranchContent(getClient,t))
36+
s.AddResourceTemplate(GetRepositoryResourceCommitContent(getClient,t))
37+
s.AddResourceTemplate(GetRepositoryResourceTagContent(getClient,t))
38+
s.AddResourceTemplate(GetRepositoryResourcePrContent(getClient,t))
39+
40+
// Add GitHub tools - Repositories
41+
s.AddTool(SearchRepositories(getClient,t))
42+
s.AddTool(GetFileContents(getClient,t))
43+
s.AddTool(ListCommits(getClient,t))
44+
if!readOnly {
45+
s.AddTool(CreateOrUpdateFile(getClient,t))
46+
s.AddTool(CreateRepository(getClient,t))
47+
s.AddTool(ForkRepository(getClient,t))
48+
s.AddTool(CreateBranch(getClient,t))
49+
s.AddTool(PushFiles(getClient,t))
50+
}
4451
}
4552

46-
// Add GitHub tools - Pull Requests
47-
s.AddTool(GetPullRequest(getClient,t))
48-
s.AddTool(ListPullRequests(getClient,t))
49-
s.AddTool(GetPullRequestFiles(getClient,t))
50-
s.AddTool(GetPullRequestStatus(getClient,t))
51-
s.AddTool(GetPullRequestComments(getClient,t))
52-
s.AddTool(GetPullRequestReviews(getClient,t))
53-
if!readOnly {
54-
s.AddTool(MergePullRequest(getClient,t))
55-
s.AddTool(UpdatePullRequestBranch(getClient,t))
56-
s.AddTool(CreatePullRequestReview(getClient,t))
57-
s.AddTool(CreatePullRequest(getClient,t))
58-
s.AddTool(UpdatePullRequest(getClient,t))
53+
iftoolsetGroup.IsEnabled("issues") {
54+
// Add GitHub tools - Issues
55+
s.AddTool(GetIssue(getClient,t))
56+
s.AddTool(SearchIssues(getClient,t))
57+
s.AddTool(ListIssues(getClient,t))
58+
s.AddTool(GetIssueComments(getClient,t))
59+
if!readOnly {
60+
s.AddTool(CreateIssue(getClient,t))
61+
s.AddTool(AddIssueComment(getClient,t))
62+
s.AddTool(UpdateIssue(getClient,t))
63+
}
5964
}
6065

61-
// Add GitHub tools - Repositories
62-
s.AddTool(SearchRepositories(getClient,t))
63-
s.AddTool(GetFileContents(getClient,t))
64-
s.AddTool(ListCommits(getClient,t))
65-
if!readOnly {
66-
s.AddTool(CreateOrUpdateFile(getClient,t))
67-
s.AddTool(CreateRepository(getClient,t))
68-
s.AddTool(ForkRepository(getClient,t))
69-
s.AddTool(CreateBranch(getClient,t))
70-
s.AddTool(PushFiles(getClient,t))
66+
iftoolsetGroup.IsEnabled("pull_requests") {
67+
// Add GitHub tools - Pull Requests
68+
s.AddTool(GetPullRequest(getClient,t))
69+
s.AddTool(ListPullRequests(getClient,t))
70+
s.AddTool(GetPullRequestFiles(getClient,t))
71+
s.AddTool(GetPullRequestStatus(getClient,t))
72+
s.AddTool(GetPullRequestComments(getClient,t))
73+
s.AddTool(GetPullRequestReviews(getClient,t))
74+
if!readOnly {
75+
s.AddTool(MergePullRequest(getClient,t))
76+
s.AddTool(UpdatePullRequestBranch(getClient,t))
77+
s.AddTool(CreatePullRequestReview(getClient,t))
78+
s.AddTool(CreatePullRequest(getClient,t))
79+
}
7180
}
7281

73-
// Add GitHub tools - Search
74-
s.AddTool(SearchCode(getClient,t))
75-
s.AddTool(SearchUsers(getClient,t))
82+
iftoolsetGroup.IsEnabled("search") {
83+
// Add GitHub tools - Search
84+
s.AddTool(SearchCode(getClient,t))
85+
s.AddTool(SearchUsers(getClient,t))
86+
}
7687

77-
// Add GitHub tools - Users
78-
s.AddTool(GetMe(getClient,t))
88+
iftoolsetGroup.IsEnabled("code_security") {
89+
// Add GitHub tools - Code Scanning
90+
s.AddTool(GetCodeScanningAlert(getClient,t))
91+
s.AddTool(ListCodeScanningAlerts(getClient,t))
92+
}
93+
94+
iftoolsetGroup.IsEnabled("experiments") {
95+
s.AddTool(ListAvailableToolsets(toolsetGroup,t))
96+
s.AddTool(EnableToolset(s,toolsetGroup,t))
97+
}
7998

80-
// Add GitHub tools - Code Scanning
81-
s.AddTool(GetCodeScanningAlert(getClient,t))
82-
s.AddTool(ListCodeScanningAlerts(getClient,t))
8399
returns
84100
}
85101

@@ -119,6 +135,48 @@ func GetMe(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mc
119135
}
120136
}
121137

138+
funcEnableToolset(s*server.MCPServer,toolsets*toolsets.ToolsetGroup,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
139+
returnmcp.NewTool("enable_toolset",
140+
mcp.WithDescription(t("TOOL_ENABLE_TOOLSET_DESCRIPTION","Enable one of the sets of tools this MCP server provides.")),
141+
mcp.WithString("toolset",
142+
mcp.Required(),
143+
mcp.Description("The name of the toolset to enable"),
144+
mcp.Enum("repos","issues","search","pull_requests","code_security","experiments"),
145+
),
146+
),
147+
func(_ context.Context,request mcp.CallToolRequest) (*mcp.CallToolResult,error) {
148+
// We need to convert the toolsets back to a map for JSON serialization
149+
toolsetName,err:=requiredParam[string](request,"toolset")
150+
iferr!=nil {
151+
returnmcp.NewToolResultError(err.Error()),nil
152+
}
153+
toolsets.EnableFeature(toolsetName)
154+
// TODO s.AddTool()
155+
// TODO SEND TOOL UPDATE TO CLIENT
156+
returnmcp.NewToolResultText(fmt.Sprintf("Toolset %s enabled",toolsetName)),nil
157+
}
158+
}
159+
160+
funcListAvailableToolsets(toolsetGroup*toolsets.ToolsetGroup,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
161+
returnmcp.NewTool("list_available_toolsets",
162+
mcp.WithDescription(t("TOOL_LIST_AVAILABLE_FEATURES_DESCRIPTION","List all available toolsets this MCP server can offer, providing the enabled status of each.")),
163+
),
164+
func(_ context.Context,_ mcp.CallToolRequest) (*mcp.CallToolResult,error) {
165+
// We need to convert the toolsetGroup back to a map for JSON serialization
166+
featureMap:=make(map[string]bool)
167+
forname:=rangetoolsetGroup.Toolsets {
168+
featureMap[name]=toolsetGroup.IsEnabled(name)
169+
}
170+
171+
r,err:=json.Marshal(featureMap)
172+
iferr!=nil {
173+
returnnil,fmt.Errorf("failed to marshal features: %w",err)
174+
}
175+
176+
returnmcp.NewToolResultText(string(r)),nil
177+
}
178+
}
179+
122180
// OptionalParamOK is a helper function that can be used to fetch a requested parameter from the request.
123181
// It returns the value, a boolean indicating if the parameter was present, and an error if the type is wrong.
124182
funcOptionalParamOK[Tany](r mcp.CallToolRequest,pstring) (valueT,okbool,errerror) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp