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

Move to modelcontextprotocol/go-sdk#1415

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

Closed
omgitsads wants to merge23 commits intogithub:mainfromomgitsads:omgitsads/go-sdk
Closed
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
23 commits
Select commitHold shift + click to select a range
d69b616
Move some utilities to go SDK
omgitsadsNov 13, 2025
8084335
Remove commented out tool
omgitsadsNov 13, 2025
5a92f9c
Add intermediate structs for toolsets
omgitsadsNov 13, 2025
385dd8d
Move to go-sdk IOTransport
omgitsadsNov 13, 2025
28bc3f4
Update context tools and tests to use ToolHandlerFor with typed argum…
omgitsadsNov 13, 2025
42ada5f
comment out broken tools for now, we'll tackle them one by one
omgitsadsNov 13, 2025
afc455d
fix schema issues
omgitsadsNov 13, 2025
b2f07e5
Get tests fully working
omgitsadsNov 17, 2025
11a154c
Add sdk migration agent
omgitsadsNov 17, 2025
5483a5b
Lets try actually making the changes in the subagent
omgitsadsNov 17, 2025
cabc7b6
Be explicit about the files to use
omgitsadsNov 17, 2025
99f2d8d
Update about toolsnaps
omgitsadsNov 17, 2025
6fa137b
Add info to allow this to be parallelized
omgitsadsNov 17, 2025
2b323c2
Dont use the request var
omgitsadsNov 17, 2025
6ce7550
Take any ToolHandlerFor
omgitsadsNov 17, 2025
5b4c6df
More info about moved files
omgitsadsNov 17, 2025
655bcca
move files rather than commenting out
omgitsadsNov 17, 2025
c946ada
Move files back, use build tags
omgitsadsNov 17, 2025
3620126
Update licenses
omgitsadsNov 18, 2025
1d257b1
Update agent to use build tags
omgitsadsNov 18, 2025
1e7a3f0
Merge branch 'main' into omgitsads/go-sdk
omgitsadsNov 18, 2025
9f25ebe
Remove dupe import from merge conflict
omgitsadsNov 18, 2025
faa90d2
fix linter issues
omgitsadsNov 18, 2025
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
42 changes: 20 additions & 22 deletionscmd/github-mcp-server/generate_docs.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,7 +14,8 @@ import (
"github.com/github/github-mcp-server/pkg/toolsets"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/shurcooL/githubv4"
"github.com/spf13/cobra"
)
Expand DownExpand Up@@ -224,7 +225,12 @@ func generateToolDoc(tool mcp.Tool) string {
lines = append(lines, fmt.Sprintf("- **%s** - %s", tool.Name, tool.Annotations.Title))

// Parameters
schema := tool.InputSchema
schema, ok := tool.InputSchema.(*jsonschema.Schema)
if !ok {
lines = append(lines, " - No parameters required")
return strings.Join(lines, "\n")
}

if len(schema.Properties) > 0 {
// Get parameter names and sort them for deterministic order
var paramNames []string
Expand All@@ -241,30 +247,22 @@ func generateToolDoc(tool mcp.Tool) string {
requiredStr = "required"
}

// Get the type and description
typeStr := "unknown"
description := ""

if propMap, ok := prop.(map[string]interface{}); ok {
if typeVal, ok := propMap["type"].(string); ok {
if typeVal == "array" {
if items, ok := propMap["items"].(map[string]interface{}); ok {
if itemType, ok := items["type"].(string); ok {
typeStr = itemType + "[]"
}
} else {
typeStr = "array"
}
} else {
typeStr = typeVal
}
}
var typeStr, description string

if desc, ok := propMap["description"].(string); ok {
description = desc
// Get the type and description
switch prop.Type {
case "array":
if prop.Items != nil {
typeStr = prop.Items.Type + "[]"
} else {
typeStr = "array"
}
default:
typeStr = prop.Type
}

description = prop.Description

paramLine := fmt.Sprintf(" - `%s`: %s (%s, %s)", propName, description, typeStr, requiredStr)
lines = append(lines, paramLine)
}
Expand Down
4 changes: 3 additions & 1 deletiongo.mod
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ go 1.24.0

require (
github.com/google/go-github/v79 v79.0.0
github.com/google/jsonschema-go v0.3.0
github.com/josephburnett/jd v1.9.2
github.com/mark3labs/mcp-go v0.36.0
github.com/microcosm-cc/bluemonday v1.0.27
Expand DownExpand Up@@ -40,6 +41,7 @@ require (
github.com/google/go-querystring v1.1.0
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/modelcontextprotocol/go-sdk v1.1.0
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
Expand All@@ -52,7 +54,7 @@ require (
github.com/spf13/pflag v1.0.10
github.com/subosito/gotenv v1.6.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.5.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletionsgo.sum
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,8 @@ github.com/google/go-github/v79 v79.0.0 h1:MdodQojuFPBhmtwHiBcIGLw/e/wei2PvFX9nd
github.com/google/go-github/v79 v79.0.0/go.mod h1:OAFbNhq7fQwohojb06iIIQAB9CBGYLq999myfUFnrS4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
Expand DownExpand Up@@ -63,6 +65,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/migueleliasweb/go-github-mock v1.3.0 h1:2sVP9JEMB2ubQw1IKto3/fzF51oFC6eVWOOFDgQoq88=
github.com/migueleliasweb/go-github-mock v1.3.0/go.mod h1:ipQhV8fTcj/G6m7BKzin08GaJ/3B5/SonRAkgrk0zCY=
github.com/modelcontextprotocol/go-sdk v1.1.0 h1:Qjayg53dnKC4UZ+792W21e4BpwEZBzwgRW6LrjLWSwA=
github.com/modelcontextprotocol/go-sdk v1.1.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
Expand DownExpand Up@@ -112,6 +116,8 @@ golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
Expand Down
134 changes: 77 additions & 57 deletionsinternal/ghmcp/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,6 @@
"context"
"fmt"
"io"
"log"
"log/slog"
"net/http"
"net/url"
Expand All@@ -20,8 +19,7 @@
"github.com/github/github-mcp-server/pkg/raw"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/shurcooL/githubv4"
)

Expand DownExpand Up@@ -54,11 +52,14 @@

// LockdownMode indicates if we should enable lockdown mode
LockdownMode bool

// Logger is used for logging within the server
Logger *slog.Logger
}

const stdioServerLogPrefix = "stdioserver"

Check failure on line 60 in internal/ghmcp/server.go

View workflow job for this annotation

GitHub Actions/ lint

const stdioServerLogPrefix is unused (unused)

Check failure on line 60 in internal/ghmcp/server.go

View workflow job for this annotation

GitHub Actions/ lint

const stdioServerLogPrefix is unused (unused)

func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) {
func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
apiHost, err := parseAPIHost(cfg.Host)
if err != nil {
return nil, fmt.Errorf("failed to parse API host: %w", err)
Expand All@@ -81,34 +82,6 @@
} // We're going to wrap the Transport later in beforeInit
gqlClient := githubv4.NewEnterpriseClient(apiHost.graphqlURL.String(), gqlHTTPClient)

// When a client send an initialize request, update the user agent to include the client info.
beforeInit := func(_ context.Context, _ any, message *mcp.InitializeRequest) {
userAgent := fmt.Sprintf(
"github-mcp-server/%s (%s/%s)",
cfg.Version,
message.Params.ClientInfo.Name,
message.Params.ClientInfo.Version,
)

restClient.UserAgent = userAgent

gqlHTTPClient.Transport = &userAgentTransport{
transport: gqlHTTPClient.Transport,
agent: userAgent,
}
}

hooks := &server.Hooks{
OnBeforeInitialize: []server.OnBeforeInitializeFunc{beforeInit},
OnBeforeAny: []server.BeforeAnyHookFunc{
func(ctx context.Context, _ any, _ mcp.MCPMethod, _ any) {
// Ensure the context is cleared of any previous errors
// as context isn't propagated through middleware
errors.ContextWithGitHubErrors(ctx)
},
},
}

enabledToolsets := cfg.EnabledToolsets

// If dynamic toolsets are enabled, remove "all" from the enabled toolsets
Expand All@@ -135,10 +108,14 @@
// Generate instructions based on enabled toolsets
instructions := github.GenerateInstructions(enabledToolsets)

ghServer := github.NewServer(cfg.Version,
server.WithInstructions(instructions),
server.WithHooks(hooks),
)
ghServer := github.NewServer(cfg.Version, &mcp.ServerOptions{
Instructions: instructions,
Logger: cfg.Logger,
})

// Add middlewares
ghServer.AddReceivingMiddleware(addGitHubAPIErrorToContext)
ghServer.AddReceivingMiddleware(addUserAgentsMiddleware(cfg, restClient, gqlHTTPClient))

getClient := func(_ context.Context) (*gogithub.Client, error) {
return restClient, nil // closing over client
Expand DownExpand Up@@ -229,23 +206,6 @@

t, dumpTranslations := translations.TranslationHelper()

ghServer, err := NewMCPServer(MCPServerConfig{
Version: cfg.Version,
Host: cfg.Host,
Token: cfg.Token,
EnabledToolsets: cfg.EnabledToolsets,
DynamicToolsets: cfg.DynamicToolsets,
ReadOnly: cfg.ReadOnly,
Translator: t,
ContentWindowSize: cfg.ContentWindowSize,
LockdownMode: cfg.LockdownMode,
})
if err != nil {
return fmt.Errorf("failed to create MCP server: %w", err)
}

stdioServer := server.NewStdioServer(ghServer)

var slogHandler slog.Handler
var logOutput io.Writer
if cfg.LogFilePath != "" {
Expand All@@ -261,8 +221,22 @@
}
logger := slog.New(slogHandler)
logger.Info("starting server", "version", cfg.Version, "host", cfg.Host, "dynamicToolsets", cfg.DynamicToolsets, "readOnly", cfg.ReadOnly, "lockdownEnabled", cfg.LockdownMode)
stdLogger := log.New(logOutput, stdioServerLogPrefix, 0)
stdioServer.SetErrorLogger(stdLogger)

ghServer, err := NewMCPServer(MCPServerConfig{
Version: cfg.Version,
Host: cfg.Host,
Token: cfg.Token,
EnabledToolsets: cfg.EnabledToolsets,
DynamicToolsets: cfg.DynamicToolsets,
ReadOnly: cfg.ReadOnly,
Translator: t,
ContentWindowSize: cfg.ContentWindowSize,
LockdownMode: cfg.LockdownMode,
Logger: logger,
})
if err != nil {
return fmt.Errorf("failed to create MCP server: %w", err)
}

if cfg.ExportTranslations {
// Once server is initialized, all translations are loaded
Expand All@@ -272,15 +246,20 @@
// Start listening for messages
errC := make(chan error, 1)
go func() {
in, out := io.Reader(os.Stdin), io.Writer(os.Stdout)
var in io.ReadCloser
var out io.WriteCloser

in = os.Stdin
out = os.Stdout

if cfg.EnableCommandLogging {
loggedIO := mcplog.NewIOLogger(in, out, logger)
in, out = loggedIO, loggedIO
}

// enable GitHub errors in the context
ctx := errors.ContextWithGitHubErrors(ctx)
errC <-stdioServer.Listen(ctx, in, out)
errC <-ghServer.Run(ctx,&mcp.IOTransport{Reader:in,Writer:out})
}()

// Output github-mcp-server string
Expand DownExpand Up@@ -497,3 +476,44 @@
req.Header.Set("Authorization", "Bearer "+t.token)
return t.transport.RoundTrip(req)
}

func addGitHubAPIErrorToContext(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, req mcp.Request) (result mcp.Result, err error) {
// Ensure the context is cleared of any previous errors
// as context isn't propagated through middleware
ctx = errors.ContextWithGitHubErrors(ctx)
return next(ctx, method, req)
}
}

func addUserAgentsMiddleware(cfg MCPServerConfig, restClient *gogithub.Client, gqlHTTPClient *http.Client) func(next mcp.MethodHandler) mcp.MethodHandler {
return func(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, request mcp.Request) (result mcp.Result, err error) {
if method != "initialize" {
return next(ctx, method, request)
}

initializeRequest, ok := request.(*mcp.InitializeRequest)
if !ok {
return next(ctx, method, request)
}

message := initializeRequest
userAgent := fmt.Sprintf(
"github-mcp-server/%s (%s/%s)",
cfg.Version,
message.Params.ClientInfo.Name,
message.Params.ClientInfo.Version,
)

restClient.UserAgent = userAgent

gqlHTTPClient.Transport = &userAgentTransport{
transport: gqlHTTPClient.Transport,
agent: userAgent,
}

return next(ctx, method, request)
}
}
}
7 changes: 4 additions & 3 deletionspkg/errors/error.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,8 +4,9 @@ import (
"context"
"fmt"

"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/modelcontextprotocol/go-sdk/mcp"
)

type GitHubAPIError struct {
Expand DownExpand Up@@ -112,7 +113,7 @@ func NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github
if ctx != nil {
_, _ = addGitHubAPIErrorToContext(ctx, apiErr) // Explicitly ignore error for graceful handling
}
returnmcp.NewToolResultErrorFromErr(message, err)
returnutils.NewToolResultErrorFromErr(message, err)
}

// NewGitHubGraphQLErrorResponse returns an mcp.NewToolResultError and retains the error in the context for access via middleware
Expand All@@ -121,5 +122,5 @@ func NewGitHubGraphQLErrorResponse(ctx context.Context, message string, err erro
if ctx != nil {
_, _ = addGitHubGraphQLErrorToContext(ctx, graphQLErr) // Explicitly ignore error for graceful handling
}
returnmcp.NewToolResultErrorFromErr(message, err)
returnutils.NewToolResultErrorFromErr(message, err)
}
9 changes: 3 additions & 6 deletionspkg/github/__toolsnaps__/get_me.snap
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
{
"annotations": {
"title":"Get my user profile",
"readOnlyHint":true
"readOnlyHint":true,
"title":"Get my user profile"
},
"description": "Get details of the authenticated GitHub user. Use this when a request is about the user's own profile for GitHub. Or when information is missing to build other tool calls.",
"inputSchema": {
"properties": {},
"type": "object"
},
"inputSchema": null,
"name": "get_me"
}
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp