mirror of
https://gitea.com/gitea/gitea-mcp.git
synced 2026-08-03 15:49:23 +02:00
fix(mcp): address SDK migration review
Co-Authored-By: OpenAI Codex (GPT-5) <noreply@openai.com>
This commit is contained in:
+11
-2
@@ -41,6 +41,9 @@ const maxRequestBodyBytes = 32 << 20
|
||||
// session, and initialize takes no token. Clients re-initialize on the 404.
|
||||
const sessionTimeout = 30 * time.Minute
|
||||
|
||||
// httpReadHeaderTimeout bounds slow header reads without limiting SSE writes.
|
||||
const httpReadHeaderTimeout = 10 * time.Second
|
||||
|
||||
var (
|
||||
mcpServer *mcp.Server
|
||||
|
||||
@@ -111,11 +114,15 @@ func newHTTPServer(addr string, s *mcp.Server) *http.Server {
|
||||
&mcp.StreamableHTTPOptions{
|
||||
Logger: log.Slog(),
|
||||
MaxRequestBodyBytes: maxRequestBodyBytes,
|
||||
Stateless: false, // PR 2 switches this on
|
||||
Stateless: false, // SessionTimeout requires stateful sessions.
|
||||
SessionTimeout: sessionTimeout,
|
||||
},
|
||||
))
|
||||
return &http.Server{Addr: addr, Handler: mux}
|
||||
return &http.Server{
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
ReadHeaderTimeout: httpReadHeaderTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
func Run() error {
|
||||
@@ -157,6 +164,8 @@ func Run() error {
|
||||
}
|
||||
|
||||
func newMCPServer(version string) *mcp.Server {
|
||||
// SDK keepalives send MCP ping requests and disconnect clients without a
|
||||
// server-to-client channel, so KeepAlive stays disabled.
|
||||
s := mcp.NewServer(
|
||||
&mcp.Implementation{
|
||||
Name: "Gitea MCP Server",
|
||||
|
||||
@@ -2,6 +2,22 @@ package operation
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewHTTPServerConfig(t *testing.T) {
|
||||
server := newHTTPServer(":12345", newMCPServer("test"))
|
||||
if server.Addr != ":12345" {
|
||||
t.Errorf("Addr = %q, want %q", server.Addr, ":12345")
|
||||
}
|
||||
if server.Handler == nil {
|
||||
t.Error("Handler is nil")
|
||||
}
|
||||
if server.ReadHeaderTimeout != httpReadHeaderTimeout {
|
||||
t.Errorf("ReadHeaderTimeout = %v, want %v", server.ReadHeaderTimeout, httpReadHeaderTimeout)
|
||||
}
|
||||
if server.WriteTimeout != 0 {
|
||||
t.Errorf("WriteTimeout = %v, want zero for SSE", server.WriteTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAuthToken(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -21,7 +21,12 @@ import (
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
const testServerVersion = "test-version"
|
||||
// Pin negotiated versions so SDK upgrades require compatibility review.
|
||||
const (
|
||||
testServerVersion = "test-version"
|
||||
expectedProtocolVersion = "2026-07-28"
|
||||
expectedStatefulHTTPProtocolVersion = "2025-11-25"
|
||||
)
|
||||
|
||||
func exposeAllTools(t *testing.T) {
|
||||
t.Helper()
|
||||
@@ -51,6 +56,21 @@ func registeredToolCount() int {
|
||||
return count
|
||||
}
|
||||
|
||||
// stdioCommandEnvironment removes variables that override subprocess flags.
|
||||
func stdioCommandEnvironment() []string {
|
||||
environment := os.Environ()
|
||||
filtered := make([]string, 0, len(environment))
|
||||
for _, entry := range environment {
|
||||
name, _, _ := strings.Cut(entry, "=")
|
||||
switch name {
|
||||
case "GITEA_READONLY", "GITEA_SCOPES", "GITEA_TOOLS", "MCP_MODE":
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, entry)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func textContent(t *testing.T, result *mcp.CallToolResult) string {
|
||||
t.Helper()
|
||||
if len(result.Content) != 1 {
|
||||
@@ -104,8 +124,8 @@ func TestOfficialSDKInMemory(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Connect() error = %v", err)
|
||||
}
|
||||
if got := session.InitializeResult().ProtocolVersion; got != "2026-07-28" {
|
||||
t.Errorf("protocol version = %q, want %q", got, "2026-07-28")
|
||||
if got := session.InitializeResult().ProtocolVersion; got != expectedProtocolVersion {
|
||||
t.Errorf("protocol version = %q, want %q", got, expectedProtocolVersion)
|
||||
}
|
||||
listAndCallVersion(ctx, t, session, testServerVersion)
|
||||
if err := session.Close(); err != nil {
|
||||
@@ -142,8 +162,9 @@ func TestStreamableHTTPStateful(t *testing.T) {
|
||||
t.Fatalf("Connect() error = %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if got := session.InitializeResult().ProtocolVersion; got != "2025-11-25" {
|
||||
t.Errorf("protocol version = %q, want %q", got, "2025-11-25")
|
||||
// Stateful Streamable HTTP cannot negotiate the sessionless 2026 protocol.
|
||||
if got := session.InitializeResult().ProtocolVersion; got != expectedStatefulHTTPProtocolVersion {
|
||||
t.Errorf("protocol version = %q, want %q", got, expectedStatefulHTTPProtocolVersion)
|
||||
}
|
||||
listAndCallVersion(ctx, t, session, testServerVersion)
|
||||
|
||||
@@ -347,19 +368,27 @@ func TestStdioCommandTransport(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping subprocess build in short mode")
|
||||
}
|
||||
exposeAllTools(t) // the subprocess runs with default flags, so match them here
|
||||
for name, value := range map[string]string{
|
||||
"GITEA_READONLY": "true",
|
||||
"GITEA_SCOPES": "user",
|
||||
"GITEA_TOOLS": "get_me",
|
||||
"MCP_MODE": "http",
|
||||
} {
|
||||
t.Setenv(name, value)
|
||||
}
|
||||
exposeAllTools(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
binary := filepath.Join(t.TempDir(), "gitea-mcp")
|
||||
build := exec.CommandContext(ctx, "go", "build", "-o", binary, "..")
|
||||
build.Env = os.Environ()
|
||||
if output, err := build.CombinedOutput(); err != nil {
|
||||
t.Fatalf("build stdio test binary: %v\n%s", err, output)
|
||||
}
|
||||
|
||||
client := mcp.NewClient(&mcp.Implementation{Name: "gitea-mcp-stdio-test", Version: "1"}, nil)
|
||||
command := exec.CommandContext(ctx, binary, "--transport", "stdio")
|
||||
command.Env = stdioCommandEnvironment()
|
||||
session, err := client.Connect(ctx, &mcp.CommandTransport{
|
||||
Command: command,
|
||||
TerminateDuration: 2 * time.Second,
|
||||
@@ -368,8 +397,8 @@ func TestStdioCommandTransport(t *testing.T) {
|
||||
t.Fatalf("Connect() error = %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if got := session.InitializeResult().ProtocolVersion; got != "2026-07-28" {
|
||||
t.Errorf("protocol version = %q, want %q", got, "2026-07-28")
|
||||
if got := session.InitializeResult().ProtocolVersion; got != expectedProtocolVersion {
|
||||
t.Errorf("protocol version = %q, want %q", got, expectedProtocolVersion)
|
||||
}
|
||||
listAndCallVersion(ctx, t, session, "Gitea MCP Server version:")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user