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

Commit5ec44fb

Browse files
olaservoalmaleksia
authored andcommitted
Add instruction generation for enabled toolsets and corresponding tests
1 parentf1e0e8f commit5ec44fb

File tree

3 files changed

+279
-2
lines changed

3 files changed

+279
-2
lines changed

‎internal/ghmcp/server.go‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,6 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
105105
},
106106
}
107107

108-
ghServer:=github.NewServer(cfg.Version,server.WithHooks(hooks))
109-
110108
enabledToolsets:=cfg.EnabledToolsets
111109
ifcfg.DynamicToolsets {
112110
// filter "all" from the enabled toolsets
@@ -118,6 +116,16 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
118116
}
119117
}
120118

119+
// Generate instructions based on enabled toolsets
120+
instructions:=github.GenerateInstructions(enabledToolsets)
121+
varserverOpts []server.ServerOption
122+
ifinstructions!="" {
123+
serverOpts=append(serverOpts,server.WithInstructions(instructions))
124+
}
125+
serverOpts=append(serverOpts,server.WithHooks(hooks))
126+
127+
ghServer:=github.NewServer(cfg.Version,serverOpts...)
128+
121129
getClient:=func(_ context.Context) (*gogithub.Client,error) {
122130
returnrestClient,nil// closing over client
123131
}

‎pkg/github/instructions.go‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package github
2+
3+
import"strings"
4+
5+
// GenerateInstructions creates server instructions based on enabled toolsets
6+
funcGenerateInstructions(enabledToolsets []string)string {
7+
varinstructions []string
8+
9+
// Core instruction - always included if context toolset enabled
10+
ifcontains(enabledToolsets,"context") {
11+
instructions=append(instructions,"Always call 'get_me' first to understand current user permissions and context.")
12+
}
13+
14+
// Individual toolset instructions
15+
for_,toolset:=rangeenabledToolsets {
16+
ifinst:=getToolsetInstructions(toolset);inst!="" {
17+
instructions=append(instructions,inst)
18+
}
19+
}
20+
21+
// Cross-toolset conditional instructions
22+
ifcontains(enabledToolsets,"pull_requests")&&contains(enabledToolsets,"context") {
23+
instructions=append(instructions,"For team workflows: Use 'get_teams' and 'get_team_members' before assigning PR reviewers.")
24+
}
25+
26+
ifhasAnySecurityToolset(enabledToolsets) {
27+
instructions=append(instructions,"Security alert priority: secret_scanning → dependabot → code_scanning alerts.")
28+
}
29+
30+
ifcontains(enabledToolsets,"issues")&&contains(enabledToolsets,"pull_requests") {
31+
instructions=append(instructions,"Link issues to PRs using 'closes #123' or 'fixes #123' in PR descriptions.")
32+
}
33+
34+
ifcontains(enabledToolsets,"repos")&&contains(enabledToolsets,"actions") {
35+
instructions=append(instructions,"For repository operations: Check workflow status before major changes using 'list_workflow_runs'.")
36+
}
37+
38+
// Only add base instruction if we have specific instructions
39+
iflen(instructions)>0 {
40+
baseInstruction:="GitHub MCP Server provides GitHub API tools. Common parameters: 'owner' (repo owner), 'repo' (repo name), 'page'/'perPage' (pagination)."
41+
instructions=append([]string{baseInstruction},instructions...)
42+
}
43+
44+
returnstrings.Join(instructions," ")
45+
}
46+
47+
// getToolsetInstructions returns specific instructions for individual toolsets
48+
funcgetToolsetInstructions(toolsetstring)string {
49+
switchtoolset {
50+
case"pull_requests":
51+
return"PR review workflow: Use 'create_pending_pull_request_review' → 'add_comment_to_pending_review' → 'submit_pending_pull_request_review' for complex reviews with line-specific comments."
52+
case"actions":
53+
return"CI/CD debugging: Use 'get_job_logs' with 'failed_only=true' and 'return_content=true' for immediate log analysis. Use 'rerun_failed_jobs' instead of 'rerun_workflow_run' to save resources."
54+
case"issues":
55+
return"Issue workflow: 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."
56+
case"repos":
57+
return"File operations: Use 'get_file_contents' to check if file exists before 'create_or_update_file'. Always specify 'sha' parameter when updating existing files. Use 'push_files' for multiple file operations in single commit."
58+
case"notifications":
59+
return"Notifications: Filter by 'participating' for issues/PRs you're involved in. Use 'mark_all_notifications_read' with repository filters to avoid marking unrelated notifications."
60+
case"gists":
61+
return"Gists: Use 'list_gists' with 'since' parameter to find recent gists. Specify 'public=false' for private gists in 'create_gist'."
62+
case"discussions":
63+
return"Discussions: Use 'list_discussion_categories' to understand available categories before creating discussions. Filter by category for better organization."
64+
default:
65+
return""
66+
}
67+
}
68+
69+
// hasAnySecurityToolset checks if any security-related toolsets are enabled
70+
funchasAnySecurityToolset(toolsets []string)bool {
71+
securityToolsets:= []string{"code_security","secret_protection","dependabot"}
72+
for_,security:=rangesecurityToolsets {
73+
ifcontains(toolsets,security) {
74+
returntrue
75+
}
76+
}
77+
returnfalse
78+
}
79+
80+
// contains checks if a slice contains a specific string
81+
funccontains(slice []string,itemstring)bool {
82+
for_,s:=rangeslice {
83+
ifs==item {
84+
returntrue
85+
}
86+
}
87+
returnfalse
88+
}

‎pkg/github/instructions_test.go‎

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package github
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
funcTestGenerateInstructions(t*testing.T) {
9+
tests:= []struct {
10+
namestring
11+
enabledToolsets []string
12+
expectedContains []string
13+
expectedEmptybool
14+
}{
15+
{
16+
name:"empty toolsets",
17+
enabledToolsets: []string{},
18+
expectedEmpty:true,
19+
},
20+
{
21+
name:"only context toolset",
22+
enabledToolsets: []string{"context"},
23+
expectedContains: []string{
24+
"GitHub MCP Server provides GitHub API tools",
25+
"Always call 'get_me' first",
26+
},
27+
},
28+
{
29+
name:"pull requests toolset",
30+
enabledToolsets: []string{"pull_requests"},
31+
expectedContains: []string{
32+
"create_pending_pull_request_review",
33+
"add_comment_to_pending_review",
34+
"submit_pending_pull_request_review",
35+
},
36+
},
37+
{
38+
name:"actions toolset",
39+
enabledToolsets: []string{"actions"},
40+
expectedContains: []string{
41+
"get_job_logs",
42+
"failed_only=true",
43+
"rerun_failed_jobs",
44+
},
45+
},
46+
{
47+
name:"security toolsets",
48+
enabledToolsets: []string{"code_security","secret_protection","dependabot"},
49+
expectedContains: []string{
50+
"Security alert priority",
51+
"secret_scanning",
52+
"dependabot",
53+
"code_scanning",
54+
},
55+
},
56+
{
57+
name:"cross-toolset instructions",
58+
enabledToolsets: []string{"context","pull_requests"},
59+
expectedContains: []string{
60+
"get_me",
61+
"get_teams",
62+
"get_team_members",
63+
},
64+
},
65+
{
66+
name:"issues and pull_requests combination",
67+
enabledToolsets: []string{"issues","pull_requests"},
68+
expectedContains: []string{
69+
"closes #123",
70+
"fixes #123",
71+
"search_issues",
72+
"list_issue_types",
73+
},
74+
},
75+
}
76+
77+
for_,tt:=rangetests {
78+
t.Run(tt.name,func(t*testing.T) {
79+
result:=GenerateInstructions(tt.enabledToolsets)
80+
81+
iftt.expectedEmpty {
82+
ifresult!="" {
83+
t.Errorf("Expected empty instructions but got: %s",result)
84+
}
85+
return
86+
}
87+
88+
for_,expectedContent:=rangett.expectedContains {
89+
if!strings.Contains(result,expectedContent) {
90+
t.Errorf("Expected instructions to contain '%s', but got: %s",expectedContent,result)
91+
}
92+
}
93+
})
94+
}
95+
}
96+
97+
funcTestGetToolsetInstructions(t*testing.T) {
98+
tests:= []struct {
99+
toolsetstring
100+
expectedstring
101+
}{
102+
{
103+
toolset:"pull_requests",
104+
expected:"create_pending_pull_request_review",
105+
},
106+
{
107+
toolset:"actions",
108+
expected:"get_job_logs",
109+
},
110+
{
111+
toolset:"issues",
112+
expected:"list_issue_types",
113+
},
114+
{
115+
toolset:"repos",
116+
expected:"get_file_contents",
117+
},
118+
{
119+
toolset:"nonexistent",
120+
expected:"",
121+
},
122+
}
123+
124+
for_,tt:=rangetests {
125+
t.Run(tt.toolset,func(t*testing.T) {
126+
result:=getToolsetInstructions(tt.toolset)
127+
iftt.expected=="" {
128+
ifresult!="" {
129+
t.Errorf("Expected empty result for toolset '%s', but got: %s",tt.toolset,result)
130+
}
131+
}else {
132+
if!strings.Contains(result,tt.expected) {
133+
t.Errorf("Expected instructions for '%s' to contain '%s', but got: %s",tt.toolset,tt.expected,result)
134+
}
135+
}
136+
})
137+
}
138+
}
139+
140+
funcTestHasAnySecurityToolset(t*testing.T) {
141+
tests:= []struct {
142+
namestring
143+
toolsets []string
144+
expectedbool
145+
}{
146+
{
147+
name:"no security toolsets",
148+
toolsets: []string{"repos","issues"},
149+
expected:false,
150+
},
151+
{
152+
name:"has code_security",
153+
toolsets: []string{"repos","code_security"},
154+
expected:true,
155+
},
156+
{
157+
name:"has secret_protection",
158+
toolsets: []string{"secret_protection","issues"},
159+
expected:true,
160+
},
161+
{
162+
name:"has dependabot",
163+
toolsets: []string{"dependabot"},
164+
expected:true,
165+
},
166+
{
167+
name:"has all security toolsets",
168+
toolsets: []string{"code_security","secret_protection","dependabot"},
169+
expected:true,
170+
},
171+
}
172+
173+
for_,tt:=rangetests {
174+
t.Run(tt.name,func(t*testing.T) {
175+
result:=hasAnySecurityToolset(tt.toolsets)
176+
ifresult!=tt.expected {
177+
t.Errorf("Expected %v for toolsets %v, but got %v",tt.expected,tt.toolsets,result)
178+
}
179+
})
180+
}
181+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp