@@ -36,13 +36,6 @@ type sseSession struct {
3636// content. This can be used to inject context values from headers, for example.
3737type SSEContextFunc func (ctx context.Context , r * http.Request ) context.Context
3838
39- // DynamicBasePathFunc allows the user to provide a function to generate the
40- // base path for a given request and sessionID. This is useful for cases where
41- // the base path is not known at the time of SSE server creation, such as when
42- // using a reverse proxy or when the base path is dynamically generated. The
43- // function should return the base path (e.g., "/mcp/tenant123").
44- type DynamicBasePathFunc func (r * http.Request , sessionID string ) string
45-
4639func (s * sseSession ) SessionID () string {
4740 return s .sessionID
4841}
@@ -100,7 +93,7 @@ type SSEServer struct {
10093 sseEndpoint string
10194 sessions sync.Map
10295 srv * http.Server
103- contextFunc SSEContextFunc
96+ contextFunc HTTPContextFunc
10497 dynamicBasePathFunc DynamicBasePathFunc
10598
10699 keepAlive bool
@@ -109,37 +102,38 @@ type SSEServer struct {
109102 mu sync.RWMutex
110103}
111104
112- // SSEOption defines a function type for configuring SSEServer
113- type SSEOption func (* SSEServer )
105+ // Ensure SSEServer implements httpTransportConfigurable
106+ var _ httpTransportConfigurable = (* SSEServer )( nil )
114107
115- // WithBaseURL sets the base URL for the SSE server
116- func WithBaseURL (baseURL string ) SSEOption {
117- return func (s * SSEServer ) {
118- if baseURL != "" {
119- u , err := url .Parse (baseURL )
120- if err != nil {
121- return
122- }
123- if u .Scheme != "http" && u .Scheme != "https" {
124- return
125- }
126- // Check if the host is empty or only contains a port
127- if u .Host == "" || strings .HasPrefix (u .Host , ":" ) {
128- return
129- }
130- if len (u .Query ()) > 0 {
131- return
132- }
108+ // setBasePath sets the static base path (internal use only)
109+ func (s * SSEServer ) setBasePath (basePath string ) {
110+ s .basePath = normalizeURLPath (basePath )
111+ }
112+
113+ // setDynamicBasePath sets the dynamic base path function (internal use only)
114+ func (s * SSEServer ) setDynamicBasePath (fn DynamicBasePathFunc ) {
115+ if fn != nil {
116+ s .dynamicBasePathFunc = func (r * http.Request , sid string ) string {
117+ bp := fn (r , sid )
118+ return normalizeURLPath (bp )
133119 }
134- s .baseURL = strings .TrimSuffix (baseURL , "/" )
135120 }
136121}
137122
138- // WithStaticBasePath adds a new option for setting a static base path
139- func WithStaticBasePath (basePath string ) SSEOption {
140- return func (s * SSEServer ) {
141- s .basePath = normalizeURLPath (basePath )
142- }
123+ // setKeepAliveInterval sets the keep-alive interval (internal use only)
124+ func (s * SSEServer ) setKeepAliveInterval (interval time.Duration ) {
125+ s .keepAlive = true
126+ s .keepAliveInterval = interval
127+ }
128+
129+ // setKeepAlive enables or disables keep-alive (internal use only)
130+ func (s * SSEServer ) setKeepAlive (keepAlive bool ) {
131+ s .keepAlive = keepAlive
132+ }
133+
134+ // setContextFunc sets the context customization function (internal use only)
135+ func (s * SSEServer ) setContextFunc (fn HTTPContextFunc ) {
136+ s .contextFunc = fn
143137}
144138
145139// WithBasePath adds a new option for setting a static base path.
@@ -151,26 +145,11 @@ func WithBasePath(basePath string) SSEOption {
151145 return WithStaticBasePath (basePath )
152146}
153147
154- // WithDynamicBasePath accepts a function for generating the base path. This is
155- // useful for cases where the base path is not known at the time of SSE server
156- // creation, such as when using a reverse proxy or when the server is mounted
157- // at a dynamic path.
158- func WithDynamicBasePath (fn DynamicBasePathFunc ) SSEOption {
159- return func (s * SSEServer ) {
160- if fn != nil {
161- s .dynamicBasePathFunc = func (r * http.Request , sid string ) string {
162- bp := fn (r , sid )
163- return normalizeURLPath (bp )
164- }
165- }
166- }
167- }
168-
169148// WithMessageEndpoint sets the message endpoint path
170149func WithMessageEndpoint (endpoint string ) SSEOption {
171- return func (s * SSEServer ) {
150+ return sseOption ( func (s * SSEServer ) {
172151 s .messageEndpoint = endpoint
173- }
152+ })
174153}
175154
176155// WithAppendQueryToMessageEndpoint configures the SSE server to append the original request's
@@ -179,53 +158,36 @@ func WithMessageEndpoint(endpoint string) SSEOption {
179158// SSE connection request and carry them over to subsequent message requests, maintaining
180159// context or authentication details across the communication channel.
181160func WithAppendQueryToMessageEndpoint () SSEOption {
182- return func (s * SSEServer ) {
161+ return sseOption ( func (s * SSEServer ) {
183162 s .appendQueryToMessageEndpoint = true
184- }
163+ })
185164}
186165
187166// WithUseFullURLForMessageEndpoint controls whether the SSE server returns a complete URL (including baseURL)
188167// or just the path portion for the message endpoint. Set to false when clients will concatenate
189168// the baseURL themselves to avoid malformed URLs like "http://localhost/mcphttp://localhost/mcp/message".
190169func WithUseFullURLForMessageEndpoint (useFullURLForMessageEndpoint bool ) SSEOption {
191- return func (s * SSEServer ) {
170+ return sseOption ( func (s * SSEServer ) {
192171 s .useFullURLForMessageEndpoint = useFullURLForMessageEndpoint
193- }
172+ })
194173}
195174
196175// WithSSEEndpoint sets the SSE endpoint path
197176func WithSSEEndpoint (endpoint string ) SSEOption {
198- return func (s * SSEServer ) {
177+ return sseOption ( func (s * SSEServer ) {
199178 s .sseEndpoint = endpoint
200- }
201- }
202-
203- // WithHTTPServer sets the HTTP server instance
204- func WithHTTPServer (srv * http.Server ) SSEOption {
205- return func (s * SSEServer ) {
206- s .srv = srv
207- }
208- }
209-
210- func WithKeepAliveInterval (keepAliveInterval time.Duration ) SSEOption {
211- return func (s * SSEServer ) {
212- s .keepAlive = true
213- s .keepAliveInterval = keepAliveInterval
214- }
215- }
216-
217- func WithKeepAlive (keepAlive bool ) SSEOption {
218- return func (s * SSEServer ) {
219- s .keepAlive = keepAlive
220- }
179+ })
221180}
222181
223182// WithSSEContextFunc sets a function that will be called to customise the context
224183// to the server using the incoming request.
184+ //
185+ // Deprecated: Use WithContextFunc instead. This will be removed in a future version.
186+ //go:deprecated
225187func WithSSEContextFunc (fn SSEContextFunc ) SSEOption {
226- return func (s * SSEServer ) {
227- s . contextFunc = fn
228- }
188+ return sseOption ( func (s * SSEServer ) {
189+ WithHTTPContextFunc ( HTTPContextFunc ( fn )). applyToSSE ( s )
190+ })
229191}
230192
231193// NewSSEServer creates a new SSE server instance with the given MCP server and options.
@@ -241,16 +203,15 @@ func NewSSEServer(server *MCPServer, opts ...SSEOption) *SSEServer {
241203
242204 // Apply all options
243205 for _ , opt := range opts {
244- opt (s )
206+ opt . applyToSSE (s )
245207 }
246208
247209 return s
248210}
249211
250- // NewTestServer creates a test server for testing purposes
212+ // NewTestServer creates a test server for testing purposes.
251213func NewTestServer (server * MCPServer , opts ... SSEOption ) * httptest.Server {
252214 sseServer := NewSSEServer (server , opts ... )
253-
254215 testServer := httptest .NewServer (sseServer )
255216 sseServer .baseURL = testServer .URL
256217 return testServer
0 commit comments