8
8
"io"
9
9
"net/http"
10
10
11
+ "github.com/github/github-mcp-server/pkg/toolsets"
11
12
"github.com/github/github-mcp-server/pkg/translations"
12
13
"github.com/google/go-github/v69/github"
13
14
"github.com/mark3labs/mcp-go/mcp"
@@ -17,69 +18,84 @@ import (
17
18
type GetClientFn func (context.Context ) (* github.Client , error )
18
19
19
20
// NewServer creates a new GitHub MCP server with the specified GH client and logger.
20
- func NewServer (getClient GetClientFn , version string , readOnly bool , t translations.TranslationHelperFunc ) * server.MCPServer {
21
+ func NewServer (getClient GetClientFn , toolsetGroup * toolsets. ToolsetGroup , version string , readOnly bool , t translations.TranslationHelperFunc ) * server.MCPServer {
21
22
// Create a new MCP server
22
23
s := server .NewMCPServer (
23
24
"github-mcp-server" ,
24
25
version ,
25
26
server .WithResourceCapabilities (true , true ),
26
27
server .WithLogging ())
27
28
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
+ if toolsetGroup .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
+ }
44
51
}
45
52
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
+ if toolsetGroup .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
+ }
59
64
}
60
65
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
+ if toolsetGroup .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
+ }
71
80
}
72
81
73
- // Add GitHub tools - Search
74
- s .AddTool (SearchCode (getClient , t ))
75
- s .AddTool (SearchUsers (getClient , t ))
82
+ if toolsetGroup .IsEnabled ("search" ) {
83
+ // Add GitHub tools - Search
84
+ s .AddTool (SearchCode (getClient , t ))
85
+ s .AddTool (SearchUsers (getClient , t ))
86
+ }
76 87
77
- // Add GitHub tools - Users
78
- s .AddTool (GetMe (getClient , t ))
88
+ if toolsetGroup .IsEnabled ("code_security" ) {
89
+ // Add GitHub tools - Code Scanning
90
+ s .AddTool (GetCodeScanningAlert (getClient , t ))
91
+ s .AddTool (ListCodeScanningAlerts (getClient , t ))
92
+ }
93
+
94
+ if toolsetGroup .IsEnabled ("experiments" ) {
95
+ s .AddTool (ListAvailableToolsets (toolsetGroup , t ))
96
+ s .AddTool (EnableToolset (s , toolsetGroup , t ))
97
+ }
79
98
80
- // Add GitHub tools - Code Scanning
81
- s .AddTool (GetCodeScanningAlert (getClient , t ))
82
- s .AddTool (ListCodeScanningAlerts (getClient , t ))
83
99
return s
84
100
}
85
101
@@ -119,6 +135,48 @@ func GetMe(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mc
119
135
}
120
136
}
121
137
138
+ func EnableToolset (s * server.MCPServer , toolsets * toolsets.ToolsetGroup , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
139
+ return mcp .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
+ if err != nil {
151
+ return mcp .NewToolResultError (err .Error ()), nil
152
+ }
153
+ toolsets .EnableFeature (toolsetName )
154
+ // TODO s.AddTool()
155
+ // TODO SEND TOOL UPDATE TO CLIENT
156
+ return mcp .NewToolResultText (fmt .Sprintf ("Toolset %s enabled" , toolsetName )), nil
157
+ }
158
+ }
159
+
160
+ func ListAvailableToolsets (toolsetGroup * toolsets.ToolsetGroup , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
161
+ return mcp .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
+ for name := range toolsetGroup .Toolsets {
168
+ featureMap [name ] = toolsetGroup .IsEnabled (name )
169
+ }
170
+
171
+ r , err := json .Marshal (featureMap )
172
+ if err != nil {
173
+ return nil , fmt .Errorf ("failed to marshal features: %w" , err )
174
+ }
175
+
176
+ return mcp .NewToolResultText (string (r )), nil
177
+ }
178
+ }
179
+
122
180
// OptionalParamOK is a helper function that can be used to fetch a requested parameter from the request.
123
181
// It returns the value, a boolean indicating if the parameter was present, and an error if the type is wrong.
124
182
func OptionalParamOK [T any ](r mcp.CallToolRequest , p string ) (value T , ok bool , err error ) {
0 commit comments