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
9 changed files with 54 additions and 85 deletions

View File

@@ -133,16 +133,20 @@ To configure the MCP server for Gitea, add the following to your MCP configurati
} }
``` ```
- **network mode** (provides both HTTP and SSE endpoints) - **sse mode**
Start the server in network mode: ```json
```bash {
gitea-mcp -t network --host https://gitea.com --token <your-token> --port 8080 "mcpServers": {
"gitea": {
"url": "http://localhost:8080/sse"
}
}
}
``` ```
Then configure your MCP client with either endpoint: - **http mode**
**HTTP endpoint:**
```json ```json
{ {
"mcpServers": { "mcpServers": {
@@ -153,17 +157,6 @@ Then configure your MCP client with either endpoint:
} }
``` ```
**SSE endpoint:**
```json
{
"mcpServers": {
"gitea": {
"url": "http://localhost:8081/sse"
}
}
}
```
**Default log path**: `$HOME/.gitea-mcp/gitea-mcp.log` **Default log path**: `$HOME/.gitea-mcp/gitea-mcp.log`
> [!NOTE] > [!NOTE]

View File

@@ -20,14 +20,14 @@ func init() {
flag.StringVar( flag.StringVar(
&flagPkg.Mode, &flagPkg.Mode,
"t", "t",
"network", "stdio",
"Transport type (stdio, http, sse, or network). Network mode starts both HTTP and SSE servers", "Transport type (stdio, sse, http, or network)",
) )
flag.StringVar( flag.StringVar(
&flagPkg.Mode, &flagPkg.Mode,
"transport", "transport",
"network", "stdio",
"Transport type (stdio, http, sse, or network). Network mode starts both HTTP and SSE servers", "Transport type (stdio, sse, http, or network)",
) )
flag.StringVar( flag.StringVar(
&host, &host,
@@ -39,7 +39,7 @@ func init() {
&port, &port,
"port", "port",
8080, 8080,
"Network server port (used for both HTTP and SSE endpoints)", "see or http port",
) )
flag.StringVar( flag.StringVar(
&token, &token,

View File

@@ -1,6 +1,6 @@
{ {
"mcpServers": { "mcpServers": {
"gitea-stdio": { "gitea": {
"command": "gitea-mcp", "command": "gitea-mcp",
"args": { "args": {
"-t": "stdio", "-t": "stdio",
@@ -11,12 +11,6 @@
"GITEA_HOST": "https://gitea.com", "GITEA_HOST": "https://gitea.com",
"GITEA_ACCESS_TOKEN": "<your personal access token>" "GITEA_ACCESS_TOKEN": "<your personal access token>"
} }
},
"gitea-network-http": {
"url": "http://localhost:8080/mcp"
},
"gitea-network-sse": {
"url": "http://localhost:8081/sse"
} }
} }
} }

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,53 +43,56 @@ 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 {
return err return err
} }
case "http":
httpServer := server.NewStreamableHTTPServer(mcpServer)
log.Infof("Gitea MCP HTTP server listening on :%d", flag.Port)
if err := httpServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
return err
}
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 "network": case "http":
// Network mode: start both HTTP and SSE servers concurrently
log.Infof("Starting Gitea MCP server in network mode")
errChan := make(chan error, 2)
// Start HTTP server on port
go func() {
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 {
errChan <- fmt.Errorf("HTTP server error: %w", 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")
// Start SSE server on port+1 log.Infof("Network mode: Creating SSE server...")
go func() { sseServer := server.NewSSEServer(mcpServer,
sseServer := server.NewSSEServer(mcpServer) server.WithSSEEndpoint("/sse"),
ssePort := flag.Port + 1 server.WithMessageEndpoint("/message"),
log.Infof("Gitea MCP SSE server listening on :%d", ssePort) )
if err := sseServer.Start(fmt.Sprintf(":%d", ssePort)); err != nil { log.Infof("Network mode: Created SSE server")
errChan <- fmt.Errorf("SSE server error: %w", err)
}
}()
// Wait for first error // Create custom HTTP mux
return <-errChan 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', 'http', 'sse' or 'network'", 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))
} }

View File

@@ -1,24 +0,0 @@
# Releases
## v0.5.0-combined - Network Mode
This directory contains binary releases for the combined server implementation.
### Features
- Network mode with both HTTP and SSE endpoints available simultaneously
- HTTP endpoint on specified port (/mcp)
- SSE endpoint on port+1 (/sse)
- Backward compatibility with stdio, http, sse modes
### Usage
```bash
# Download and make executable
chmod +x gitea-mcp-combined
# Start network mode
./gitea-mcp-combined -t network --host https://gitea.ext.ben.io --token <token> --port 8080
```
### Endpoints
- HTTP: http://localhost:8080/mcp
- SSE: http://localhost:8081/sse