From 5146832e75b1c58fdf13e6fa970cedf991ec91a8 Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Tue, 28 Oct 2025 23:28:19 +0800 Subject: [PATCH 1/4] Change xtramcp endpoint --- internal/services/toolkit/client/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/services/toolkit/client/client.go b/internal/services/toolkit/client/client.go index 2e8b091d..b1c4fc1b 100644 --- a/internal/services/toolkit/client/client.go +++ b/internal/services/toolkit/client/client.go @@ -52,9 +52,9 @@ func NewAIClient( // toolRegistry.Register("paper_score", toolPaperScore.Description, toolPaperScore.Call) // toolRegistry.Register("paper_score_comment", toolPaperScoreComment.Description, toolPaperScoreComment.Call) - // Load tools dynamically from backend (TODO: Make URL configurable / Xtramcp url) - xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "http://localhost:8080/mcp") - + // Load tools dynamically from backen + xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "https://paperdebugger-xtra-mcp-server/mcp") + // initialize MCP session first and log session ID sessionID, err := xtraMCPLoader.InitializeMCP() if err != nil { @@ -62,7 +62,7 @@ func NewAIClient( // TODO: Fallback to static tools or exit? } else { logger.Info("[AI Client] XtraMCP session initialized", "sessionID", sessionID) - + // dynamically load all tools from XtraMCP backend err = xtraMCPLoader.LoadToolsFromBackend(toolRegistry) if err != nil { From 8bb90036ca420cef6a053b50a9691be1e0033f6a Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Wed, 29 Oct 2025 00:09:21 +0800 Subject: [PATCH 2/4] nit: Abstract parsing sse as helper --- internal/services/toolkit/client/client.go | 2 -- .../services/toolkit/tools/xtramcp/helper.go | 24 +++++++++++++++++++ .../services/toolkit/tools/xtramcp/loader.go | 20 ++++------------ .../services/toolkit/tools/xtramcp/tool.go | 19 +++++---------- 4 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 internal/services/toolkit/tools/xtramcp/helper.go diff --git a/internal/services/toolkit/client/client.go b/internal/services/toolkit/client/client.go index b1c4fc1b..f8c927c4 100644 --- a/internal/services/toolkit/client/client.go +++ b/internal/services/toolkit/client/client.go @@ -49,8 +49,6 @@ func NewAIClient( // toolRegistry.Register("always_exception", tools.AlwaysExceptionToolDescription, tools.AlwaysExceptionTool) // toolRegistry.Register("greeting", tools.GreetingToolDescription, tools.GreetingTool) - // toolRegistry.Register("paper_score", toolPaperScore.Description, toolPaperScore.Call) - // toolRegistry.Register("paper_score_comment", toolPaperScoreComment.Description, toolPaperScoreComment.Call) // Load tools dynamically from backen xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "https://paperdebugger-xtra-mcp-server/mcp") diff --git a/internal/services/toolkit/tools/xtramcp/helper.go b/internal/services/toolkit/tools/xtramcp/helper.go new file mode 100644 index 00000000..c7ba6137 --- /dev/null +++ b/internal/services/toolkit/tools/xtramcp/helper.go @@ -0,0 +1,24 @@ +package xtramcp + +import ( + "fmt" + "strings" +) + +// extracts JSON data from SSE format response +// SSE format: +// +// event: message +// data: { ... } +func parseSSEResponse(body []byte) (string, error) { + lines := strings.Split(string(body), "\n") + + for _, line := range lines { + if strings.HasPrefix(line, "data: ") { + jsonData := strings.TrimPrefix(line, "data: ") + return jsonData, nil + } + } + + return "", fmt.Errorf("no data line found in SSE response") +} diff --git a/internal/services/toolkit/tools/xtramcp/loader.go b/internal/services/toolkit/tools/xtramcp/loader.go index 974ff71b..a47b95c4 100644 --- a/internal/services/toolkit/tools/xtramcp/loader.go +++ b/internal/services/toolkit/tools/xtramcp/loader.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "net/http" - "strings" "paperdebugger/internal/libs/db" "paperdebugger/internal/services" "paperdebugger/internal/services/toolkit/registry" @@ -55,10 +54,10 @@ func (loader *XtraMCPLoader) LoadToolsFromBackend(toolRegistry *registry.ToolReg // Register each tool dynamically, passing the session ID for _, toolSchema := range toolSchemas { dynamicTool := NewDynamicTool(loader.db, loader.projectService, toolSchema, loader.baseURL, loader.sessionID) - + // Register the tool with the registry toolRegistry.Register(toolSchema.Name, dynamicTool.Description, dynamicTool.Call) - + fmt.Printf("Registered dynamic tool: %s\n", toolSchema.Name) } @@ -196,18 +195,9 @@ func (loader *XtraMCPLoader) fetchAvailableTools() ([]ToolSchema, error) { return nil, fmt.Errorf("failed to read response body: %w", err) } - // Parse SSE format - extract JSON from "data: " lines - lines := strings.Split(string(bodyBytes), "\n") - var extractedJSON string - for _, line := range lines { - if strings.HasPrefix(line, "data: ") { - extractedJSON = strings.TrimPrefix(line, "data: ") - break - } - } - - if extractedJSON == "" { - return nil, fmt.Errorf("no data line found in SSE response") + extractedJSON, err := parseSSEResponse(bodyBytes) + if err != nil { + return nil, fmt.Errorf("failed to parse SSE response: %w", err) } // Parse the extracted JSON diff --git a/internal/services/toolkit/tools/xtramcp/tool.go b/internal/services/toolkit/tools/xtramcp/tool.go index 12156837..f9a4e470 100644 --- a/internal/services/toolkit/tools/xtramcp/tool.go +++ b/internal/services/toolkit/tools/xtramcp/tool.go @@ -10,13 +10,11 @@ import ( "paperdebugger/internal/libs/db" "paperdebugger/internal/services" toolCallRecordDB "paperdebugger/internal/services/toolkit/db" - "strings" "time" "github.com/openai/openai-go/v2" "github.com/openai/openai-go/v2/packages/param" "github.com/openai/openai-go/v2/responses" - "github.com/samber/lo" ) // ToolSchema represents the schema from your backend @@ -155,16 +153,11 @@ func (t *DynamicTool) executeTool(args map[string]interface{}) (string, error) { if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } - - // Parse response (assuming stream format) - lines := strings.Split(string(body), "\n") - lines = lo.Filter(lines, func(line string, _ int) bool { - return strings.HasPrefix(line, "data:") - }) - if len(lines) == 0 { - return "", fmt.Errorf("no data line found") + + extractedJSON, err := parseSSEResponse(body) + if err != nil { + return "", fmt.Errorf("failed to parse SSE response: %w", err) } - line := lines[0] - line = strings.TrimPrefix(line, "data: ") - return line, nil + + return extractedJSON, nil } From 2edf3bc85db403293220d517c94ebcef65c19513 Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Wed, 29 Oct 2025 00:20:11 +0800 Subject: [PATCH 3/4] Fix hostname --- internal/services/toolkit/client/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/services/toolkit/client/client.go b/internal/services/toolkit/client/client.go index f8c927c4..578fa6d5 100644 --- a/internal/services/toolkit/client/client.go +++ b/internal/services/toolkit/client/client.go @@ -50,8 +50,8 @@ func NewAIClient( // toolRegistry.Register("always_exception", tools.AlwaysExceptionToolDescription, tools.AlwaysExceptionTool) // toolRegistry.Register("greeting", tools.GreetingToolDescription, tools.GreetingTool) - // Load tools dynamically from backen - xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "https://paperdebugger-xtra-mcp-server/mcp") + // Load tools dynamically from backend + xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "https://paperdebugger-xtra-mcp-server.com/mcp") // initialize MCP session first and log session ID sessionID, err := xtraMCPLoader.InitializeMCP() From 732d49f820fc7d5f20bb4e76de253d27e3ec85f9 Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Thu, 30 Oct 2025 23:20:30 +0800 Subject: [PATCH 4/4] Change protocol from https to http --- internal/services/toolkit/client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/toolkit/client/client.go b/internal/services/toolkit/client/client.go index 578fa6d5..34ca1975 100644 --- a/internal/services/toolkit/client/client.go +++ b/internal/services/toolkit/client/client.go @@ -51,7 +51,7 @@ func NewAIClient( // toolRegistry.Register("greeting", tools.GreetingToolDescription, tools.GreetingTool) // Load tools dynamically from backend - xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "https://paperdebugger-xtra-mcp-server.com/mcp") + xtraMCPLoader := xtramcp.NewXtraMCPLoader(db, projectService, "http://paperdebugger-xtra-mcp-server.com/mcp") // initialize MCP session first and log session ID sessionID, err := xtraMCPLoader.InitializeMCP()