Skip to content

Add context toolset and adjust readme #499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,22 @@ If you don't have Docker, you can use `go build` to build the binary in the

The GitHub MCP Server supports enabling or disabling specific groups of functionalities via the `--toolsets` flag. This allows you to control which GitHub API capabilities are available to your AI tools. Enabling only the toolsets that you need can help the LLM with tool choice and reduce the context size.

_Toolsets are not limited to Tools. Relevent MCP Resources and Prompts are also included where applicable._

### Available Toolsets

The following sets of tools are available (all are on by default):

| Toolset | Description |
| ----------------------- | ------------------------------------------------------------- |
| `repos` | Repository-related tools (file operations, branches, commits) |
| `context` | **Strongly recommended**: Tools that provide context about the current user and GitHub context you are operating in |
| `code_security` | Code scanning alerts and security features |
| `issues` | Issue-related tools (create, read, update, comment) |
| `users` | Anything relating to GitHub Users |
| `notifications` | GitHub Notifications related tools |
| `pull_requests` | Pull request operations (create, merge, review) |
| `code_security` | Code scanning alerts and security features |
| `repos` | Repository-related tools (file operations, branches, commits) |
| `secret_protection` | Secret protection related tools, such as GitHub Secret Scanning |
| `users` | Anything relating to GitHub Users |
| `experiments` | Experimental features (not considered stable) |

#### Specifying Toolsets
Expand Down
8 changes: 2 additions & 6 deletions internal/ghmcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,8 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
return nil, fmt.Errorf("failed to enable toolsets: %w", err)
}

context := github.InitContextToolset(getClient, cfg.Translator)
github.RegisterResources(ghServer, getClient, cfg.Translator)

// Register the tools with the server
tsg.RegisterTools(ghServer)
context.RegisterTools(ghServer)
// Register all mcp functionality with the server
tsg.RegisterAll(ghServer)

if cfg.DynamicToolsets {
dynamic := github.InitDynamicToolset(ghServer, tsg, cfg.Translator)
Expand Down
14 changes: 0 additions & 14 deletions pkg/github/resources.go

This file was deleted.

23 changes: 13 additions & 10 deletions pkg/github/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
toolsets.NewServerTool(CreateBranch(getClient, t)),
toolsets.NewServerTool(PushFiles(getClient, t)),
toolsets.NewServerTool(DeleteFile(getClient, t)),
).
AddResourceTemplates(
toolsets.NewServerResourceTemplate(GetRepositoryResourceContent(getClient, t)),
toolsets.NewServerResourceTemplate(GetRepositoryResourceBranchContent(getClient, t)),
toolsets.NewServerResourceTemplate(GetRepositoryResourceCommitContent(getClient, t)),
toolsets.NewServerResourceTemplate(GetRepositoryResourceTagContent(getClient, t)),
toolsets.NewServerResourceTemplate(GetRepositoryResourcePrContent(getClient, t)),
)
issues := toolsets.NewToolset("issues", "GitHub Issues related tools").
AddReadTools(
Expand Down Expand Up @@ -106,7 +113,13 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
// Keep experiments alive so the system doesn't error out when it's always enabled
experiments := toolsets.NewToolset("experiments", "Experimental features that are not considered stable yet")

contextTools := toolsets.NewToolset("context", "Tools that provide context about the current user and GitHub context you are operating in").
AddReadTools(
toolsets.NewServerTool(GetMe(getClient, t)),
)

// Add toolsets to the group
tsg.AddToolset(contextTools)
tsg.AddToolset(repos)
tsg.AddToolset(issues)
tsg.AddToolset(users)
Expand All @@ -119,16 +132,6 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
return tsg
}

func InitContextToolset(getClient GetClientFn, t translations.TranslationHelperFunc) *toolsets.Toolset {
// Create a new context toolset
contextTools := toolsets.NewToolset("context", "Tools that provide context about the current user and GitHub context you are operating in").
AddReadTools(
toolsets.NewServerTool(GetMe(getClient, t)),
)
contextTools.Enabled = true
return contextTools
}

// InitDynamicToolset creates a dynamic toolset that can be used to enable other toolsets, and so requires the server and toolset group as arguments
func InitDynamicToolset(s *server.MCPServer, tsg *toolsets.ToolsetGroup, t translations.TranslationHelperFunc) *toolsets.Toolset {
// Create a new dynamic toolset
Expand Down
45 changes: 44 additions & 1 deletion pkg/toolsets/toolsets.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,30 @@ func NewServerTool(tool mcp.Tool, handler server.ToolHandlerFunc) server.ServerT
return server.ServerTool{Tool: tool, Handler: handler}
}

func NewServerResourceTemplate(resourceTemplate mcp.ResourceTemplate, handler server.ResourceTemplateHandlerFunc) ServerResourceTemplate {
return ServerResourceTemplate{
resourceTemplate: resourceTemplate,
handler: handler,
}
}

// ServerResourceTemplate represents a resource template that can be registered with the MCP server.
type ServerResourceTemplate struct {
resourceTemplate mcp.ResourceTemplate
handler server.ResourceTemplateHandlerFunc
}

// Toolset represents a collection of MCP functionality that can be enabled or disabled as a group.
type Toolset struct {
Name string
Description string
Enabled bool
readOnly bool
writeTools []server.ServerTool
readTools []server.ServerTool
// resources are not tools, but the community seems to be moving towards namespaces as a broader concept
// and in order to have multiple servers running concurrently, we want to avoid overlapping resources too.
resourceTemplates []ServerResourceTemplate
}

func (t *Toolset) GetActiveTools() []server.ServerTool {
Expand Down Expand Up @@ -73,6 +90,31 @@ func (t *Toolset) RegisterTools(s *server.MCPServer) {
}
}

func (t *Toolset) AddResourceTemplates(templates ...ServerResourceTemplate) *Toolset {
t.resourceTemplates = append(t.resourceTemplates, templates...)
return t
}

func (t *Toolset) GetActiveResourceTemplates() []ServerResourceTemplate {
if !t.Enabled {
return nil
}
return t.resourceTemplates
}

func (t *Toolset) GetAvailableResourceTemplates() []ServerResourceTemplate {
return t.resourceTemplates
}

func (t *Toolset) RegisterResourcesTemplates(s *server.MCPServer) {
if !t.Enabled {
return
}
for _, resource := range t.resourceTemplates {
s.AddResourceTemplate(resource.resourceTemplate, resource.handler)
}
}

func (t *Toolset) SetReadOnly() {
// Set the toolset to read-only
t.readOnly = true
Expand Down Expand Up @@ -179,9 +221,10 @@ func (tg *ToolsetGroup) EnableToolset(name string) error {
return nil
}

func (tg *ToolsetGroup) RegisterTools(s *server.MCPServer) {
func (tg *ToolsetGroup) RegisterAll(s *server.MCPServer) {
for _, toolset := range tg.Toolsets {
toolset.RegisterTools(s)
toolset.RegisterResourcesTemplates(s)
}
}

Expand Down