Skip to content

Commit 03f1a6a

Browse files
committed
set up wizard with hardcoded tools
1 parent 6793b9d commit 03f1a6a

File tree

1 file changed

+254
-0
lines changed

1 file changed

+254
-0
lines changed

cmd/github-mcp-server/wizard.go

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"sort"
6+
"strings"
7+
8+
"github.com/AlecAivazis/survey/v2"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var wizardCmd = &cobra.Command{
13+
Use: "wizard",
14+
Short: "Interactive configuration wizard for GitHub MCP Server",
15+
Long: `This wizard will help you configure which specific tools to enable.`,
16+
RunE: runWizard,
17+
}
18+
19+
type toolInfo struct {
20+
name string
21+
description string
22+
toolsetName string
23+
isReadOnly bool
24+
}
25+
26+
// Define all available tools statically to avoid runtime initialization issues
27+
var availableTools = map[string][]toolInfo{
28+
"repos": {
29+
{name: "search_repositories", description: "Search for GitHub repositories", isReadOnly: true},
30+
{name: "get_file_contents", description: "Get file contents from a repository", isReadOnly: true},
31+
{name: "list_commits", description: "List commits in a repository", isReadOnly: true},
32+
{name: "search_code", description: "Search code across GitHub", isReadOnly: true},
33+
{name: "get_commit", description: "Get details of a specific commit", isReadOnly: true},
34+
{name: "list_branches", description: "List branches in a repository", isReadOnly: true},
35+
{name: "list_tags", description: "List tags in a repository", isReadOnly: true},
36+
{name: "get_tag", description: "Get details of a specific tag", isReadOnly: true},
37+
{name: "list_releases", description: "List releases in a repository", isReadOnly: true},
38+
{name: "get_latest_release", description: "Get the latest release of a repository", isReadOnly: true},
39+
{name: "get_release_by_tag", description: "Get a release by its tag", isReadOnly: true},
40+
{name: "list_starred_repositories", description: "List starred repositories", isReadOnly: true},
41+
{name: "create_or_update_file", description: "Create or update a file in a repository", isReadOnly: false},
42+
{name: "create_repository", description: "Create a new repository", isReadOnly: false},
43+
{name: "fork_repository", description: "Fork a repository", isReadOnly: false},
44+
{name: "create_branch", description: "Create a new branch", isReadOnly: false},
45+
{name: "push_files", description: "Push files to a repository", isReadOnly: false},
46+
{name: "delete_file", description: "Delete a file from a repository", isReadOnly: false},
47+
{name: "star_repository", description: "Star a repository", isReadOnly: false},
48+
{name: "unstar_repository", description: "Unstar a repository", isReadOnly: false},
49+
},
50+
"issues": {
51+
{name: "get_issue", description: "Get details of an issue", isReadOnly: true},
52+
{name: "search_issues", description: "Search for issues", isReadOnly: true},
53+
{name: "list_issues", description: "List issues in a repository", isReadOnly: true},
54+
{name: "get_issue_comments", description: "Get comments on an issue", isReadOnly: true},
55+
{name: "list_issue_types", description: "List available issue types", isReadOnly: true},
56+
{name: "list_sub_issues", description: "List sub-issues of an issue", isReadOnly: true},
57+
{name: "create_issue", description: "Create a new issue", isReadOnly: false},
58+
{name: "add_issue_comment", description: "Add a comment to an issue", isReadOnly: false},
59+
{name: "update_issue", description: "Update an issue", isReadOnly: false},
60+
{name: "assign_copilot_to_issue", description: "Assign Copilot to an issue", isReadOnly: false},
61+
{name: "add_sub_issue", description: "Add a sub-issue", isReadOnly: false},
62+
{name: "remove_sub_issue", description: "Remove a sub-issue", isReadOnly: false},
63+
{name: "reprioritize_sub_issue", description: "Reprioritize a sub-issue", isReadOnly: false},
64+
},
65+
"users": {
66+
{name: "search_users", description: "Search for GitHub users", isReadOnly: true},
67+
},
68+
"orgs": {
69+
{name: "search_orgs", description: "Search for GitHub organizations", isReadOnly: true},
70+
},
71+
"pull_requests": {
72+
{name: "get_pull_request", description: "Get details of a pull request", isReadOnly: true},
73+
{name: "list_pull_requests", description: "List pull requests in a repository", isReadOnly: true},
74+
{name: "get_pull_request_files", description: "Get files changed in a pull request", isReadOnly: true},
75+
{name: "search_pull_requests", description: "Search for pull requests", isReadOnly: true},
76+
{name: "get_pull_request_status", description: "Get status of a pull request", isReadOnly: true},
77+
{name: "get_pull_request_review_comments", description: "Get review comments on a pull request", isReadOnly: true},
78+
{name: "get_pull_request_reviews", description: "Get reviews on a pull request", isReadOnly: true},
79+
{name: "get_pull_request_diff", description: "Get diff of a pull request", isReadOnly: true},
80+
{name: "merge_pull_request", description: "Merge a pull request", isReadOnly: false},
81+
{name: "update_pull_request_branch", description: "Update pull request branch", isReadOnly: false},
82+
{name: "create_pull_request", description: "Create a pull request", isReadOnly: false},
83+
{name: "update_pull_request", description: "Update a pull request", isReadOnly: false},
84+
{name: "request_copilot_review", description: "Request Copilot review", isReadOnly: false},
85+
{name: "create_and_submit_pull_request_review", description: "Create and submit a PR review", isReadOnly: false},
86+
{name: "create_pending_pull_request_review", description: "Create a pending PR review", isReadOnly: false},
87+
{name: "add_comment_to_pending_review", description: "Add comment to pending review", isReadOnly: false},
88+
{name: "submit_pending_pull_request_review", description: "Submit a pending PR review", isReadOnly: false},
89+
{name: "delete_pending_pull_request_review", description: "Delete a pending PR review", isReadOnly: false},
90+
},
91+
"code_security": {
92+
{name: "get_code_scanning_alert", description: "Get a code scanning alert", isReadOnly: true},
93+
{name: "list_code_scanning_alerts", description: "List code scanning alerts", isReadOnly: true},
94+
},
95+
"secret_protection": {
96+
{name: "get_secret_scanning_alert", description: "Get a secret scanning alert", isReadOnly: true},
97+
{name: "list_secret_scanning_alerts", description: "List secret scanning alerts", isReadOnly: true},
98+
},
99+
"dependabot": {
100+
{name: "get_dependabot_alert", description: "Get a Dependabot alert", isReadOnly: true},
101+
{name: "list_dependabot_alerts", description: "List Dependabot alerts", isReadOnly: true},
102+
},
103+
"notifications": {
104+
{name: "list_notifications", description: "List notifications", isReadOnly: true},
105+
{name: "get_notification_details", description: "Get notification details", isReadOnly: true},
106+
{name: "dismiss_notification", description: "Dismiss a notification", isReadOnly: false},
107+
{name: "mark_all_notifications_read", description: "Mark all notifications as read", isReadOnly: false},
108+
{name: "manage_notification_subscription", description: "Manage notification subscription", isReadOnly: false},
109+
{name: "manage_repository_notification_subscription", description: "Manage repository notification subscription", isReadOnly: false},
110+
},
111+
"discussions": {
112+
{name: "list_discussions", description: "List discussions", isReadOnly: true},
113+
{name: "get_discussion", description: "Get a discussion", isReadOnly: true},
114+
{name: "get_discussion_comments", description: "Get discussion comments", isReadOnly: true},
115+
{name: "list_discussion_categories", description: "List discussion categories", isReadOnly: true},
116+
},
117+
"actions": {
118+
{name: "list_workflows", description: "List workflows", isReadOnly: true},
119+
{name: "list_workflow_runs", description: "List workflow runs", isReadOnly: true},
120+
{name: "get_workflow_run", description: "Get a workflow run", isReadOnly: true},
121+
{name: "get_workflow_run_logs", description: "Get workflow run logs", isReadOnly: true},
122+
{name: "list_workflow_jobs", description: "List workflow jobs", isReadOnly: true},
123+
{name: "get_job_logs", description: "Get job logs", isReadOnly: true},
124+
{name: "list_workflow_run_artifacts", description: "List workflow run artifacts", isReadOnly: true},
125+
{name: "download_workflow_run_artifact", description: "Download workflow run artifact", isReadOnly: true},
126+
{name: "get_workflow_run_usage", description: "Get workflow run usage", isReadOnly: true},
127+
{name: "run_workflow", description: "Run a workflow", isReadOnly: false},
128+
{name: "rerun_workflow_run", description: "Rerun a workflow run", isReadOnly: false},
129+
{name: "rerun_failed_jobs", description: "Rerun failed jobs", isReadOnly: false},
130+
{name: "cancel_workflow_run", description: "Cancel a workflow run", isReadOnly: false},
131+
{name: "delete_workflow_run_logs", description: "Delete workflow run logs", isReadOnly: false},
132+
},
133+
"security_advisories": {
134+
{name: "list_global_security_advisories", description: "List global security advisories", isReadOnly: true},
135+
{name: "get_global_security_advisory", description: "Get a global security advisory", isReadOnly: true},
136+
{name: "list_repository_security_advisories", description: "List repository security advisories", isReadOnly: true},
137+
{name: "list_org_repository_security_advisories", description: "List org repository security advisories", isReadOnly: true},
138+
},
139+
"context": {
140+
{name: "get_me", description: "Get current user information", isReadOnly: true},
141+
{name: "get_teams", description: "Get teams", isReadOnly: true},
142+
{name: "get_team_members", description: "Get team members", isReadOnly: true},
143+
},
144+
"gists": {
145+
{name: "list_gists", description: "List gists", isReadOnly: true},
146+
{name: "create_gist", description: "Create a gist", isReadOnly: false},
147+
{name: "update_gist", description: "Update a gist", isReadOnly: false},
148+
},
149+
"projects": {
150+
{name: "list_projects", description: "List projects", isReadOnly: true},
151+
{name: "get_project", description: "Get a project", isReadOnly: true},
152+
{name: "list_project_fields", description: "List project fields", isReadOnly: true},
153+
{name: "get_project_field", description: "Get a project field", isReadOnly: true},
154+
{name: "list_project_items", description: "List project items", isReadOnly: true},
155+
{name: "get_project_item", description: "Get a project item", isReadOnly: true},
156+
{name: "add_project_item", description: "Add a project item", isReadOnly: false},
157+
{name: "delete_project_item", description: "Delete a project item", isReadOnly: false},
158+
{name: "update_project_item", description: "Update a project item", isReadOnly: false},
159+
},
160+
}
161+
162+
func runWizard(cmd *cobra.Command, args []string) error {
163+
fmt.Println("🧙 GitHub MCP Server Configuration Wizard")
164+
fmt.Println("==========================================")
165+
fmt.Println()
166+
167+
// Collect all available tools
168+
var allTools []toolInfo
169+
for toolsetName, tools := range availableTools {
170+
for _, tool := range tools {
171+
tool.toolsetName = toolsetName
172+
allTools = append(allTools, tool)
173+
}
174+
}
175+
176+
// Sort tools alphabetically by name
177+
sort.Slice(allTools, func(i, j int) bool {
178+
return allTools[i].name < allTools[j].name
179+
})
180+
181+
// Create options for the survey with formatted descriptions
182+
var toolOptions []string
183+
toolMap := make(map[string]toolInfo)
184+
for _, tool := range allTools {
185+
readOnlyTag := ""
186+
if tool.isReadOnly {
187+
readOnlyTag = " [READ-ONLY]"
188+
}
189+
option := fmt.Sprintf("%s%s - %s (from %s)", tool.name, readOnlyTag, tool.description, tool.toolsetName)
190+
toolOptions = append(toolOptions, option)
191+
toolMap[option] = tool
192+
}
193+
194+
// Select individual tools
195+
selectedOptions := []string{}
196+
toolPrompt := &survey.MultiSelect{
197+
Message: "Select the specific tools you want to enable:",
198+
Options: toolOptions,
199+
PageSize: 20,
200+
}
201+
202+
if err := survey.AskOne(toolPrompt, &selectedOptions); err != nil {
203+
return err
204+
}
205+
206+
// Parse selected tools
207+
selectedTools := []string{}
208+
for _, selection := range selectedOptions {
209+
if tool, exists := toolMap[selection]; exists {
210+
selectedTools = append(selectedTools, tool.name)
211+
}
212+
}
213+
214+
// Build args array
215+
cmdArgs := []string{
216+
"run",
217+
"cmd/github-mcp-server/main.go",
218+
"cmd/github-mcp-server/wizard.go",
219+
"stdio",
220+
}
221+
222+
// Add specific tools
223+
if len(selectedTools) > 0 {
224+
cmdArgs = append(cmdArgs, "--tools")
225+
cmdArgs = append(cmdArgs, strings.Join(selectedTools, ","))
226+
}
227+
228+
// Display the command
229+
fmt.Println()
230+
fmt.Println("✅ Configuration Complete!")
231+
fmt.Println("==========================")
232+
fmt.Println()
233+
fmt.Println("Selected tools:", strings.Join(selectedTools, ", "))
234+
fmt.Println()
235+
fmt.Println("Add this to your mcp.json configuration:")
236+
fmt.Println()
237+
238+
// Print JSON format
239+
fmt.Println(`"args": [`)
240+
for i, arg := range cmdArgs {
241+
comma := ","
242+
if i == len(cmdArgs)-1 {
243+
comma = ""
244+
}
245+
fmt.Printf(` "%s"%s`+"\n", arg, comma)
246+
}
247+
fmt.Println(`],`)
248+
249+
fmt.Println()
250+
fmt.Println("Or run directly with:")
251+
fmt.Printf("go %s\n", strings.Join(cmdArgs, " "))
252+
253+
return nil
254+
}

0 commit comments

Comments
 (0)