Skip to content

Commit 9db748b

Browse files
authored
Merge branch 'main' into feat/259/assign-reviewers
2 parents 3234755 + 7c197f5 commit 9db748b

File tree

5 files changed

+418
-3
lines changed

5 files changed

+418
-3
lines changed

.gitignore

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
@@ -439,6 +437,21 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
439437
- `severity`: Alert severity (string, optional)
440438
- `tool_name`: The name of the tool used for code scanning (string, optional)
441439

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

444457
### 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)