mirror of
https://github.com/mudler/LocalAI.git
synced 2026-02-04 11:42:57 -05:00
fix: resolve duplicate MCP route registration causing 50% failure rate
Fixes #7772 The issue was caused by duplicate registration of the MCP endpoint /mcp/v1/chat/completions in both openai.go and localai.go, leading to a race condition where requests would randomly hit different handlers with incompatible behaviors. Changes: - Removed duplicate MCP route registration from openai.go - Kept the localai.MCPStreamEndpoint as the canonical handler - Added all three MCP route patterns for backward compatibility: * /v1/mcp/chat/completions * /mcp/v1/chat/completions * /mcp/chat/completions - Added comments to clarify route ownership and prevent future conflicts - Fixed formatting in ui_api.go The localai.MCPStreamEndpoint handler is more feature-complete as it supports both streaming and non-streaming modes, while the removed openai.MCPCompletionEndpoint only supported synchronous requests. This eliminates the ~50% failure rate where the cogito library would receive "Invalid http method" errors when internal HTTP requests were routed to the wrong handler. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: majiayu000 <1835304752@qq.com>
This commit is contained in:
committed by
Ettore Di Giacinto
parent
5f6c941399
commit
d89c7b731a
@@ -137,7 +137,8 @@ func RegisterLocalAIRoutes(router *echo.Echo,
|
||||
requestExtractor.BuildFilteredFirstAvailableDefaultModel(config.BuildUsecaseFilterFn(config.FLAG_TOKENIZE)),
|
||||
requestExtractor.SetModelAndConfig(func() schema.LocalAIRequest { return new(schema.TokenizeRequest) }))
|
||||
|
||||
// MCP Stream endpoint
|
||||
// MCP endpoint - supports both streaming and non-streaming modes
|
||||
// Note: These are the canonical MCP routes (not duplicated in openai.go)
|
||||
if evaluator != nil {
|
||||
mcpStreamHandler := localai.MCPStreamEndpoint(cl, ml, evaluator, appConfig)
|
||||
mcpStreamMiddleware := []echo.MiddlewareFunc{
|
||||
@@ -154,6 +155,7 @@ func RegisterLocalAIRoutes(router *echo.Echo,
|
||||
}
|
||||
router.POST("/v1/mcp/chat/completions", mcpStreamHandler, mcpStreamMiddleware...)
|
||||
router.POST("/mcp/v1/chat/completions", mcpStreamHandler, mcpStreamMiddleware...)
|
||||
router.POST("/mcp/chat/completions", mcpStreamHandler, mcpStreamMiddleware...)
|
||||
}
|
||||
|
||||
// Agent job routes
|
||||
|
||||
@@ -79,23 +79,8 @@ func RegisterOpenAIRoutes(app *echo.Echo,
|
||||
app.POST("/completions", completionHandler, completionMiddleware...)
|
||||
app.POST("/v1/engines/:model/completions", completionHandler, completionMiddleware...)
|
||||
|
||||
// MCPcompletion
|
||||
mcpCompletionHandler := openai.MCPCompletionEndpoint(application.ModelConfigLoader(), application.ModelLoader(), application.TemplatesEvaluator(), application.ApplicationConfig())
|
||||
mcpCompletionMiddleware := []echo.MiddlewareFunc{
|
||||
traceMiddleware,
|
||||
re.BuildFilteredFirstAvailableDefaultModel(config.BuildUsecaseFilterFn(config.FLAG_CHAT)),
|
||||
re.SetModelAndConfig(func() schema.LocalAIRequest { return new(schema.OpenAIRequest) }),
|
||||
func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
if err := re.SetOpenAIRequest(c); err != nil {
|
||||
return err
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
},
|
||||
}
|
||||
app.POST("/mcp/v1/chat/completions", mcpCompletionHandler, mcpCompletionMiddleware...)
|
||||
app.POST("/mcp/chat/completions", mcpCompletionHandler, mcpCompletionMiddleware...)
|
||||
// Note: MCP endpoints are registered in localai.go to avoid route conflicts
|
||||
// The localai.MCPStreamEndpoint handler supports both streaming and non-streaming modes
|
||||
|
||||
// embeddings
|
||||
embeddingHandler := openai.EmbeddingsEndpoint(application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig())
|
||||
|
||||
@@ -954,7 +954,7 @@ func RegisterUIAPIRoutes(app *echo.Echo, cl *config.ModelConfigLoader, ml *model
|
||||
if !appConfig.EnableTracing {
|
||||
return c.JSON(503, map[string]any{
|
||||
"error": "Tracing disabled",
|
||||
})
|
||||
})
|
||||
}
|
||||
traces := middleware.GetTraces()
|
||||
return c.JSON(200, map[string]interface{}{
|
||||
|
||||
Reference in New Issue
Block a user