@@ -52,15 +52,15 @@ var _ ClientSession = (*sseSession)(nil)
52
52
// SSEServer implements a Server-Sent Events (SSE) based MCP server.
53
53
// It provides real-time communication capabilities over HTTP using the SSE protocol.
54
54
type SSEServer struct {
55
- server * MCPServer
56
- baseURL string
57
- basePath string
58
- messageEndpoint string
59
- isCompleteMessageEndpoint bool
60
- sseEndpoint string
61
- sessions sync.Map
62
- srv * http.Server
63
- contextFunc SSEContextFunc
55
+ server * MCPServer
56
+ baseURL string
57
+ basePath string
58
+ messageEndpoint string
59
+ useFullURLForMessageEndpoint bool
60
+ sseEndpoint string
61
+ sessions sync.Map
62
+ srv * http.Server
63
+ contextFunc SSEContextFunc
64
64
}
65
65
66
66
// SSEOption defines a function type for configuring SSEServer
@@ -107,10 +107,12 @@ func WithMessageEndpoint(endpoint string) SSEOption {
107
107
}
108
108
}
109
109
110
- // WithIsCompleteMessageEndpoint sets the flag for whether the endpoint is for complete messages or not
111
- func WithIsCompleteMessageEndpoint (isCompleteMessageEndpoint bool ) SSEOption {
110
+ // WithUseFullURLForMessageEndpoint controls whether the SSE server returns a complete URL (including baseURL)
111
+ // or just the path portion for the message endpoint. Set to false when clients will concatenate
112
+ // the baseURL themselves to avoid malformed URLs like "http://localhost/mcphttp://localhost/mcp/message".
113
+ func WithUseFullURLForMessageEndpoint (useFullURLForMessageEndpoint bool ) SSEOption {
112
114
return func (s * SSEServer ) {
113
- s .isCompleteMessageEndpoint = isCompleteMessageEndpoint
115
+ s .useFullURLForMessageEndpoint = useFullURLForMessageEndpoint
114
116
}
115
117
}
116
118
@@ -139,10 +141,10 @@ func WithSSEContextFunc(fn SSEContextFunc) SSEOption {
139
141
// NewSSEServer creates a new SSE server instance with the given MCP server and options.
140
142
func NewSSEServer (server * MCPServer , opts ... SSEOption ) * SSEServer {
141
143
s := & SSEServer {
142
- server : server ,
143
- sseEndpoint : "/sse" ,
144
- messageEndpoint : "/message" ,
145
- isCompleteMessageEndpoint : true ,
144
+ server : server ,
145
+ sseEndpoint : "/sse" ,
146
+ messageEndpoint : "/message" ,
147
+ useFullURLForMessageEndpoint : true ,
146
148
}
147
149
148
150
// Apply all options
@@ -252,9 +254,10 @@ func (s *SSEServer) handleSSE(w http.ResponseWriter, r *http.Request) {
252
254
}
253
255
}
254
256
}()
255
-
257
+ // Use either just the path or the complete URL based on configuration.
258
+ // This prevents issues with clients that concatenate the base URL themselves.
256
259
messageEndpoint := s .messageEndpoint
257
- if s .isCompleteMessageEndpoint {
260
+ if s .useFullURLForMessageEndpoint {
258
261
messageEndpoint = s .CompleteMessageEndpoint ()
259
262
}
260
263
messageEndpoint = fmt .Sprintf ("%s?sessionId=%s" , messageEndpoint , sessionID )
0 commit comments