8000 feat: Adding SecretScanning Toolset (#280) · github/github-mcp-server@7c197f5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c197f5

Browse files
tonytrgCopilotSamMorrowDrums
authored
feat: Adding SecretScanning Toolset (#280)
* Adding GetSecretScanningAlert and ListSecretScanningAlerts * adding wip for tests * fix tests * add readme section * Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update .gitignore Co-authored-by: Sam Morrow <info@sam-morrow.com> * fix product name --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Sam Morrow <info@sam-morrow.com>
1 parent 614f226 commit 7c197f5

File tree

5 files changed

+418
-3
lines changed

5 files changed

+418
-3
lines changed
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
.idea
22
cmd/github-mcp-server/github-mcp-server
3+
4+
# VSCode
5+
.vscode/mcp.json
6+
37
# Added by goreleaser init:
48
dist/
5-
__debug_bin*
9+
__debug_bin*
10+
11+
# Go
12+
vendor

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ automation and interaction capabilities for developers and tools.
1919
3. Lastly you will need to [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
2020
The MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)).
2121

22-
23-
2422
## Installation
2523

2624
### Usage with VS Code
@@ -438,6 +436,21 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
438436
- `severity`: Alert severity (string, optional)
439437
- `tool_name`: The name of the tool used for code scanning (string, optional)
440438

439+
### Secret Scanning
440+
441+
- **get_secret_scanning_alert** - Get a secret scanning alert
442+
443+
- `owner`: Repository owner (string, required)
444+
- `repo`: Repository name (string, required)
445+
- `alertNumber`: Alert number (number, required)
446+
447+
- **list_secret_scanning_alerts** - List secret scanning alerts for a repository
448+
- `owner`: Repository owner (string, required)
449+
- `repo`: Repository name (string, required)
450+
- `state`: Alert state (string, optional)
451+
- `secret_type`: The secret types to be filtered for in a comma-separated list (string, optional)
452+
- `resolution`: The resolution status (string, optional)
453+
441454
## Resources
442455

443456
### Repository Content

pkg/github/secret_scanning.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
10+
"github.com/github/github-mcp-server/pkg/translations"
11+
"github.com/google/go-github/v69/github"
12+
"github.com/mark3labs/mcp-go/mcp"
13+
"github.com/mark3labs/mcp-go/server"
14+
)
15+
16+
func GetSecretScanningAlert(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
17+
return mcp.NewTool(
18+
"get_secret_scanning_alert",
19+
mcp.WithDescription(t("TOOL_GET_SECRET_SCANNING_ALERT_DESCRIPTION", "Get details of a specific secret scanning alert in a GitHub repository.")),
20+
mcp.WithString("owner",
21+
mcp.Required(),
22+
mcp.Description("The owner of the repository."),
23+
),
24+
mcp.WithString("repo",
25+
mcp.Required(),
26+
mcp.Description("The name of the repository."),
27+
),
28+
mcp.WithNumber("alertNumber",
29+
mcp.Required(),
30+
mcp.Description("The number of the alert."),
31+
),
32+
),
33+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
34+
owner, err := requiredParam[string](request, "owner")
35+
if err != nil {
36+
return mcp.NewToolResultError(err.Error()), nil
37+
}
38+
repo, err := requiredParam[string](request, "repo")
39+
if err != nil {
40+
return mcp.NewToolResultError(err.Error()), nil
41+
}
42+
alertNumber, err := RequiredInt(request, "alertNumber")
43+
if err != nil {
44+
return mcp.NewToolResultError(err.Error()), nil
45+
}
46+
47+
client, err := getClient(ctx)
48+
if err != nil {
49+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
50+
}
51+
52+
alert, resp, err := client.SecretScanning.GetAlert(ctx, owner, repo, int64(alertNumber))
53+
if err != nil {
54+
return nil, fmt.Errorf("failed to get alert: %w", err)
55+
}
56+
defer func() { _ = resp.Body.Close() }()
57+
58+
if resp.StatusCode != http.StatusOK {
59+
body, err := io.ReadAll(resp.Body)
60+
if err != nil {
61+
return nil, fmt.Errorf("failed to read response body: %w", err)
62+
}
63+
return mcp.NewToolResultError(fmt.Sprintf("failed to get alert: %s", string(body))), nil
64+
}
65+
66+
r, err := json.Marshal(alert)
67+
if err != nil {
68+
return nil, fmt.Errorf("failed to marshal alert: %w", err)
69+
}
70+
71+
return mcp.NewToolResultText(string(r)), nil
72+
}
73+
}
74+
75+
func ListSecretScanningAlerts(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
76+
return mcp.NewTool(
77+
"list_secret_scanning_alerts",
78+
mcp.WithDescription(t("TOOL_LIST_SECRET_SCANNING_ALERTS_DESCRIPTION", "List secret scanning alerts in a GitHub repository.")),
79+
mcp.WithString("owner",
80+
mcp.Required(),
81+
mcp.Description("The owner of the repository."),
82+
),
83+
mcp.WithString("repo",
84+
mcp.Required(),
85+
mcp.Description("The name of the repository."),
86+
),
87+
mcp.WithString("state",
88+
mcp.Description("Filter by state"),
89+
mcp.Enum("open", "resolved"),
90+
),
91+
mcp.WithString("secret_type",
92+
mcp.Description("A comma-separated list of secret types to return. All default secret patterns are returned. To return generic patterns, pass the token name(s) in the parameter."),
93+
),
94+
mcp.WithString("resolution",
95+
mcp.Description("Filter by resolution"),
96+
mcp.Enum("false_positive", "wont_fix", "revoked", "pattern_edited", "pattern_deleted", "used_in_tests"),
97+
),
98+
),
99+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
100+
owner, err := requiredParam[string](request, "owner")
101+
if err != nil {
102+
return mcp.NewToolResultError(err.Error()), nil
103+
}
104+
repo, err := requiredParam[string](request, "repo")
105+
if err != nil {
106+
return mcp.NewToolResultError(err.Error()), nil
107+
}
108+
state, err := OptionalParam[string](request, "state")
109+
if err != nil {
110+
return mcp.NewToolResultError(err.Error()), nil
111+
}
112+
secretType, err := OptionalParam[string](request, "secret_type")
113+
if err != nil {
114+
return mcp.NewToolResultError(err.Error()), nil
115+
}
116+
resolution, err := OptionalParam[string](request, "resolution")
117+
if err != nil {
118+
return mcp.NewToolResultError(err.Error()), nil
119+
}
120+
121+
client, err := getClient(ctx)
122+
if err != nil {
123+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
124+
}
125+
alerts, resp, err := client.SecretScanning.ListAlertsForRepo(ctx, owner, repo, &github.SecretScanningAlertListOptions{State: state, SecretType: secretType, Resolution: resolution})
126+
if err != nil {
127+
return nil, fmt.Errorf("failed to list alerts: %w", err)
128+
}
129+
defer func() { _ = resp.Body.Close() }()
130+
131+
if resp.StatusCode != http.StatusOK {
132+
body, err := io.ReadAll(resp.Body)
133+
if err != nil {
134+
return nil, fmt.Errorf("failed to read response body: %w", err)
135+
}
136+
return mcp.NewToolResultError(fmt.Sprintf("failed to list alerts: %s", string(body))), nil
137+
}
138+
139+
r, err := json.Marshal(alerts)
140+
if err != nil {
141+
return nil, fmt.Errorf("failed to marshal alerts: %w", err)
142+
}
143+
144+
return mcp.NewToolResultText(string(r)), nil
145+
}
146+
}

0 commit comments

Comments
 (0)
0