From 05a8efef8e9feacb0462ed2ec54a93a866c7b57d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:03:04 +0000 Subject: [PATCH 1/4] Initial plan From 6b3df9a88e220ec0b0eb6fbd5d93e21d5c33cd00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:06:30 +0000 Subject: [PATCH 2/4] chore: upgrade go-sdk to v1.5.0 Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/09a95415-798b-406d-9dbf-101e2e388180 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index f7782280..9627c2c0 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( github.com/BurntSushi/toml v1.6.0 - github.com/modelcontextprotocol/go-sdk v1.4.1 + github.com/modelcontextprotocol/go-sdk v1.5.0 github.com/spf13/cobra v1.10.2 golang.org/x/term v0.41.0 ) diff --git a/go.sum b/go.sum index 8c290f57..0647d3d6 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -34,8 +34,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/modelcontextprotocol/go-sdk v1.4.1 h1:M4x9GyIPj+HoIlHNGpK2hq5o3BFhC+78PkEaldQRphc= -github.com/modelcontextprotocol/go-sdk v1.4.1/go.mod h1:Bo/mS87hPQqHSRkMv4dQq1XCu6zv4INdXnFZabkNU6s= +github.com/modelcontextprotocol/go-sdk v1.5.0 h1:CHU0FIX9kpueNkxuYtfYQn1Z0slhFzBZuq+x6IiblIU= +github.com/modelcontextprotocol/go-sdk v1.5.0/go.mod h1:gggDIhoemhWs3BGkGwd1umzEXCEMMvAnhTrnbXJKKKA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= From 2d002ac4d893f0dbb302a76c01e05ded1bc436de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:09:45 +0000 Subject: [PATCH 3/4] fix: replace string-matching session error with sdk.ErrSessionMissing, route SSE warnings to structured logger, update tool_registry comment Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/09a95415-798b-406d-9dbf-101e2e388180 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- internal/mcp/connection.go | 8 ++++---- internal/mcp/http_transport.go | 7 ++++++- internal/server/tool_registry.go | 9 ++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/internal/mcp/connection.go b/internal/mcp/connection.go index abf68b02..e5fd1f86 100644 --- a/internal/mcp/connection.go +++ b/internal/mcp/connection.go @@ -248,10 +248,10 @@ func NewHTTPConnection(ctx context.Context, serverID, url string, headers map[st conn, err = trySSETransport(ctx, cancel, serverID, url, headers, headerClient, keepAlive) if err == nil { logger.LogWarn("backend", "⚠️ MCP over SSE has been deprecated. Connected using SSE transport for url=%s. Please migrate to streamable HTTP transport (2025-03-26 spec).", url) - log.Printf("⚠️ WARNING: MCP over SSE (2024-11-05 spec) has been DEPRECATED") - log.Printf("⚠️ The server at %s is using the deprecated SSE transport", url) - log.Printf("⚠️ Please migrate to streamable HTTP transport (2025-03-26 spec)") - log.Printf("Configured HTTP MCP server with SSE transport: %s", url) + logger.LogWarn("backend", "⚠️ WARNING: MCP over SSE (2024-11-05 spec) has been DEPRECATED") + logger.LogWarn("backend", "⚠️ The server at %s is using the deprecated SSE transport", url) + logger.LogWarn("backend", "⚠️ Please migrate to streamable HTTP transport (2025-03-26 spec)") + logConn.Printf("Configured HTTP MCP server with SSE transport: %s", url) return conn, nil } logConn.Printf("SSE transport failed: %v", err) diff --git a/internal/mcp/http_transport.go b/internal/mcp/http_transport.go index ab4516fd..3c7bb4d4 100644 --- a/internal/mcp/http_transport.go +++ b/internal/mcp/http_transport.go @@ -67,12 +67,17 @@ func isHTTPConnectionError(err error) bool { return false } -// isSessionNotFoundError checks if an error message indicates a backend MCP session has expired +// isSessionNotFoundError checks if an error indicates a backend MCP session has expired // or is not found. This is used to detect when automatic reconnection to the backend is needed. +// It uses errors.Is to check for sdk.ErrSessionMissing (the typed sentinel introduced in v1.5.0), +// and also falls back to string-matching for non-SDK transports that return plain error messages. func isSessionNotFoundError(err error) bool { if err == nil { return false } + if errors.Is(err, sdk.ErrSessionMissing) { + return true + } return strings.Contains(strings.ToLower(err.Error()), "session not found") } diff --git a/internal/server/tool_registry.go b/internal/server/tool_registry.go index eff7c00b..65ce9ce0 100644 --- a/internal/server/tool_registry.go +++ b/internal/server/tool_registry.go @@ -44,9 +44,12 @@ type launchResult struct { // The wrapper in this function adapts the three-argument form back to the SDK's two-argument // form when registering with the SDK server. // -// NOTE: The Server.AddTool method (used here) skips JSON Schema validation whereas the -// sdk.AddTool function validates the schema. This distinction relies on internal SDK -// behaviour and must be re-verified on every SDK upgrade. +// NOTE: The Server.AddTool method (used here) does not validate tool arguments against the +// input schema at call time, whereas the package-level sdk.AddTool function does. The method +// does require that InputSchema is non-nil and has type "object" (enforced since v1.5.0), but +// it does not validate the argument values — that responsibility belongs to the caller. +// This distinction relies on internal SDK behaviour and must be re-verified on every SDK upgrade. +// Verified correct for go-sdk v1.5.0 (see server.go:Server.AddTool vs AddTool[In,Out]). func registerToolWithoutValidation(server *sdk.Server, tool *sdk.Tool, handler func(context.Context, *sdk.CallToolRequest, interface{}) (*sdk.CallToolResult, interface{}, error)) { server.AddTool(tool, func(ctx context.Context, req *sdk.CallToolRequest) (*sdk.CallToolResult, error) { result, _, err := handler(ctx, req, nil) From 53b7390b9a91688880252e1ab784e575ce6383e1 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Sat, 11 Apr 2026 14:27:06 -0700 Subject: [PATCH 4/4] Address review: add sentinel test cases, use structured logger for SSE warning - Add test cases for sdk.ErrSessionMissing sentinel and wrapped form to TestIsSessionNotFoundError, ensuring typed-sentinel detection won't silently regress on future SDK upgrades. - Replace debug-gated logConn.Printf with logger.LogWarn for the SSE transport configuration message, ensuring operator visibility in mcp-gateway.log at WARN level. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- internal/mcp/connection.go | 2 +- internal/mcp/http_transport_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/mcp/connection.go b/internal/mcp/connection.go index e5fd1f86..57374691 100644 --- a/internal/mcp/connection.go +++ b/internal/mcp/connection.go @@ -251,7 +251,7 @@ func NewHTTPConnection(ctx context.Context, serverID, url string, headers map[st logger.LogWarn("backend", "⚠️ WARNING: MCP over SSE (2024-11-05 spec) has been DEPRECATED") logger.LogWarn("backend", "⚠️ The server at %s is using the deprecated SSE transport", url) logger.LogWarn("backend", "⚠️ Please migrate to streamable HTTP transport (2025-03-26 spec)") - logConn.Printf("Configured HTTP MCP server with SSE transport: %s", url) + logger.LogWarn("backend", "Configured HTTP MCP server with SSE transport: %s", url) return conn, nil } logConn.Printf("SSE transport failed: %v", err) diff --git a/internal/mcp/http_transport_test.go b/internal/mcp/http_transport_test.go index e2f0c592..05322092 100644 --- a/internal/mcp/http_transport_test.go +++ b/internal/mcp/http_transport_test.go @@ -12,6 +12,7 @@ import ( "time" "github.com/github/gh-aw-mcpg/internal/oidc" + sdk "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -875,6 +876,8 @@ func TestIsSessionNotFoundError(t *testing.T) { {name: "uppercase returns true", err: fmt.Errorf("Session Not Found"), want: true}, {name: "embedded in longer message returns true", err: fmt.Errorf("Streamable HTTP error: Error POSTing to endpoint: session not found"), want: true}, {name: "session expired message returns false", err: fmt.Errorf("session expired"), want: false}, + {name: "sdk ErrSessionMissing sentinel returns true", err: sdk.ErrSessionMissing, want: true}, + {name: "wrapped sdk ErrSessionMissing returns true", err: fmt.Errorf("transport failure: %w", sdk.ErrSessionMissing), want: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {