diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index 6090063f1..9e7dafcae 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -215,7 +215,7 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) { cfg.Translator, github.FeatureFlags{ LockdownMode: cfg.LockdownMode, - InsiderMode: cfg.InsiderMode, + InsiderMode: cfg.InsiderMode, }, cfg.ContentWindowSize, featureChecker, @@ -235,7 +235,7 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) { WithToolsets(enabledToolsets). WithTools(cfg.EnabledTools). WithFeatureChecker(featureChecker) - + // Apply token scope filtering if scopes are known (for PAT filtering) if cfg.TokenScopes != nil { inventoryBuilder = inventoryBuilder.WithFilter(github.CreateToolScopeFilter(cfg.TokenScopes)) diff --git a/pkg/github/instructions.go b/pkg/github/instructions.go index 3a5fb54bb..8f579f20d 100644 --- a/pkg/github/instructions.go +++ b/pkg/github/instructions.go @@ -13,22 +13,10 @@ func GenerateInstructions(enabledToolsets []string) string { return "" // Baseline mode } - var instructions []string - - // Core instruction - always included if context toolset enabled - if slices.Contains(enabledToolsets, "context") { - instructions = append(instructions, "Always call 'get_me' first to understand current user permissions and context.") - } - - // Individual toolset instructions - for _, toolset := range enabledToolsets { - if inst := getToolsetInstructions(toolset, enabledToolsets); inst != "" { - instructions = append(instructions, inst) - } - } + var buf strings.Builder // Base instruction with context management - baseInstruction := `The GitHub MCP Server provides tools to interact with GitHub platform. + buf.WriteString(`The GitHub MCP Server provides tools to interact with GitHub platform. Tool selection guidance: 1. Use 'list_*' tools for broad, simple retrieval and pagination of all items of a type (e.g., all issues, all PRs, all branches) with basic filtering. @@ -39,37 +27,48 @@ Context management: 2. Use minimal_output parameter set to true if the full information is not needed to accomplish a task. Tool usage guidance: - 1. For 'search_*' tools: Use separate 'sort' and 'order' parameters if available for sorting results - do not include 'sort:' syntax in query strings. Query strings should contain only search criteria (e.g., 'org:google language:python'), not sorting instructions.` + 1. For 'search_*' tools: Use separate 'sort' and 'order' parameters if available for sorting results - do not include 'sort:' syntax in query strings. Query strings should contain only search criteria (e.g., 'org:google language:python'), not sorting instructions.`) - allInstructions := []string{baseInstruction} - allInstructions = append(allInstructions, instructions...) + // Core instruction - always included if context toolset enabled + if slices.Contains(enabledToolsets, "context") { + buf.WriteString(" Always call 'get_me' first to understand current user permissions and context.") + } + + // Individual toolset instructions + for _, toolset := range enabledToolsets { + if inst := getToolsetInstructions(toolset, enabledToolsets); inst != "" { + buf.WriteString(" ") + buf.WriteString(inst) + } + } - return strings.Join(allInstructions, " ") + return buf.String() } // getToolsetInstructions returns specific instructions for individual toolsets func getToolsetInstructions(toolset string, enabledToolsets []string) string { + var buf strings.Builder + switch toolset { case "pull_requests": - pullRequestInstructions := `## Pull Requests + buf.WriteString(`## Pull Requests -PR review workflow: Always use 'pull_request_review_write' with method 'create' to create a pending review, then 'add_comment_to_pending_review' to add comments, and finally 'pull_request_review_write' with method 'submit_pending' to submit the review for complex reviews with line-specific comments.` +PR review workflow: Always use 'pull_request_review_write' with method 'create' to create a pending review, then 'add_comment_to_pending_review' to add comments, and finally 'pull_request_review_write' with method 'submit_pending' to submit the review for complex reviews with line-specific comments.`) if slices.Contains(enabledToolsets, "repos") { - pullRequestInstructions += ` + buf.WriteString(` -Before creating a pull request, search for pull request templates in the repository. Template files are called pull_request_template.md or they're located in '.github/PULL_REQUEST_TEMPLATE' directory. Use the template content to structure the PR description and then call create_pull_request tool.` +Before creating a pull request, search for pull request templates in the repository. Template files are called pull_request_template.md or they're located in '.github/PULL_REQUEST_TEMPLATE' directory. Use the template content to structure the PR description and then call create_pull_request tool.`) } - return pullRequestInstructions case "issues": - return `## Issues + buf.WriteString(`## Issues -Check 'list_issue_types' first for organizations to use proper issue types. Use 'search_issues' before creating new issues to avoid duplicates. Always set 'state_reason' when closing issues.` +Check 'list_issue_types' first for organizations to use proper issue types. Use 'search_issues' before creating new issues to avoid duplicates. Always set 'state_reason' when closing issues.`) case "discussions": - return `## Discussions + buf.WriteString(`## Discussions -Use 'list_discussion_categories' to understand available categories before creating discussions. Filter by category for better organization.` +Use 'list_discussion_categories' to understand available categories before creating discussions. Filter by category for better organization.`) case "projects": - return `## Projects + buf.WriteString(`## Projects Workflow: 1) list_project_fields (get field IDs), 2) list_project_items (with pagination), 3) optional updates. @@ -136,8 +135,10 @@ Common Qualifier Glossary (items): Never: - Infer field IDs; fetch via list_project_fields. - - Drop 'fields' param on subsequent pages if field values are needed.` + - Drop 'fields' param on subsequent pages if field values are needed.`) default: return "" } + + return buf.String() }