From 4427c399c626aad0f32b723ab9f4c41522448837 Mon Sep 17 00:00:00 2001 From: yuchou87 Date: Sun, 1 Mar 2026 08:53:13 +0800 Subject: [PATCH] chore: fix lint issues in mcp and agent packages - Fix gci import ordering in manager.go, manager_test.go - Fix gofmt formatting in loop.go, manager.go, mcp_tool.go, mcp_tool_test.go - Fix gofumpt formatting in manager_test.go - Fix golines line length issues in manager.go, mcp_tool_test.go - Fix wastedassign: replace redundant zero-value init with var declaration in loop.go --- pkg/agent/loop.go | 124 +++++++++++++++++++++++++++---------- pkg/mcp/manager.go | 64 ++++++++++++------- pkg/mcp/manager_test.go | 10 ++- pkg/tools/mcp_tool.go | 32 +++++----- pkg/tools/mcp_tool_test.go | 50 ++++++++------- 5 files changed, 186 insertions(+), 94 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 12ca35148..338ce9c58 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -58,7 +58,11 @@ type processOptions struct { const defaultResponse = "I've completed processing but have no response to give. Increase `max_tool_iterations` in config.json." -func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers.LLMProvider) *AgentLoop { +func NewAgentLoop( + cfg *config.Config, + msgBus *bus.MessageBus, + provider providers.LLMProvider, +) *AgentLoop { registry := NewAgentRegistry(cfg, provider) // Register shared tools to all agents @@ -166,7 +170,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { if al.cfg.Tools.MCP.Enabled { mcpManager := mcp.NewManager() defaultAgent := al.registry.GetDefaultAgent() - workspacePath := "" + var workspacePath string if defaultAgent != nil && defaultAgent.Workspace != "" { workspacePath = defaultAgent.Workspace } else { @@ -175,7 +179,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { if err := mcpManager.LoadFromMCPConfig(ctx, al.cfg.Tools.MCP, workspacePath); err != nil { logger.WarnCF("agent", "Failed to load MCP servers, MCP tools will not be available", - map[string]interface{}{ + map[string]any{ "error": err.Error(), }) } else { @@ -183,7 +187,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { defer func() { if err := mcpManager.Close(); err != nil { logger.ErrorCF("agent", "Failed to close MCP manager", - map[string]interface{}{ + map[string]any{ "error": err.Error(), }) } @@ -208,7 +212,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { agent.Tools.Register(mcpTool) totalRegistrations++ logger.DebugCF("agent", "Registered MCP tool", - map[string]interface{}{ + map[string]any{ "agent_id": agentID, "server": serverName, "tool": tool.Name, @@ -218,7 +222,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { } } logger.InfoCF("agent", "MCP tools registered successfully", - map[string]interface{}{ + map[string]any{ "server_count": len(servers), "unique_tools": uniqueTools, "total_registrations": totalRegistrations, @@ -367,7 +371,10 @@ func (al *AgentLoop) RecordLastChatID(chatID string) error { return al.state.SetLastChatID(chatID) } -func (al *AgentLoop) ProcessDirect(ctx context.Context, content, sessionKey string) (string, error) { +func (al *AgentLoop) ProcessDirect( + ctx context.Context, + content, sessionKey string, +) (string, error) { return al.ProcessDirectWithChannel(ctx, content, sessionKey, "cli", "direct") } @@ -388,7 +395,10 @@ func (al *AgentLoop) ProcessDirectWithChannel( // ProcessHeartbeat processes a heartbeat request without session history. // Each heartbeat is independent and doesn't accumulate context. -func (al *AgentLoop) ProcessHeartbeat(ctx context.Context, content, channel, chatID string) (string, error) { +func (al *AgentLoop) ProcessHeartbeat( + ctx context.Context, + content, channel, chatID string, +) (string, error) { agent := al.registry.GetDefaultAgent() if agent == nil { return "", fmt.Errorf("no default agent for heartbeat") @@ -413,13 +423,16 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage) } else { logContent = utils.Truncate(msg.Content, 80) } - logger.InfoCF("agent", fmt.Sprintf("Processing message from %s:%s: %s", msg.Channel, msg.SenderID, logContent), + logger.InfoCF( + "agent", + fmt.Sprintf("Processing message from %s:%s: %s", msg.Channel, msg.SenderID, logContent), map[string]any{ "channel": msg.Channel, "chat_id": msg.ChatID, "sender_id": msg.SenderID, "session_key": msg.SessionKey, - }) + }, + ) // Route system messages to processSystemMessage if msg.Channel == "system" { @@ -480,9 +493,15 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage) }) } -func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMessage) (string, error) { +func (al *AgentLoop) processSystemMessage( + ctx context.Context, + msg bus.InboundMessage, +) (string, error) { if msg.Channel != "system" { - return "", fmt.Errorf("processSystemMessage called with non-system message channel: %s", msg.Channel) + return "", fmt.Errorf( + "processSystemMessage called with non-system message channel: %s", + msg.Channel, + ) } logger.InfoCF("agent", "Processing system message", @@ -540,14 +559,22 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe } // runAgentLoop is the core message processing logic. -func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opts processOptions) (string, error) { +func (al *AgentLoop) runAgentLoop( + ctx context.Context, + agent *AgentInstance, + opts processOptions, +) (string, error) { // 0. Record last channel for heartbeat notifications (skip internal channels) if opts.Channel != "" && opts.ChatID != "" { // Don't record internal channels (cli, system, subagent) if !constants.IsInternalChannel(opts.Channel) { channelKey := fmt.Sprintf("%s:%s", opts.Channel, opts.ChatID) if err := al.RecordLastChannel(channelKey); err != nil { - logger.WarnCF("agent", "Failed to record last channel", map[string]any{"error": err.Error()}) + logger.WarnCF( + "agent", + "Failed to record last channel", + map[string]any{"error": err.Error()}, + ) } } } @@ -629,7 +656,10 @@ func (al *AgentLoop) targetReasoningChannelID(channelName string) (chatID string return "" } -func (al *AgentLoop) handleReasoning(ctx context.Context, reasoningContent, channelName, channelID string) { +func (al *AgentLoop) handleReasoning( + ctx context.Context, + reasoningContent, channelName, channelID string, +) { if reasoningContent == "" || channelName == "" || channelID == "" { return } @@ -697,22 +727,33 @@ func (al *AgentLoop) runLLMIteration( callLLM := func() (*providers.LLMResponse, error) { if len(agent.Candidates) > 1 && al.fallback != nil { - fbResult, fbErr := al.fallback.Execute(ctx, agent.Candidates, + fbResult, fbErr := al.fallback.Execute( + ctx, + agent.Candidates, func(ctx context.Context, provider, model string) (*providers.LLMResponse, error) { - return agent.Provider.Chat(ctx, messages, providerToolDefs, model, map[string]any{ - "max_tokens": agent.MaxTokens, - "temperature": agent.Temperature, - "prompt_cache_key": agent.ID, - }) + return agent.Provider.Chat( + ctx, + messages, + providerToolDefs, + model, + map[string]any{ + "max_tokens": agent.MaxTokens, + "temperature": agent.Temperature, + "prompt_cache_key": agent.ID, + }, + ) }, ) if fbErr != nil { return nil, fbErr } if fbResult.Provider != "" && len(fbResult.Attempts) > 0 { - logger.InfoCF("agent", fmt.Sprintf("Fallback: succeeded with %s/%s after %d attempts", - fbResult.Provider, fbResult.Model, len(fbResult.Attempts)+1), - map[string]any{"agent_id": agent.ID, "iteration": iteration}) + logger.InfoCF( + "agent", + fmt.Sprintf("Fallback: succeeded with %s/%s after %d attempts", + fbResult.Provider, fbResult.Model, len(fbResult.Attempts)+1), + map[string]any{"agent_id": agent.ID, "iteration": iteration}, + ) } return fbResult.Response, nil } @@ -738,10 +779,14 @@ func (al *AgentLoop) runLLMIteration( strings.Contains(errMsg, "length") if isContextError && retry < maxRetries { - logger.WarnCF("agent", "Context window error detected, attempting compression", map[string]any{ - "error": err.Error(), - "retry": retry, - }) + logger.WarnCF( + "agent", + "Context window error detected, attempting compression", + map[string]any{ + "error": err.Error(), + "retry": retry, + }, + ) if retry == 0 && !constants.IsInternalChannel(opts.Channel) { al.bus.PublishOutbound(ctx, bus.OutboundMessage{ @@ -773,7 +818,12 @@ func (al *AgentLoop) runLLMIteration( return "", iteration, fmt.Errorf("LLM call failed after retries: %w", err) } - go al.handleReasoning(ctx, response.Reasoning, opts.Channel, al.targetReasoningChannelID(opts.Channel)) + go al.handleReasoning( + ctx, + response.Reasoning, + opts.Channel, + al.targetReasoningChannelID(opts.Channel), + ) logger.DebugCF("agent", "LLM response", map[string]any{ @@ -1075,7 +1125,11 @@ func formatMessagesForLog(messages []providers.Message) string { for _, tc := range msg.ToolCalls { fmt.Fprintf(&sb, " - ID: %s, Type: %s, Name: %s\n", tc.ID, tc.Type, tc.Name) if tc.Function != nil { - fmt.Fprintf(&sb, " Arguments: %s\n", utils.Truncate(tc.Function.Arguments, 200)) + fmt.Fprintf( + &sb, + " Arguments: %s\n", + utils.Truncate(tc.Function.Arguments, 200), + ) } } } @@ -1104,7 +1158,11 @@ func formatToolsForLog(toolDefs []providers.ToolDefinition) string { fmt.Fprintf(&sb, " [%d] Type: %s, Name: %s\n", i, tool.Type, tool.Function.Name) fmt.Fprintf(&sb, " Description: %s\n", tool.Function.Description) if len(tool.Function.Parameters) > 0 { - fmt.Fprintf(&sb, " Parameters: %s\n", utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200)) + fmt.Fprintf( + &sb, + " Parameters: %s\n", + utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200), + ) } } sb.WriteString("]") @@ -1201,7 +1259,9 @@ func (al *AgentLoop) summarizeBatch( existingSummary string, ) (string, error) { var sb strings.Builder - sb.WriteString("Provide a concise summary of this conversation segment, preserving core context and key points.\n") + sb.WriteString( + "Provide a concise summary of this conversation segment, preserving core context and key points.\n", + ) if existingSummary != "" { sb.WriteString("Existing context: ") sb.WriteString(existingSummary) diff --git a/pkg/mcp/manager.go b/pkg/mcp/manager.go index 90f31f0c1..e79c9d3f8 100644 --- a/pkg/mcp/manager.go +++ b/pkg/mcp/manager.go @@ -13,6 +13,7 @@ import ( "sync" "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/logger" ) @@ -125,7 +126,11 @@ func (m *Manager) LoadFromConfig(ctx context.Context, cfg *config.Config) error // LoadFromMCPConfig loads MCP servers from MCP configuration and workspace path. // This is the minimal dependency version that doesn't require the full Config object. -func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig, workspacePath string) error { +func (m *Manager) LoadFromMCPConfig( + ctx context.Context, + mcpCfg config.MCPConfig, + workspacePath string, +) error { if !mcpCfg.Enabled { logger.InfoCF("mcp", "MCP integration is disabled", nil) return nil @@ -137,7 +142,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig } logger.InfoCF("mcp", "Initializing MCP servers", - map[string]interface{}{ + map[string]any{ "count": len(mcpCfg.Servers), }) @@ -148,7 +153,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig for name, serverCfg := range mcpCfg.Servers { if !serverCfg.Enabled { logger.DebugCF("mcp", "Skipping disabled server", - map[string]interface{}{ + map[string]any{ "server": name, }) continue @@ -162,9 +167,13 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig // Resolve relative envFile paths relative to workspace if serverCfg.EnvFile != "" && !filepath.IsAbs(serverCfg.EnvFile) { if workspace == "" { - err := fmt.Errorf("workspace path is empty while resolving relative envFile %q for server %s", serverCfg.EnvFile, name) + err := fmt.Errorf( + "workspace path is empty while resolving relative envFile %q for server %s", + serverCfg.EnvFile, + name, + ) logger.ErrorCF("mcp", "Invalid MCP server configuration", - map[string]interface{}{ + map[string]any{ "server": name, "env_file": serverCfg.EnvFile, "error": err.Error(), @@ -177,7 +186,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig if err := m.ConnectServer(ctx, name, serverCfg); err != nil { logger.ErrorCF("mcp", "Failed to connect to MCP server", - map[string]interface{}{ + map[string]any{ "server": name, "error": err.Error(), }) @@ -200,7 +209,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig // If all enabled servers failed to connect, return aggregated error if enabledCount > 0 && connectedCount == 0 { logger.ErrorCF("mcp", "All MCP servers failed to connect", - map[string]interface{}{ + map[string]any{ "failed": len(allErrors), "total": enabledCount, }) @@ -209,7 +218,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig if len(allErrors) > 0 { logger.WarnCF("mcp", "Some MCP servers failed to connect", - map[string]interface{}{ + map[string]any{ "failed": len(allErrors), "connected": connectedCount, "total": enabledCount, @@ -218,7 +227,7 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig } logger.InfoCF("mcp", "MCP server initialization complete", - map[string]interface{}{ + map[string]any{ "connected": connectedCount, "total": enabledCount, }) @@ -227,9 +236,13 @@ func (m *Manager) LoadFromMCPConfig(ctx context.Context, mcpCfg config.MCPConfig } // ConnectServer connects to a single MCP server -func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCPServerConfig) error { +func (m *Manager) ConnectServer( + ctx context.Context, + name string, + cfg config.MCPServerConfig, +) error { logger.InfoCF("mcp", "Connecting to MCP server", - map[string]interface{}{ + map[string]any{ "server": name, "command": cfg.Command, "args": cfg.Args, @@ -263,7 +276,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP return fmt.Errorf("URL is required for SSE/HTTP transport") } logger.DebugCF("mcp", "Using SSE/HTTP transport", - map[string]interface{}{ + map[string]any{ "server": name, "url": cfg.URL, }) @@ -282,7 +295,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP }, } logger.DebugCF("mcp", "Added custom HTTP headers", - map[string]interface{}{ + map[string]any{ "server": name, "header_count": len(cfg.Headers), }) @@ -294,7 +307,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP return fmt.Errorf("command is required for stdio transport") } logger.DebugCF("mcp", "Using stdio transport", - map[string]interface{}{ + map[string]any{ "server": name, "command": cfg.Command, }) @@ -322,7 +335,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP envMap[k] = v } logger.DebugCF("mcp", "Loaded environment variables from file", - map[string]interface{}{ + map[string]any{ "server": name, "envFile": cfg.EnvFile, "var_count": len(envVars), @@ -343,7 +356,10 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP transport = &mcp.CommandTransport{Command: cmd} default: - return fmt.Errorf("unsupported transport type: %s (supported: stdio, sse, http)", transportType) + return fmt.Errorf( + "unsupported transport type: %s (supported: stdio, sse, http)", + transportType, + ) } // Connect to server @@ -355,7 +371,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP // Get server info initResult := session.InitializeResult() logger.InfoCF("mcp", "Connected to MCP server", - map[string]interface{}{ + map[string]any{ "server": name, "serverName": initResult.ServerInfo.Name, "serverVersion": initResult.ServerInfo.Version, @@ -368,7 +384,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP for tool, err := range session.Tools(ctx, nil) { if err != nil { logger.WarnCF("mcp", "Error listing tool", - map[string]interface{}{ + map[string]any{ "server": name, "error": err.Error(), }) @@ -378,7 +394,7 @@ func (m *Manager) ConnectServer(ctx context.Context, name string, cfg config.MCP } logger.InfoCF("mcp", "Listed tools from MCP server", - map[string]interface{}{ + map[string]any{ "server": name, "toolCount": len(tools), }) @@ -419,7 +435,11 @@ func (m *Manager) GetServer(name string) (*ServerConnection, bool) { } // CallTool calls a tool on a specific server -func (m *Manager) CallTool(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { +func (m *Manager) CallTool( + ctx context.Context, + serverName, toolName string, + arguments map[string]any, +) (*mcp.CallToolResult, error) { m.mu.RLock() if m.closed { m.mu.RUnlock() @@ -466,7 +486,7 @@ func (m *Manager) Close() error { defer m.mu.Unlock() logger.InfoCF("mcp", "Closing all MCP server connections", - map[string]interface{}{ + map[string]any{ "count": len(m.servers), }) @@ -474,7 +494,7 @@ func (m *Manager) Close() error { for name, conn := range m.servers { if err := conn.Session.Close(); err != nil { logger.ErrorCF("mcp", "Failed to close server connection", - map[string]interface{}{ + map[string]any{ "server": name, "error": err.Error(), }) diff --git a/pkg/mcp/manager_test.go b/pkg/mcp/manager_test.go index f9b8c07dd..6dd71a3c2 100644 --- a/pkg/mcp/manager_test.go +++ b/pkg/mcp/manager_test.go @@ -8,6 +8,7 @@ import ( "testing" sdkmcp "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/sipeed/picoclaw/pkg/config" ) @@ -95,7 +96,7 @@ PORT =8080`, tmpDir := t.TempDir() envFile := filepath.Join(tmpDir, ".env") - if err := os.WriteFile(envFile, []byte(tt.content), 0644); err != nil { + if err := os.WriteFile(envFile, []byte(tt.content), 0o644); err != nil { t.Fatalf("Failed to create test file: %v", err) } @@ -144,7 +145,7 @@ func TestEnvFilePriority(t *testing.T) { DATABASE_URL=from_file SHARED_VAR=from_file` - if err := os.WriteFile(envFile, []byte(envContent), 0644); err != nil { + if err := os.WriteFile(envFile, []byte(envContent), 0o644); err != nil { t.Fatalf("Failed to create .env file: %v", err) } @@ -176,7 +177,10 @@ SHARED_VAR=from_file` // Verify priority: config.Env should override envFile if merged["SHARED_VAR"] != "from_config" { - t.Errorf("Expected SHARED_VAR=from_config (config should override file), got %s", merged["SHARED_VAR"]) + t.Errorf( + "Expected SHARED_VAR=from_config (config should override file), got %s", + merged["SHARED_VAR"], + ) } if merged["API_KEY"] != "from_file" { t.Errorf("Expected API_KEY=from_file, got %s", merged["API_KEY"]) diff --git a/pkg/tools/mcp_tool.go b/pkg/tools/mcp_tool.go index 6bd3d75e3..69615b4bc 100644 --- a/pkg/tools/mcp_tool.go +++ b/pkg/tools/mcp_tool.go @@ -12,7 +12,11 @@ import ( // MCPManager defines the interface for MCP manager operations // This allows for easier testing with mock implementations type MCPManager interface { - CallTool(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) + CallTool( + ctx context.Context, + serverName, toolName string, + arguments map[string]any, + ) (*mcp.CallToolResult, error) } // MCPTool wraps an MCP tool to implement the Tool interface @@ -48,21 +52,21 @@ func (t *MCPTool) Description() string { } // Parameters returns the tool parameters schema -func (t *MCPTool) Parameters() map[string]interface{} { +func (t *MCPTool) Parameters() map[string]any { // The InputSchema is already a JSON Schema object schema := t.tool.InputSchema // Handle nil schema if schema == nil { - return map[string]interface{}{ + return map[string]any{ "type": "object", - "properties": map[string]interface{}{}, + "properties": map[string]any{}, "required": []string{}, } } // Try direct conversion first (fast path) - if schemaMap, ok := schema.(map[string]interface{}); ok { + if schemaMap, ok := schema.(map[string]any); ok { return schemaMap } @@ -75,14 +79,14 @@ func (t *MCPTool) Parameters() map[string]interface{} { } if jsonData != nil { - var result map[string]interface{} + var result map[string]any if err := json.Unmarshal(jsonData, &result); err == nil { return result } // Fallback on error - return map[string]interface{}{ + return map[string]any{ "type": "object", - "properties": map[string]interface{}{}, + "properties": map[string]any{}, "required": []string{}, } } @@ -92,19 +96,19 @@ func (t *MCPTool) Parameters() map[string]interface{} { jsonData, err = json.Marshal(schema) if err != nil { // Fallback to empty schema if marshaling fails - return map[string]interface{}{ + return map[string]any{ "type": "object", - "properties": map[string]interface{}{}, + "properties": map[string]any{}, "required": []string{}, } } - var result map[string]interface{} + var result map[string]any if err := json.Unmarshal(jsonData, &result); err != nil { // Fallback to empty schema if unmarshaling fails - return map[string]interface{}{ + return map[string]any{ "type": "object", - "properties": map[string]interface{}{}, + "properties": map[string]any{}, "required": []string{}, } } @@ -113,7 +117,7 @@ func (t *MCPTool) Parameters() map[string]interface{} { } // Execute executes the MCP tool -func (t *MCPTool) Execute(ctx context.Context, args map[string]interface{}) *ToolResult { +func (t *MCPTool) Execute(ctx context.Context, args map[string]any) *ToolResult { result, err := t.manager.CallTool(ctx, t.serverName, t.tool.Name, args) if err != nil { return ErrorResult(fmt.Sprintf("MCP tool execution failed: %v", err)).WithError(err) diff --git a/pkg/tools/mcp_tool_test.go b/pkg/tools/mcp_tool_test.go index 580abc2ba..95bb0f992 100644 --- a/pkg/tools/mcp_tool_test.go +++ b/pkg/tools/mcp_tool_test.go @@ -11,10 +11,14 @@ import ( // MockMCPManager is a mock implementation of MCPManager interface for testing type MockMCPManager struct { - callToolFunc func(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) + callToolFunc func(ctx context.Context, serverName, toolName string, arguments map[string]any) (*mcp.CallToolResult, error) } -func (m *MockMCPManager) CallTool(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { +func (m *MockMCPManager) CallTool( + ctx context.Context, + serverName, toolName string, + arguments map[string]any, +) (*mcp.CallToolResult, error) { if m.callToolFunc != nil { return m.callToolFunc(ctx, serverName, toolName, arguments) } @@ -32,10 +36,10 @@ func TestNewMCPTool(t *testing.T) { tool := &mcp.Tool{ Name: "test_tool", Description: "A test tool", - InputSchema: map[string]interface{}{ + InputSchema: map[string]any{ "type": "object", - "properties": map[string]interface{}{ - "input": map[string]interface{}{ + "properties": map[string]any{ + "input": map[string]any{ "type": "string", "description": "Test input", }, @@ -142,17 +146,17 @@ func TestMCPTool_Description(t *testing.T) { func TestMCPTool_Parameters(t *testing.T) { tests := []struct { name string - inputSchema interface{} + inputSchema any expectType string checkProperty string expectProperty bool }{ { name: "map schema", - inputSchema: map[string]interface{}{ + inputSchema: map[string]any{ "type": "object", - "properties": map[string]interface{}{ - "query": map[string]interface{}{ + "properties": map[string]any{ + "query": map[string]any{ "type": "string", "description": "Search query", }, @@ -212,7 +216,7 @@ func TestMCPTool_Parameters(t *testing.T) { // Check if property exists when expected if tt.checkProperty != "" { - properties, ok := params["properties"].(map[string]interface{}) + properties, ok := params["properties"].(map[string]any) if !ok && tt.expectProperty { t.Errorf("Expected properties to be a map") return @@ -232,7 +236,7 @@ func TestMCPTool_Parameters(t *testing.T) { // TestMCPTool_Execute_Success tests successful tool execution func TestMCPTool_Execute_Success(t *testing.T) { manager := &MockMCPManager{ - callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { + callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]any) (*mcp.CallToolResult, error) { // Verify correct parameters passed if serverName != "github" { t.Errorf("Expected serverName 'github', got '%s'", serverName) @@ -257,7 +261,7 @@ func TestMCPTool_Execute_Success(t *testing.T) { mcpTool := NewMCPTool(manager, "github", tool) ctx := context.Background() - args := map[string]interface{}{ + args := map[string]any{ "query": "golang mcp", } @@ -277,7 +281,7 @@ func TestMCPTool_Execute_Success(t *testing.T) { // TestMCPTool_Execute_ManagerError tests execution when manager returns error func TestMCPTool_Execute_ManagerError(t *testing.T) { manager := &MockMCPManager{ - callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { + callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]any) (*mcp.CallToolResult, error) { return nil, fmt.Errorf("connection failed") }, } @@ -286,7 +290,7 @@ func TestMCPTool_Execute_ManagerError(t *testing.T) { mcpTool := NewMCPTool(manager, "test_server", tool) ctx := context.Background() - result := mcpTool.Execute(ctx, map[string]interface{}{}) + result := mcpTool.Execute(ctx, map[string]any{}) if result == nil { t.Fatal("Result should not be nil") @@ -305,7 +309,7 @@ func TestMCPTool_Execute_ManagerError(t *testing.T) { // TestMCPTool_Execute_ServerError tests execution when server returns error func TestMCPTool_Execute_ServerError(t *testing.T) { manager := &MockMCPManager{ - callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { + callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]any) (*mcp.CallToolResult, error) { return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{Text: "Invalid API key"}, @@ -319,7 +323,7 @@ func TestMCPTool_Execute_ServerError(t *testing.T) { mcpTool := NewMCPTool(manager, "test_server", tool) ctx := context.Background() - result := mcpTool.Execute(ctx, map[string]interface{}{}) + result := mcpTool.Execute(ctx, map[string]any{}) if result == nil { t.Fatal("Result should not be nil") @@ -338,7 +342,7 @@ func TestMCPTool_Execute_ServerError(t *testing.T) { // TestMCPTool_Execute_MultipleContent tests execution with multiple content items func TestMCPTool_Execute_MultipleContent(t *testing.T) { manager := &MockMCPManager{ - callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { + callToolFunc: func(ctx context.Context, serverName, toolName string, arguments map[string]any) (*mcp.CallToolResult, error) { return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{Text: "First line"}, @@ -354,7 +358,7 @@ func TestMCPTool_Execute_MultipleContent(t *testing.T) { mcpTool := NewMCPTool(manager, "test_server", tool) ctx := context.Background() - result := mcpTool.Execute(ctx, map[string]interface{}{}) + result := mcpTool.Execute(ctx, map[string]any{}) if result.IsError { t.Errorf("Expected no error, got: %s", result.ForLLM) @@ -448,10 +452,10 @@ func TestMCPTool_InterfaceCompliance(t *testing.T) { // TestMCPTool_Parameters_MapSchema tests schema that's already a map func TestMCPTool_Parameters_MapSchema(t *testing.T) { manager := &MockMCPManager{} - schema := map[string]interface{}{ + schema := map[string]any{ "type": "object", - "properties": map[string]interface{}{ - "name": map[string]interface{}{ + "properties": map[string]any{ + "name": map[string]any{ "type": "string", "description": "The name parameter", }, @@ -472,12 +476,12 @@ func TestMCPTool_Parameters_MapSchema(t *testing.T) { t.Errorf("Expected type 'object', got '%v'", params["type"]) } - props, ok := params["properties"].(map[string]interface{}) + props, ok := params["properties"].(map[string]any) if !ok { t.Error("Properties should be a map") } - nameParam, ok := props["name"].(map[string]interface{}) + nameParam, ok := props["name"].(map[string]any) if !ok { t.Error("Name parameter should exist") }