Skip to content

Commit f069f36

Browse files
committed
initial workflows
1 parent d15026b commit f069f36

File tree

2 files changed

+255
-6
lines changed

2 files changed

+255
-6
lines changed

pkg/github/tools.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
4646
toolsets.NewServerResourceTemplate(GetRepositoryResourceCommitContent(getClient, getRawClient, t)),
4747
toolsets.NewServerResourceTemplate(GetRepositoryResourceTagContent(getClient, getRawClient, t)),
4848
toolsets.NewServerResourceTemplate(GetRepositoryResourcePrContent(getClient, getRawClient, t)),
49-
)
49+
).AddPrompts(
50+
toolsets.NewServerPrompt(RepositorySetupWorkflowPrompt(t)),
51+
)
5052
issues := toolsets.NewToolset("issues", "GitHub Issues related tools").
5153
AddReadTools(
5254
toolsets.NewServerTool(GetIssue(getClient, t)),
@@ -59,7 +61,10 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
5961
toolsets.NewServerTool(AddIssueComment(getClient, t)),
6062
toolsets.NewServerTool(UpdateIssue(getClient, t)),
6163
toolsets.NewServerTool(AssignCopilotToIssue(getGQLClient, t)),
62-
).AddPrompts(toolsets.NewServerPrompt(AssignCodingAgentPrompt(t)))
64+
).AddPrompts(
65+
toolsets.NewServerPrompt(AssignCodingAgentPrompt(t)),
66+
toolsets.NewServerPrompt(IssueInvestigationWorkflowPrompt(t)),
67+
)
6368
users := toolsets.NewToolset("users", "GitHub User related tools").
6469
AddReadTools(
6570
toolsets.NewServerTool(SearchUsers(getClient, t)),
@@ -92,12 +97,16 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
9297
toolsets.NewServerTool(AddPullRequestReviewCommentToPendingReview(getGQLClient, t)),
9398
toolsets.NewServerTool(SubmitPendingPullRequestReview(getGQLClient, t)),
9499
toolsets.NewServerTool(DeletePendingPullRequestReview(getGQLClient, t)),
95-
)
100+
).AddPrompts(
101+
toolsets.NewServerPrompt(PullRequestReviewWorkflowPrompt(t)),
102+
)
96103
codeSecurity := toolsets.NewToolset("code_security", "Code security related tools, such as GitHub Code Scanning").
97104
AddReadTools(
98105
toolsets.NewServerTool(GetCodeScanningAlert(getClient, t)),
99106
toolsets.NewServerTool(ListCodeScanningAlerts(getClient, t)),
100-
)
107+
).AddPrompts(
108+
toolsets.NewServerPrompt(SecurityAlertWorkflowPrompt(t)),
109+
)
101110
secretProtection := toolsets.NewToolset("secret_protection", "Secret protection related tools, such as GitHub Secret Scanning").
102111
AddReadTools(
103112
toolsets.NewServerTool(GetSecretScanningAlert(getClient, t)),
@@ -107,7 +116,9 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
107116
AddReadTools(
108117
toolsets.NewServerTool(GetDependabotAlert(getClient, t)),
109118
toolsets.NewServerTool(ListDependabotAlerts(getClient, t)),
110-
)
119+
).AddPrompts(
120+
toolsets.NewServerPrompt(SecurityAlertWorkflowPrompt(t)),
121+
)
111122

112123
notifications := toolsets.NewToolset("notifications", "GitHub Notifications related tools").
113124
AddReadTools(
@@ -119,7 +130,9 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
119130
toolsets.NewServerTool(MarkAllNotificationsRead(getClient, t)),
120131
toolsets.NewServerTool(ManageNotificationSubscription(getClient, t)),
121132
toolsets.NewServerTool(ManageRepositoryNotificationSubscription(getClient, t)),
122-
)
133+
).AddPrompts(
134+
toolsets.NewServerPrompt(NotificationTriageWorkflowPrompt(t)),
135+
)
123136

124137
discussions := toolsets.NewToolset("discussions", "GitHub Discussions related tools").
125138
AddReadTools(

pkg/github/workflow_prompts.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/github/github-mcp-server/pkg/translations"
8+
"github.com/mark3labs/mcp-go/mcp"
9+
"github.com/mark3labs/mcp-go/server"
10+
)
11+
12+
// PullRequestReviewWorkflowPrompt provides a guided workflow for comprehensive PR review
13+
func PullRequestReviewWorkflowPrompt(t translations.TranslationHelperFunc) (tool mcp.Prompt, handler server.PromptHandlerFunc) {
14+
return mcp.NewPrompt("PRReviewWorkflow",
15+
mcp.WithPromptDescription(t("PROMPT_PR_REVIEW_WORKFLOW_DESCRIPTION", "Guide through comprehensive pull request review process using pending review workflow")),
16+
mcp.WithArgument("owner", mcp.ArgumentDescription("Repository owner"), mcp.RequiredArgument()),
17+
mcp.WithArgument("repo", mcp.ArgumentDescription("Repository name"), mcp.RequiredArgument()),
18+
mcp.WithArgument("pullNumber", mcp.ArgumentDescription("Pull request number to review"), mcp.RequiredArgument()),
19+
), func(_ context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
20+
owner := request.Params.Arguments["owner"]
21+
repo := request.Params.Arguments["repo"]
22+
pullNumber := request.Params.Arguments["pullNumber"]
23+
24+
messages := []mcp.PromptMessage{
25+
{
26+
Role: "system",
27+
Content: mcp.NewTextContent("You are a code review assistant helping with a comprehensive GitHub pull request review. You should use the pending review workflow to provide thorough, professional feedback. This involves: 1) Creating a pending review, 2) Adding multiple specific comments, and 3) Submitting the complete review with overall feedback."),
28+
},
29+
{
30+
Role: "user",
31+
Content: mcp.NewTextContent(fmt.Sprintf("I need to review pull request #%s in %s/%s. Please help me conduct a thorough review using the pending review workflow.", pullNumber, owner, repo)),
32+
},
33+
{
34+
Role: "assistant",
35+
Content: mcp.NewTextContent(fmt.Sprintf("I'll help you conduct a comprehensive review of PR #%s in %s/%s using the pending review workflow. Let me start by getting the PR details and creating a pending review.", pullNumber, owner, repo)),
36+
},
37+
{
38+
Role: "user",
39+
Content: mcp.NewTextContent("Perfect! Please first get the PR details and files changed, then create a pending review. After that, I'll provide specific feedback for you to add as line comments before we submit the complete review."),
40+
},
41+
{
42+
Role: "assistant",
43+
Content: mcp.NewTextContent("Absolutely! Here's my plan:\n\n1. First, I'll get the PR details and files changed\n2. Create a pending review\n3. Wait for your specific feedback to add as line comments\n4. Submit the complete review with overall assessment\n\nLet me start by examining the pull request."),
44+
},
45+
}
46+
return &mcp.GetPromptResult{
47+
Messages: messages,
48+
}, nil
49+
}
50+
}
51+
52+
// NotificationTriageWorkflowPrompt provides a guided workflow for processing notifications
53+
func NotificationTriageWorkflowPrompt(t translations.TranslationHelperFunc) (tool mcp.Prompt, handler server.PromptHandlerFunc) {
54+
return mcp.NewPrompt("NotificationTriageWorkflow",
55+
mcp.WithPromptDescription(t("PROMPT_NOTIFICATION_TRIAGE_WORKFLOW_DESCRIPTION", "Systematically process and triage GitHub notifications")),
56+
mcp.WithArgument("filter", mcp.ArgumentDescription("Notification filter (default, include_read_notifications, only_participating)")),
57+
), func(_ context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
58+
filter := "default"
59+
if f, exists := request.Params.Arguments["filter"]; exists {
60+
filter = fmt.Sprintf("%v", f)
61+
}
62+
63+
messages := []mcp.PromptMessage{
64+
{
65+
Role: "system",
66+
Content: mcp.NewTextContent("You are a notification management assistant helping to efficiently process GitHub notifications. You should help triage notifications by examining them and taking appropriate actions like dismissing, unsubscribing, or marking as read."),
67+
},
68+
{
69+
Role: "user",
70+
Content: mcp.NewTextContent(fmt.Sprintf("I need to triage my GitHub notifications. Please help me process them systematically using filter '%s'.", filter)),
71+
},
72+
{
73+
Role: "assistant",
74+
Content: mcp.NewTextContent(fmt.Sprintf("I'll help you efficiently triage your GitHub notifications using the '%s' filter. Let me start by listing your notifications and then we can examine each one to determine the appropriate action.", filter)),
75+
},
76+
{
77+
Role: "user",
78+
Content: mcp.NewTextContent("Great! For each notification, please show me the details and suggest what action to take - whether to dismiss it, unsubscribe from the thread, or take other action."),
79+
},
80+
{
81+
Role: "assistant",
82+
Content: mcp.NewTextContent("Perfect! I'll examine each notification and provide recommendations. Let me start by getting your notification list and then we'll go through them systematically."),
83+
},
84+
}
85+
return &mcp.GetPromptResult{
86+
Messages: messages,
87+
}, nil
88+
}
89+
}
90+
91+
// IssueInvestigationWorkflowPrompt provides guided workflow for investigating and delegating issues
92+
func IssueInvestigationWorkflowPrompt(t translations.TranslationHelperFunc) (tool mcp.Prompt, handler server.PromptHandlerFunc) {
93+
return mcp.NewPrompt("IssueInvestigationWorkflow",
94+
mcp.WithPromptDescription(t("PROMPT_ISSUE_INVESTIGATION_WORKFLOW_DESCRIPTION", "Investigate issues and delegate appropriate ones to Copilot coding agent")),
95+
mcp.WithArgument("owner", mcp.ArgumentDescription("Repository owner"), mcp.RequiredArgument()),
96+
mcp.WithArgument("repo", mcp.ArgumentDescription("Repository name"), mcp.RequiredArgument()),
97+
mcp.WithArgument("searchQuery", mcp.ArgumentDescription("Search query for issues (optional)")),
98+
), func(_ context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
99+
owner := request.Params.Arguments["owner"]
100+
repo := request.Params.Arguments["repo"]
101+
searchQuery := ""
102+
if q, exists := request.Params.Arguments["searchQuery"]; exists {
103+
searchQuery = fmt.Sprintf("%v", q)
104+
}
105+
106+
messages := []mcp.PromptMessage{
107+
{
108+
Role: "system",
109+
Content: mcp.NewTextContent("You are an issue management assistant helping to investigate GitHub issues and identify which ones are suitable for delegation to Copilot coding agent. You should examine issues for clarity, scope, and complexity to determine suitability for autonomous work."),
110+
},
111+
{
112+
Role: "user",
113+
Content: mcp.NewTextContent(fmt.Sprintf("I need to investigate issues in %s/%s and identify which ones can be assigned to Copilot. %s", owner, repo, func() string {
114+
if searchQuery != "" {
115+
return fmt.Sprintf("Please focus on issues matching: '%s'", searchQuery)
116+
}
117+
return "Please help me find suitable issues."
118+
}())),
119+
},
120+
{
121+
Role: "assistant",
122+
Content: mcp.NewTextContent(fmt.Sprintf("I'll help you investigate issues in %s/%s and identify which ones are suitable for Copilot assignment. Let me search for relevant issues and examine them for clarity, scope, and complexity.", owner, repo)),
123+
},
124+
{
125+
Role: "user",
126+
Content: mcp.NewTextContent("Perfect! For each issue, please check if it has:\n- Clear problem description\n- Defined acceptance criteria\n- Appropriate scope (not too large/complex)\n- Technical feasibility for autonomous work\n\nThen assign suitable ones to Copilot."),
127+
},
128+
{
129+
Role: "assistant",
130+
Content: mcp.NewTextContent("Excellent criteria! I'll evaluate each issue against these requirements:\n\n Clear problem description\n Defined acceptance criteria \n Appropriate scope\n Technical feasibility\n\nLet me start by finding and examining the issues."),
131+
},
132+
}
133+
return &mcp.GetPromptResult{
134+
Messages: messages,
135+
}, nil
136+
}
137+
}
138+
139+
// SecurityAlertWorkflowPrompt provides guided workflow for managing security alerts
140+
func SecurityAlertWorkflowPrompt(t translations.TranslationHelperFunc) (tool mcp.Prompt, handler server.PromptHandlerFunc) {
141+
return mcp.NewPrompt("SecurityAlertWorkflow",
142+
mcp.WithPromptDescription(t("PROMPT_SECURITY_ALERT_WORKFLOW_DESCRIPTION", "Convert security alerts into trackable issues and assign to appropriate resources")),
143+
mcp.WithArgument("owner", mcp.ArgumentDescription("Repository owner"), mcp.RequiredArgument()),
144+
mcp.WithArgument("repo", mcp.ArgumentDescription("Repository name"), mcp.RequiredArgument()),
145+
mcp.WithArgument("alertType", mcp.ArgumentDescription("Type of alerts to process: dependabot, code_scanning, or secret_scanning")),
146+
), func(_ context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
147+
owner := request.Params.Arguments["owner"]
148+
repo := request.Params.Arguments["repo"]
149+
alertType := "dependabot"
150+
if t, exists := request.Params.Arguments["alertType"]; exists {
151+
alertType = fmt.Sprintf("%v", t)
152+
}
153+
154+
messages := []mcp.PromptMessage{
155+
{
156+
Role: "system",
157+
Content: mcp.NewTextContent("You are a security management assistant helping to process security alerts and convert them into actionable work items. You should examine alerts, create tracking issues for important ones, and assign appropriate work to Copilot where suitable."),
158+
},
159+
{
160+
Role: "user",
161+
Content: mcp.NewTextContent(fmt.Sprintf("I need to process %s security alerts for %s/%s. Please help me convert critical alerts into trackable issues and assign work appropriately.", alertType, owner, repo)),
162+
},
163+
{
164+
Role: "assistant",
165+
Content: mcp.NewTextContent(fmt.Sprintf("I'll help you process %s alerts for %s/%s systematically. Let me examine the alerts, identify critical ones, and create appropriate tracking issues.", alertType, owner, repo)),
166+
},
167+
{
168+
Role: "user",
169+
Content: mcp.NewTextContent("Great! Please prioritize by severity and create issues for critical/high priority alerts. For straightforward dependency updates, consider assigning to Copilot. For complex security issues, create detailed issues for human review."),
170+
},
171+
{
172+
Role: "assistant",
173+
Content: mcp.NewTextContent("Perfect approach! I'll:\n\n1. List and examine the security alerts\n2. Prioritize by severity (critical/high first)\n3. Create detailed tracking issues\n4. Assign simple dependency updates to Copilot\n5. Flag complex security issues for human review\n\nLet me start by examining the alerts."),
174+
},
175+
}
176+
return &mcp.GetPromptResult{
177+
Messages: messages,
178+
}, nil
179+
}
180+
}
181+
182+
// RepositorySetupWorkflowPrompt provides guided workflow for setting up new repositories
183+
func RepositorySetupWorkflowPrompt(t translations.TranslationHelperFunc) (tool mcp.Prompt, handler server.PromptHandlerFunc) {
184+
return mcp.NewPrompt("RepositorySetupWorkflow",
185+
mcp.WithPromptDescription(t("PROMPT_REPOSITORY_SETUP_WORKFLOW_DESCRIPTION", "Guide through setting up a new repository with initial content and structure")),
186+
mcp.WithArgument("repoName", mcp.ArgumentDescription("Name for the new repository"), mcp.RequiredArgument()),
187+
mcp.WithArgument("description", mcp.ArgumentDescription("Repository description")),
188+
mcp.WithArgument("private", mcp.ArgumentDescription("Whether repository should be private (true/false)")),
189+
), func(_ context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
190+
repoName := request.Params.Arguments["repoName"]
191+
description := ""
192+
if d, exists := request.Params.Arguments["description"]; exists {
193+
description = fmt.Sprintf("%v", d)
194+
}
195+
private := "false"
196+
if p, exists := request.Params.Arguments["private"]; exists {
197+
private = fmt.Sprintf("%v", p)
198+
}
199+
200+
messages := []mcp.PromptMessage{
201+
{
202+
Role: "system",
203+
Content: mcp.NewTextContent("You are a repository setup assistant helping to create and configure new GitHub repositories with best practices. You should guide through creating the repository, setting up initial structure, and establishing good development workflows."),
204+
},
205+
{
206+
Role: "user",
207+
Content: mcp.NewTextContent(fmt.Sprintf("I want to create a new repository called '%s'%s%s. Please help me set it up with proper initial structure.", repoName, func() string {
208+
if description != "" {
209+
return fmt.Sprintf(" with description '%s'", description)
210+
}
211+
return ""
212+
}(), func() string {
213+
if private == "true" {
214+
return " (private repository)"
215+
}
216+
return ""
217+
}())),
218+
},
219+
{
220+
Role: "assistant",
221+
Content: mcp.NewTextContent(fmt.Sprintf("I'll help you create and set up the '%s' repository with a proper initial structure. Let me guide you through the process step by step.", repoName)),
222+
},
223+
{
224+
Role: "user",
225+
Content: mcp.NewTextContent("Perfect! Please:\n1. Create the repository\n2. Set up a development branch\n3. Add essential files (README, .gitignore, etc.)\n4. Create an initial pull request to establish the workflow\n\nLet me know what type of project this is so you can suggest appropriate templates."),
226+
},
227+
{
228+
Role: "assistant",
229+
Content: mcp.NewTextContent("Excellent plan! I'll create a well-structured repository with:\n\n Repository creation\n Development branch setup\n Essential files (README, .gitignore, etc.)\n Initial PR workflow\n\nWhat type of project is this? (e.g., JavaScript/Node.js, Python, Go, documentation, etc.) This will help me suggest the right templates and structure."),
230+
},
231+
}
232+
return &mcp.GetPromptResult{
233+
Messages: messages,
234+
}, nil
235+
}
236+
}

0 commit comments

Comments
 (0)