Part of duplicate code analysis: #5070
Summary
Both internal/server/transport.go (unified mode) and internal/server/routed.go (routed mode) implement the same three-step handler construction sequence:
sdk.NewStreamableHTTPHandler(...) with StreamableHTTPOptions{Stateless: false, Logger: ..., SessionTimeout: ...}
WrapWithSessionAutoInit(handler)
wrapWithMiddleware(handler, tag, unifiedServer, apiKey, hmacSecret)
The only differences are the session-factory callback, the logger variable, the log tag, and the SessionTimeout source.
Duplication Details
Pattern: StreamableHTTP handler + middleware chain
- Severity: Medium
- Occurrences: 2
- Locations:
internal/server/transport.go (lines 28–54) — unified mode
internal/server/routed.go (lines 163–186) — routed mode (once per backend, inside a loop)
- Code Sample:
// Both files follow this identical structure:
handler := sdk.NewStreamableHTTPHandler(serverFactory, &sdk.StreamableHTTPOptions{
Stateless: false,
Logger: logger.NewSlogLoggerWithHandler(logXxx),
SessionTimeout: <session timeout>,
})
autoInitHandler := WrapWithSessionAutoInit(handler)
finalHandler := wrapWithMiddleware(autoInitHandler, logTag, unifiedServer, apiKey, hmacSecret)
Impact Analysis
- Maintainability: Medium — any change to the middleware chain (e.g. adding a new wrapper) must be applied in both files.
- Bug Risk: Medium — it is easy to apply a fix to one mode but forget the other.
- Code Bloat: Low — ~12 duplicated lines per occurrence.
Refactoring Recommendations
- Extract a
buildMCPHandler helper in internal/server/http_helpers.go (or a new server/handler_factory.go):
// buildMCPHandler constructs the standard streamable HTTP handler stack.
func buildMCPHandler(
serverFactory func(*http.Request) *sdk.Server,
log *logger.Logger,
sessionTimeout time.Duration,
logTag string,
unifiedServer *UnifiedServer,
apiKey, hmacSecret string,
) http.Handler {
h := sdk.NewStreamableHTTPHandler(serverFactory, &sdk.StreamableHTTPOptions{
Stateless: false,
Logger: logger.NewSlogLoggerWithHandler(log),
SessionTimeout: sessionTimeout,
})
return wrapWithMiddleware(WrapWithSessionAutoInit(h), logTag, unifiedServer, apiKey, hmacSecret)
}
- Estimated effort: ~1 hour
- Benefits: middleware chain changes need one edit; both modes stay in sync automatically.
Implementation Checklist
Parent Issue
See parent analysis report: #5070
Related to #5070
Generated by Duplicate Code Detector · ● 960.3K · ◷
Part of duplicate code analysis: #5070
Summary
Both
internal/server/transport.go(unified mode) andinternal/server/routed.go(routed mode) implement the same three-step handler construction sequence:sdk.NewStreamableHTTPHandler(...)withStreamableHTTPOptions{Stateless: false, Logger: ..., SessionTimeout: ...}WrapWithSessionAutoInit(handler)wrapWithMiddleware(handler, tag, unifiedServer, apiKey, hmacSecret)The only differences are the session-factory callback, the logger variable, the log tag, and the
SessionTimeoutsource.Duplication Details
Pattern: StreamableHTTP handler + middleware chain
internal/server/transport.go(lines 28–54) — unified modeinternal/server/routed.go(lines 163–186) — routed mode (once per backend, inside a loop)Impact Analysis
Refactoring Recommendations
buildMCPHandlerhelper ininternal/server/http_helpers.go(or a newserver/handler_factory.go):Implementation Checklist
buildMCPHandlerhelper ininternal/server/transport.goto use the helperrouted.goto use the helpermake test-allto verify no regressionsParent Issue
See parent analysis report: #5070
Related to #5070