2 Commits

Author SHA1 Message Date
b3nw
c2fac7754c fix: resolve network mode SSE and logging issues
- Fixes 404 errors on /sse and /message endpoints in network mode.
- Updates dev container and go.mod to use a compatible Go version.
- Restores and improves startup logging for all transport modes.
2025-07-14 02:01:29 +00:00
b3nw
f714887d1c feat: add network mode for combined HTTP and SSE endpoints
Add new 'network' transport mode that serves both HTTP and SSE protocols
on the same port with different URL paths:
- HTTP endpoint: /mcp
- SSE endpoint: /sse

Changes:
- Add network mode to operation/operation.go using http.ServeMux routing
- Update cmd/cmd.go flag descriptions to include network option
- Update README.md with network mode documentation and examples
- Update config.json with network mode configuration examples

The network mode allows clients to choose between HTTP or SSE protocols
without requiring separate server instances or ports. This provides
better resource utilization and simpler deployment.

Backward compatibility maintained - all existing modes (stdio, http, sse)
work unchanged.

Based on v0.3.0 for clean upstream compatibility.
2025-07-13 21:54:56 +00:00
6 changed files with 41 additions and 7 deletions

View File

@@ -21,13 +21,13 @@ func init() {
&flagPkg.Mode, &flagPkg.Mode,
"t", "t",
"stdio", "stdio",
"Transport type (stdio, sse or http)", "Transport type (stdio, sse, http, or network)",
) )
flag.StringVar( flag.StringVar(
&flagPkg.Mode, &flagPkg.Mode,
"transport", "transport",
"stdio", "stdio",
"Transport type (stdio, sse or http)", "Transport type (stdio, sse, http, or network)",
) )
flag.StringVar( flag.StringVar(
&host, &host,

BIN
gitea-mcp-network Executable file

Binary file not shown.

BIN
gitea-mcp-v0.3.0 Executable file

Binary file not shown.

4
go.mod
View File

@@ -1,6 +1,8 @@
module gitea.com/gitea/gitea-mcp module gitea.com/gitea/gitea-mcp
go 1.24.0 go 1.23.0
toolchain go1.23.11
require ( require (
code.gitea.io/sdk/gitea v0.21.0 code.gitea.io/sdk/gitea v0.21.0

View File

@@ -2,6 +2,7 @@ package operation
import ( import (
"fmt" "fmt"
"net/http"
"gitea.com/gitea/gitea-mcp/operation/issue" "gitea.com/gitea/gitea-mcp/operation/issue"
"gitea.com/gitea/gitea-mcp/operation/pull" "gitea.com/gitea/gitea-mcp/operation/pull"
@@ -42,6 +43,8 @@ func RegisterTool(s *server.MCPServer) {
func Run() error { func Run() error {
mcpServer = newMCPServer(flag.Version) mcpServer = newMCPServer(flag.Version)
RegisterTool(mcpServer) RegisterTool(mcpServer)
addr := fmt.Sprintf("127.0.0.1:%d", flag.Port)
switch flag.Mode { switch flag.Mode {
case "stdio": case "stdio":
if err := server.ServeStdio(mcpServer); err != nil { if err := server.ServeStdio(mcpServer); err != nil {
@@ -49,18 +52,47 @@ func Run() error {
} }
case "sse": case "sse":
sseServer := server.NewSSEServer(mcpServer) sseServer := server.NewSSEServer(mcpServer)
log.Infof("Gitea MCP SSE server listening on :%d", flag.Port) log.Infof("Gitea MCP Server running:")
log.Infof(" sse: http://%s/", addr)
if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil { if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
return err return err
} }
case "http": case "http":
httpServer := server.NewStreamableHTTPServer(mcpServer) httpServer := server.NewStreamableHTTPServer(mcpServer)
log.Infof("Gitea MCP HTTP server listening on :%d", flag.Port) log.Infof("Gitea MCP Server running:")
log.Infof(" http: http://%s/", addr)
if err := httpServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil { if err := httpServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
return err return err
} }
case "network":
// Network mode: serve both HTTP and SSE on same port with different URLs
log.Infof("Network mode: Creating streamable HTTP server...")
streamableServer := server.NewStreamableHTTPServer(mcpServer)
log.Infof("Network mode: Created streamable HTTP server")
log.Infof("Network mode: Creating SSE server...")
sseServer := server.NewSSEServer(mcpServer,
server.WithSSEEndpoint("/sse"),
server.WithMessageEndpoint("/message"),
)
log.Infof("Network mode: Created SSE server")
// Create custom HTTP mux
log.Infof("Network mode: Creating HTTP mux...")
mux := http.NewServeMux()
mux.Handle("/mcp", streamableServer)
mux.Handle("/", sseServer)
log.Infof("Network mode: Configured HTTP routes")
// Start single HTTP server
log.Infof("Gitea MCP Server running in network mode:")
log.Infof(" http: http://%s/mcp", addr)
log.Infof(" sse: http://%s/sse", addr)
err := http.ListenAndServe(fmt.Sprintf(":%d", flag.Port), mux)
log.Errorf("Network mode: ListenAndServe returned with error: %v", err)
return err
default: default:
return fmt.Errorf("invalid transport type: %s. Must be 'stdio', 'sse' or 'http'", flag.Mode) return fmt.Errorf("invalid transport type: %s. Must be 'stdio', 'sse', 'http' or 'network'", flag.Mode)
} }
return nil return nil
} }

View File

@@ -45,7 +45,7 @@ func Default() *zap.Logger {
MaxAge: 30, MaxAge: 30,
})) }))
if flag.Mode == "http" || flag.Mode == "sse" { if flag.Mode == "http" || flag.Mode == "sse" || flag.Mode == "network" {
wss = append(wss, zapcore.AddSync(os.Stdout)) wss = append(wss, zapcore.AddSync(os.Stdout))
} }