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

Add OAuth scope metadata to all MCP tools#1679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
Copilot wants to merge5 commits intomain
base:main
Choose a base branch
Loading
fromcopilot/add-oauth-scopes-documentation
Draft
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletionsREADME.md
View file
Open in desktop

Large diffs are not rendered by default.

43 changes: 37 additions & 6 deletionscmd/github-mcp-server/generate_docs.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,7 +11,6 @@ import (
"github.com/github/github-mcp-server/pkg/inventory"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/spf13/cobra"
)

Expand DownExpand Up@@ -190,7 +189,7 @@ func generateToolsDoc(r *inventory.Inventory) string {
currentToolsetID = tool.Toolset.ID
currentToolsetIcon = tool.Toolset.Icon
}
writeToolDoc(&toolBuf, tool.Tool)
writeToolDoc(&toolBuf, tool)
toolBuf.WriteString("\n\n")
}

Expand DownExpand Up@@ -224,16 +223,26 @@ func formatToolsetName(name string) string {
}
}

func writeToolDoc(buf *strings.Builder, toolmcp.Tool) {
func writeToolDoc(buf *strings.Builder, toolinventory.ServerTool) {
// Tool name (no icon - section header already has the toolset icon)
fmt.Fprintf(buf, "- **%s** - %s\n", tool.Name, tool.Annotations.Title)
fmt.Fprintf(buf, "- **%s** - %s\n", tool.Tool.Name, tool.Tool.Annotations.Title)

// OAuth scopes if present
if len(tool.RequiredScopes) > 0 {
fmt.Fprintf(buf, " - **Required OAuth Scopes**: `%s`\n", strings.Join(tool.RequiredScopes, "`, `"))

// Only show accepted scopes if they differ from required scopes
if len(tool.AcceptedScopes) > 0 && !scopesEqual(tool.RequiredScopes, tool.AcceptedScopes) {
fmt.Fprintf(buf, " - **Accepted OAuth Scopes**: `%s`\n", strings.Join(tool.AcceptedScopes, "`, `"))
}
}

// Parameters
if tool.InputSchema == nil {
if tool.Tool.InputSchema == nil {
buf.WriteString(" - No parameters required")
return
}
schema, ok := tool.InputSchema.(*jsonschema.Schema)
schema, ok := tool.Tool.InputSchema.(*jsonschema.Schema)
if !ok || schema == nil {
buf.WriteString(" - No parameters required")
return
Expand DownExpand Up@@ -282,6 +291,28 @@ func writeToolDoc(buf *strings.Builder, tool mcp.Tool) {
}
}

// scopesEqual checks if two scope slices contain the same elements (order-independent)
func scopesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}

// Create a map for quick lookup
aMap := make(map[string]bool, len(a))
for _, scope := range a {
aMap[scope] = true
}

// Check if all elements in b are in a
for _, scope := range b {
if !aMap[scope] {
return false
}
}

return true
}

func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
Expand Down
37 changes: 37 additions & 0 deletionspkg/github/actions.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import (
buffer "github.com/github/github-mcp-server/pkg/buffer"
ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/inventory"
"github.com/github/github-mcp-server/pkg/scopes"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
Expand DownExpand Up@@ -74,6 +75,8 @@ func ListWorkflows(t translations.TranslationHelperFunc) inventory.ServerTool {
Required: []string{"owner", "repo"},
}),
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -200,6 +203,8 @@ func ListWorkflowRuns(t translations.TranslationHelperFunc) inventory.ServerTool
Required: []string{"owner", "repo", "workflow_id"},
}),
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -311,6 +316,8 @@ func RunWorkflow(t translations.TranslationHelperFunc) inventory.ServerTool {
Required: []string{"owner", "repo", "workflow_id", "ref"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -415,6 +422,8 @@ func GetWorkflowRun(t translations.TranslationHelperFunc) inventory.ServerTool {
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -483,6 +492,8 @@ func GetWorkflowRunLogs(t translations.TranslationHelperFunc) inventory.ServerTo
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -566,6 +577,8 @@ func ListWorkflowJobs(t translations.TranslationHelperFunc) inventory.ServerTool
Required: []string{"owner", "repo", "run_id"},
}),
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -678,6 +691,8 @@ func GetJobLogs(t translations.TranslationHelperFunc) inventory.ServerTool {
Required: []string{"owner", "repo"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -926,6 +941,8 @@ func RerunWorkflowRun(t translations.TranslationHelperFunc) inventory.ServerTool
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1001,6 +1018,8 @@ func RerunFailedJobs(t translations.TranslationHelperFunc) inventory.ServerTool
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1076,6 +1095,8 @@ func CancelWorkflowRun(t translations.TranslationHelperFunc) inventory.ServerToo
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1153,6 +1174,8 @@ func ListWorkflowRunArtifacts(t translations.TranslationHelperFunc) inventory.Se
Required: []string{"owner", "repo", "run_id"},
}),
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1233,6 +1256,8 @@ func DownloadWorkflowRunArtifact(t translations.TranslationHelperFunc) inventory
Required: []string{"owner", "repo", "artifact_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1311,6 +1336,8 @@ func DeleteWorkflowRunLogs(t translations.TranslationHelperFunc) inventory.Serve
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1386,6 +1413,8 @@ func GetWorkflowRunUsage(t translations.TranslationHelperFunc) inventory.ServerT
Required: []string{"owner", "repo", "run_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -1550,6 +1579,8 @@ Use this tool to list workflows in a repository, or list workflow runs, jobs, an
Required: []string{"method", "owner", "repo"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand DownExpand Up@@ -1668,6 +1699,8 @@ Use this tool to get details about individual workflows, workflow runs, jobs, an
Required: []string{"method", "owner", "repo", "resource_id"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand DownExpand Up@@ -1781,6 +1814,8 @@ func ActionsRunTrigger(t translations.TranslationHelperFunc) inventory.ServerToo
Required: []string{"method", "owner", "repo"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand DownExpand Up@@ -1895,6 +1930,8 @@ For single job logs, provide job_id. For all failed jobs in a run, provide run_i
Required: []string{"owner", "repo"},
},
},
scopes.ToStringSlice(scopes.Repo),
scopes.ToStringSlice(scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletionspkg/github/code_scanning.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ import (

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/inventory"
"github.com/github/github-mcp-server/pkg/scopes"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
Expand DownExpand Up@@ -44,6 +45,8 @@ func GetCodeScanningAlert(t translations.TranslationHelperFunc) inventory.Server
Required: []string{"owner", "repo", "alertNumber"},
},
},
scopes.ToStringSlice(scopes.SecurityEvents),
scopes.ToStringSlice(scopes.SecurityEvents, scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand DownExpand Up@@ -135,6 +138,8 @@ func ListCodeScanningAlerts(t translations.TranslationHelperFunc) inventory.Serv
Required: []string{"owner", "repo"},
},
},
scopes.ToStringSlice(scopes.SecurityEvents),
scopes.ToStringSlice(scopes.SecurityEvents, scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletionspkg/github/context_tools.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@ import (

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/inventory"
"github.com/github/github-mcp-server/pkg/scopes"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
Expand DownExpand Up@@ -51,6 +52,8 @@ func GetMe(t translations.TranslationHelperFunc) inventory.ServerTool {
// OpenAI strict mode requires the properties field to be present.
InputSchema: json.RawMessage(`{"type":"object","properties":{}}`),
},
nil, // no required scopes
nil, // no accepted scopes
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, _ map[string]any) (*mcp.CallToolResult, any, error) {
client, err := deps.GetClient(ctx)
if err != nil {
Expand DownExpand Up@@ -129,6 +132,8 @@ func GetTeams(t translations.TranslationHelperFunc) inventory.ServerTool {
},
},
},
scopes.ToStringSlice(scopes.ReadOrg),
scopes.ToStringSlice(scopes.ReadOrg, scopes.WriteOrg, scopes.AdminOrg),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
user, err := OptionalParam[string](args, "user")
if err != nil {
Expand DownExpand Up@@ -231,6 +236,8 @@ func GetTeamMembers(t translations.TranslationHelperFunc) inventory.ServerTool {
Required: []string{"org", "team_slug"},
},
},
scopes.ToStringSlice(scopes.ReadOrg),
scopes.ToStringSlice(scopes.ReadOrg, scopes.WriteOrg, scopes.AdminOrg),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
org, err := RequiredParam[string](args, "org")
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletionspkg/github/dependabot.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@ import (

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/inventory"
"github.com/github/github-mcp-server/pkg/scopes"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
Expand DownExpand Up@@ -45,6 +46,8 @@ func GetDependabotAlert(t translations.TranslationHelperFunc) inventory.ServerTo
Required: []string{"owner", "repo", "alertNumber"},
},
},
scopes.ToStringSlice(scopes.SecurityEvents),
scopes.ToStringSlice(scopes.SecurityEvents, scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand DownExpand Up@@ -128,6 +131,8 @@ func ListDependabotAlerts(t translations.TranslationHelperFunc) inventory.Server
Required: []string{"owner", "repo"},
},
},
scopes.ToStringSlice(scopes.SecurityEvents),
scopes.ToStringSlice(scopes.SecurityEvents, scopes.Repo),
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
Expand Down
30 changes: 26 additions & 4 deletionspkg/github/dependencies.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,21 +148,43 @@ func (d BaseDeps) GetContentWindowSize() int { return d.ContentWindowSize }
//
// The handler function receives deps extracted from context via MustDepsFromContext.
// Ensure ContextWithDeps is called to inject deps before any tool handlers are invoked.
func NewTool[In, Out any](toolset inventory.ToolsetMetadata, tool mcp.Tool, handler func(ctx context.Context, deps ToolDependencies, req *mcp.CallToolRequest, args In) (*mcp.CallToolResult, Out, error)) inventory.ServerTool {
return inventory.NewServerToolWithContextHandler(tool, toolset, func(ctx context.Context, req *mcp.CallToolRequest, args In) (*mcp.CallToolResult, Out, error) {
//
// All tools must explicitly specify their OAuth scope requirements, even if empty (nil).
func NewTool[In, Out any](
toolset inventory.ToolsetMetadata,
tool mcp.Tool,
requiredScopes []string,
acceptedScopes []string,
handler func(ctx context.Context, deps ToolDependencies, req *mcp.CallToolRequest, args In) (*mcp.CallToolResult, Out, error),
) inventory.ServerTool {
st := inventory.NewServerToolWithContextHandler(tool, toolset, func(ctx context.Context, req *mcp.CallToolRequest, args In) (*mcp.CallToolResult, Out, error) {
deps := MustDepsFromContext(ctx)
return handler(ctx, deps, req, args)
})
st.RequiredScopes = requiredScopes
st.AcceptedScopes = acceptedScopes
return st
}

// NewToolFromHandler creates a ServerTool that retrieves ToolDependencies from context at call time.
// Use this when you have a handler that conforms to mcp.ToolHandler directly.
//
// The handler function receives deps extracted from context via MustDepsFromContext.
// Ensure ContextWithDeps is called to inject deps before any tool handlers are invoked.
func NewToolFromHandler(toolset inventory.ToolsetMetadata, tool mcp.Tool, handler func(ctx context.Context, deps ToolDependencies, req *mcp.CallToolRequest) (*mcp.CallToolResult, error)) inventory.ServerTool {
return inventory.NewServerToolWithRawContextHandler(tool, toolset, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
//
// All tools must explicitly specify their OAuth scope requirements, even if empty (nil).
func NewToolFromHandler(
toolset inventory.ToolsetMetadata,
tool mcp.Tool,
requiredScopes []string,
acceptedScopes []string,
handler func(ctx context.Context, deps ToolDependencies, req *mcp.CallToolRequest) (*mcp.CallToolResult, error),
) inventory.ServerTool {
st := inventory.NewServerToolWithRawContextHandler(tool, toolset, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
deps := MustDepsFromContext(ctx)
return handler(ctx, deps, req)
})
st.RequiredScopes = requiredScopes
st.AcceptedScopes = acceptedScopes
return st
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp