From 8589044ea55ce24bd4db416e8f1d7ac158b967e8 Mon Sep 17 00:00:00 2001 From: LuluBeatson Date: Thu, 3 Jul 2025 11:08:33 +0100 Subject: [PATCH 1/4] add dependabit get and list tools --- pkg/github/dependabot.go | 161 +++++++++++++++++++++++++++++++++++++++ pkg/github/tools.go | 15 ++++ 2 files changed, 176 insertions(+) create mode 100644 pkg/github/dependabot.go diff --git a/pkg/github/dependabot.go b/pkg/github/dependabot.go new file mode 100644 index 000000000..af21b83d1 --- /dev/null +++ b/pkg/github/dependabot.go @@ -0,0 +1,161 @@ +package github + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + ghErrors "github.com/github/github-mcp-server/pkg/errors" + "github.com/github/github-mcp-server/pkg/translations" + "github.com/google/go-github/v72/github" + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" +) + +func GetDependabotAlert(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) { + return mcp.NewTool( + "get_dependabot_alert", + mcp.WithDescription(t("TOOL_GET_DEPENDABOT_ALERT_DESCRIPTION", "Get details of a specific dependabot alert in a GitHub repository.")), + mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: t("TOOL_GET_DEPENDABOT_ALERT_USER_TITLE", "Get dependabot alert"), + ReadOnlyHint: ToBoolPtr(true), + }), + mcp.WithString("owner", + mcp.Required(), + mcp.Description("The owner of the repository."), + ), + mcp.WithString("repo", + mcp.Required(), + mcp.Description("The name of the repository."), + ), + mcp.WithNumber("alertNumber", + mcp.Required(), + mcp.Description("The number of the alert."), + ), + ), + func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + owner, err := RequiredParam[string](request, "owner") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + repo, err := RequiredParam[string](request, "repo") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + alertNumber, err := RequiredInt(request, "alertNumber") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + + client, err := getClient(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get GitHub client: %w", err) + } + + alert, resp, err := client.Dependabot.GetRepoAlert(ctx, owner, repo, alertNumber) + if err != nil { + return ghErrors.NewGitHubAPIErrorResponse(ctx, + fmt.Sprintf("failed to get alert with number '%d'", alertNumber), + resp, + err, + ), nil + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + return mcp.NewToolResultError(fmt.Sprintf("failed to get alert: %s", string(body))), nil + } + + r, err := json.Marshal(alert) + if err != nil { + return nil, fmt.Errorf("failed to marshal alert: %w", err) + } + + return mcp.NewToolResultText(string(r)), nil + } +} + +func ListDependabotAlerts(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) { + return mcp.NewTool( + "list_dependabot_alerts", + mcp.WithDescription(t("TOOL_LIST_DEPENDABOT_ALERTS_DESCRIPTION", "List dependabot alerts in a GitHub repository.")), + mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: t("TOOL_LIST_DEPENDABOT_ALERTS_USER_TITLE", "List dependabot alerts"), + ReadOnlyHint: ToBoolPtr(true), + }), + mcp.WithString("owner", + mcp.Required(), + mcp.Description("The owner of the repository."), + ), + mcp.WithString("repo", + mcp.Required(), + mcp.Description("The name of the repository."), + ), + mcp.WithString("state", + mcp.Description("Filter dependabot alerts by state. Defaults to open"), + mcp.DefaultString("open"), + mcp.Enum("open", "fixed", "dismissed", "auto_dismissed"), + ), + mcp.WithString("severity", + mcp.Description("Filter dependabot alerts by severity"), + mcp.Enum("low", "medium", "high", "critical"), + ), + ), + func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + owner, err := RequiredParam[string](request, "owner") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + repo, err := RequiredParam[string](request, "repo") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + state, err := OptionalParam[string](request, "state") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + severity, err := OptionalParam[string](request, "severity") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + + client, err := getClient(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get GitHub client: %w", err) + } + + alerts, resp, err := client.Dependabot.ListRepoAlerts(ctx, owner, repo, &github.ListAlertsOptions{ + State: ToStringPtr(state), + Severity: ToStringPtr(severity), + }) + if err != nil { + return ghErrors.NewGitHubAPIErrorResponse(ctx, + fmt.Sprintf("failed to list alerts for repository '%s/%s'", owner, repo), + resp, + err, + ), nil + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + return mcp.NewToolResultError(fmt.Sprintf("failed to list alerts: %s", string(body))), nil + } + + r, err := json.Marshal(alerts) + if err != nil { + return nil, fmt.Errorf("failed to marshal alerts: %w", err) + } + + return mcp.NewToolResultText(string(r)), nil + } +} diff --git a/pkg/github/tools.go b/pkg/github/tools.go index 9f36cfc3d..459b29ead 100644 --- a/pkg/github/tools.go +++ b/pkg/github/tools.go @@ -103,6 +103,11 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG toolsets.NewServerTool(GetSecretScanningAlert(getClient, t)), toolsets.NewServerTool(ListSecretScanningAlerts(getClient, t)), ) + dependabot := toolsets.NewToolset("dependabot", "Dependabot alerts tools"). + AddReadTools( + toolsets.NewServerTool(GetDependabotAlert(getClient, t)), + toolsets.NewServerTool(ListDependabotAlerts(getClient, t)), + ) notifications := toolsets.NewToolset("notifications", "GitHub Notifications related tools"). AddReadTools( @@ -162,6 +167,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG tsg.AddToolset(actions) tsg.AddToolset(codeSecurity) tsg.AddToolset(secretProtection) + tsg.AddToolset(dependabot) tsg.AddToolset(notifications) tsg.AddToolset(experiments) tsg.AddToolset(discussions) @@ -188,3 +194,12 @@ func InitDynamicToolset(s *server.MCPServer, tsg *toolsets.ToolsetGroup, t trans func ToBoolPtr(b bool) *bool { return &b } + +// ToStringPtr converts a string to a *string pointer. +// Returns nil if the string is empty. +func ToStringPtr(s string) *string { + if s == "" { + return nil + } + return &s +} From 0ea24f29e6862ea5c0a8632a613ec4e951f34d83 Mon Sep 17 00:00:00 2001 From: LuluBeatson Date: Thu, 3 Jul 2025 11:16:14 +0100 Subject: [PATCH 2/4] add toolsnaps --- .../__toolsnaps__/get_dependabot_alert.snap | 30 ++++++++++++ .../__toolsnaps__/list_dependabot_alerts.snap | 46 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 pkg/github/__toolsnaps__/get_dependabot_alert.snap create mode 100644 pkg/github/__toolsnaps__/list_dependabot_alerts.snap diff --git a/pkg/github/__toolsnaps__/get_dependabot_alert.snap b/pkg/github/__toolsnaps__/get_dependabot_alert.snap new file mode 100644 index 000000000..76b5ef126 --- /dev/null +++ b/pkg/github/__toolsnaps__/get_dependabot_alert.snap @@ -0,0 +1,30 @@ +{ + "annotations": { + "title": "Get dependabot alert", + "readOnlyHint": true + }, + "description": "Get details of a specific dependabot alert in a GitHub repository.", + "inputSchema": { + "properties": { + "alertNumber": { + "description": "The number of the alert.", + "type": "number" + }, + "owner": { + "description": "The owner of the repository.", + "type": "string" + }, + "repo": { + "description": "The name of the repository.", + "type": "string" + } + }, + "required": [ + "owner", + "repo", + "alertNumber" + ], + "type": "object" + }, + "name": "get_dependabot_alert" +} \ No newline at end of file diff --git a/pkg/github/__toolsnaps__/list_dependabot_alerts.snap b/pkg/github/__toolsnaps__/list_dependabot_alerts.snap new file mode 100644 index 000000000..681d640b7 --- /dev/null +++ b/pkg/github/__toolsnaps__/list_dependabot_alerts.snap @@ -0,0 +1,46 @@ +{ + "annotations": { + "title": "List dependabot alerts", + "readOnlyHint": true + }, + "description": "List dependabot alerts in a GitHub repository.", + "inputSchema": { + "properties": { + "owner": { + "description": "The owner of the repository.", + "type": "string" + }, + "repo": { + "description": "The name of the repository.", + "type": "string" + }, + "severity": { + "description": "Filter dependabot alerts by severity", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "state": { + "default": "open", + "description": "Filter dependabot alerts by state. Defaults to open", + "enum": [ + "open", + "fixed", + "dismissed", + "auto_dismissed" + ], + "type": "string" + } + }, + "required": [ + "owner", + "repo" + ], + "type": "object" + }, + "name": "list_dependabot_alerts" +} \ No newline at end of file From 6c970a4ba6c5eaa0eeb77c8719eada953f19e3e8 Mon Sep 17 00:00:00 2001 From: LuluBeatson Date: Thu, 3 Jul 2025 11:20:51 +0100 Subject: [PATCH 3/4] add unit tests for new tools --- pkg/github/dependabot_test.go | 276 ++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 pkg/github/dependabot_test.go diff --git a/pkg/github/dependabot_test.go b/pkg/github/dependabot_test.go new file mode 100644 index 000000000..f7c091981 --- /dev/null +++ b/pkg/github/dependabot_test.go @@ -0,0 +1,276 @@ +package github + +import ( + "context" + "encoding/json" + "net/http" + "testing" + + "github.com/github/github-mcp-server/internal/toolsnaps" + "github.com/github/github-mcp-server/pkg/translations" + "github.com/google/go-github/v72/github" + "github.com/migueleliasweb/go-github-mock/src/mock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_GetDependabotAlert(t *testing.T) { + // Verify tool definition + mockClient := github.NewClient(nil) + tool, _ := GetDependabotAlert(stubGetClientFn(mockClient), translations.NullTranslationHelper) + require.NoError(t, toolsnaps.Test(tool.Name, tool)) + + // Validate tool schema + assert.Equal(t, "get_dependabot_alert", tool.Name) + assert.NotEmpty(t, tool.Description) + assert.Contains(t, tool.InputSchema.Properties, "owner") + assert.Contains(t, tool.InputSchema.Properties, "repo") + assert.Contains(t, tool.InputSchema.Properties, "alertNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alertNumber"}) + + // Setup mock alert for success case + mockAlert := &github.DependabotAlert{ + Number: github.Ptr(42), + State: github.Ptr("open"), + HTMLURL: github.Ptr("https://github.com/owner/repo/security/dependabot/42"), + } + + tests := []struct { + name string + mockedClient *http.Client + requestArgs map[string]interface{} + expectError bool + expectedAlert *github.DependabotAlert + expectedErrMsg string + }{ + { + name: "successful alert fetch", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetReposDependabotAlertsByOwnerByRepoByAlertNumber, + mockAlert, + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + "alertNumber": float64(42), + }, + expectError: false, + expectedAlert: mockAlert, + }, + { + name: "alert fetch fails", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposDependabotAlertsByOwnerByRepoByAlertNumber, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + "alertNumber": float64(9999), + }, + expectError: true, + expectedErrMsg: "failed to get alert", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Setup client with mock + client := github.NewClient(tc.mockedClient) + _, handler := GetDependabotAlert(stubGetClientFn(client), translations.NullTranslationHelper) + + // Create call request + request := createMCPRequest(tc.requestArgs) + + // Call handler + result, err := handler(context.Background(), request) + + // Verify results + if tc.expectError { + require.NoError(t, err) + require.True(t, result.IsError) + errorContent := getErrorResult(t, result) + assert.Contains(t, errorContent.Text, tc.expectedErrMsg) + return + } + + require.NoError(t, err) + require.False(t, result.IsError) + + // Parse the result and get the text content if no error + textContent := getTextResult(t, result) + + // Unmarshal and verify the result + var returnedAlert github.DependabotAlert + err = json.Unmarshal([]byte(textContent.Text), &returnedAlert) + assert.NoError(t, err) + assert.Equal(t, *tc.expectedAlert.Number, *returnedAlert.Number) + assert.Equal(t, *tc.expectedAlert.State, *returnedAlert.State) + assert.Equal(t, *tc.expectedAlert.HTMLURL, *returnedAlert.HTMLURL) + }) + } +} + +func Test_ListDependabotAlerts(t *testing.T) { + // Verify tool definition once + mockClient := github.NewClient(nil) + tool, _ := ListDependabotAlerts(stubGetClientFn(mockClient), translations.NullTranslationHelper) + require.NoError(t, toolsnaps.Test(tool.Name, tool)) + + assert.Equal(t, "list_dependabot_alerts", tool.Name) + assert.NotEmpty(t, tool.Description) + assert.Contains(t, tool.InputSchema.Properties, "owner") + assert.Contains(t, tool.InputSchema.Properties, "repo") + assert.Contains(t, tool.InputSchema.Properties, "state") + assert.Contains(t, tool.InputSchema.Properties, "severity") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"}) + + // Setup mock alerts for success case + criticalAlert := github.DependabotAlert{ + Number: github.Ptr(1), + HTMLURL: github.Ptr("https://github.com/owner/repo/security/dependabot/1"), + State: github.Ptr("open"), + SecurityAdvisory: &github.DependabotSecurityAdvisory{ + Severity: github.Ptr("critical"), + }, + } + highSeverityAlert := github.DependabotAlert{ + Number: github.Ptr(2), + HTMLURL: github.Ptr("https://github.com/owner/repo/security/dependabot/2"), + State: github.Ptr("fixed"), + SecurityAdvisory: &github.DependabotSecurityAdvisory{ + Severity: github.Ptr("high"), + }, + } + + tests := []struct { + name string + mockedClient *http.Client + requestArgs map[string]interface{} + expectError bool + expectedAlerts []*github.DependabotAlert + expectedErrMsg string + }{ + { + name: "successful open alerts listing", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposDependabotAlertsByOwnerByRepo, + expectQueryParams(t, map[string]string{ + "state": "open", + }).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert}), + ), + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + "state": "open", + }, + expectError: false, + expectedAlerts: []*github.DependabotAlert{&criticalAlert}, + }, + { + name: "successful severity filtered listing", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposDependabotAlertsByOwnerByRepo, + expectQueryParams(t, map[string]string{ + "severity": "high", + }).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&highSeverityAlert}), + ), + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + "severity": "high", + }, + expectError: false, + expectedAlerts: []*github.DependabotAlert{&highSeverityAlert}, + }, + { + name: "successful all alerts listing", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposDependabotAlertsByOwnerByRepo, + expectQueryParams(t, map[string]string{}).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert, &highSeverityAlert}), + ), + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + }, + expectError: false, + expectedAlerts: []*github.DependabotAlert{&criticalAlert, &highSeverityAlert}, + }, + { + name: "alerts listing fails", + mockedClient: mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposDependabotAlertsByOwnerByRepo, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message": "Unauthorized access"}`)) + }), + ), + ), + requestArgs: map[string]interface{}{ + "owner": "owner", + "repo": "repo", + }, + expectError: true, + expectedErrMsg: "failed to list alerts", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + client := github.NewClient(tc.mockedClient) + _, handler := ListDependabotAlerts(stubGetClientFn(client), translations.NullTranslationHelper) + + request := createMCPRequest(tc.requestArgs) + + result, err := handler(context.Background(), request) + + if tc.expectError { + require.NoError(t, err) + require.True(t, result.IsError) + errorContent := getErrorResult(t, result) + assert.Contains(t, errorContent.Text, tc.expectedErrMsg) + return + } + + require.NoError(t, err) + require.False(t, result.IsError) + + textContent := getTextResult(t, result) + + // Unmarshal and verify the result + var returnedAlerts []*github.DependabotAlert + err = json.Unmarshal([]byte(textContent.Text), &returnedAlerts) + assert.NoError(t, err) + assert.Len(t, returnedAlerts, len(tc.expectedAlerts)) + for i, alert := range returnedAlerts { + assert.Equal(t, *tc.expectedAlerts[i].Number, *alert.Number) + assert.Equal(t, *tc.expectedAlerts[i].HTMLURL, *alert.HTMLURL) + assert.Equal(t, *tc.expectedAlerts[i].State, *alert.State) + if tc.expectedAlerts[i].SecurityAdvisory != nil && tc.expectedAlerts[i].SecurityAdvisory.Severity != nil && + alert.SecurityAdvisory != nil && alert.SecurityAdvisory.Severity != nil { + assert.Equal(t, *tc.expectedAlerts[i].SecurityAdvisory.Severity, *alert.SecurityAdvisory.Severity) + } + } + }) + } +} From c4ac6b5f5f161e7d96574b9e806fd59e4d739c5d Mon Sep 17 00:00:00 2001 From: LuluBeatson Date: Thu, 3 Jul 2025 11:30:08 +0100 Subject: [PATCH 4/4] generate-docs --- README.md | 18 ++++++++++++++++++ docs/remote-server.md | 1 + pkg/github/tools.go | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a0364932..0bb054355 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,7 @@ The following sets of tools are available (all are on by default): | `context` | **Strongly recommended**: Tools that provide context about the current user and GitHub context you are operating in | | `actions` | GitHub Actions workflows and CI/CD operations | | `code_security` | Code security related tools, such as GitHub Code Scanning | +| `dependabot` | Dependabot tools | | `discussions` | GitHub Discussions related tools | | `experiments` | Experimental features that are not considered stable yet | | `issues` | GitHub Issues related tools | @@ -555,6 +556,23 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
+Dependabot + +- **get_dependabot_alert** - Get dependabot alert + - `alertNumber`: The number of the alert. (number, required) + - `owner`: The owner of the repository. (string, required) + - `repo`: The name of the repository. (string, required) + +- **list_dependabot_alerts** - List dependabot alerts + - `owner`: The owner of the repository. (string, required) + - `repo`: The name of the repository. (string, required) + - `severity`: Filter dependabot alerts by severity (string, optional) + - `state`: Filter dependabot alerts by state. Defaults to open (string, optional) + +
+ +
+ Discussions - **get_discussion** - Get discussion diff --git a/docs/remote-server.md b/docs/remote-server.md index 7b5f2c0d4..c36124ecc 100644 --- a/docs/remote-server.md +++ b/docs/remote-server.md @@ -20,6 +20,7 @@ Below is a table of available toolsets for the remote GitHub MCP Server. Each to | all | All available GitHub MCP tools | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2F%22%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Freadonly%22%7D) | | Actions | GitHub Actions workflows and CI/CD operations | https://api.githubcopilot.com/mcp/x/actions | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/actions/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%2Freadonly%22%7D) | | Code Security | Code security related tools, such as GitHub Code Scanning | https://api.githubcopilot.com/mcp/x/code_security | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/code_security/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%2Freadonly%22%7D) | +| Dependabot | Dependabot tools | https://api.githubcopilot.com/mcp/x/dependabot | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/dependabot/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%2Freadonly%22%7D) | | Discussions | GitHub Discussions related tools | https://api.githubcopilot.com/mcp/x/discussions | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-discussions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdiscussions%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/discussions/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-discussions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdiscussions%2Freadonly%22%7D) | | Experiments | Experimental features that are not considered stable yet | https://api.githubcopilot.com/mcp/x/experiments | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-experiments&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fexperiments%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/experiments/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-experiments&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fexperiments%2Freadonly%22%7D) | | Issues | GitHub Issues related tools | https://api.githubcopilot.com/mcp/x/issues | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-issues&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fissues%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/issues/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-issues&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fissues%2Freadonly%22%7D) | diff --git a/pkg/github/tools.go b/pkg/github/tools.go index 459b29ead..a469b7678 100644 --- a/pkg/github/tools.go +++ b/pkg/github/tools.go @@ -103,7 +103,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG toolsets.NewServerTool(GetSecretScanningAlert(getClient, t)), toolsets.NewServerTool(ListSecretScanningAlerts(getClient, t)), ) - dependabot := toolsets.NewToolset("dependabot", "Dependabot alerts tools"). + dependabot := toolsets.NewToolset("dependabot", "Dependabot tools"). AddReadTools( toolsets.NewServerTool(GetDependabotAlert(getClient, t)), toolsets.NewServerTool(ListDependabotAlerts(getClient, t)), pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy