From 0ffb0ba7889752a85357c83d319b6eabec5789cd Mon Sep 17 00:00:00 2001 From: Ed Zynda Date: Wed, 15 Apr 2026 11:27:47 +0300 Subject: [PATCH] refactor(tools): remove fantasy dependency from internal/tools - Replace fantasy.AgentTool with plain MCPTool struct in MCPToolManager - Move fantasy adapter from internal/tools to internal/agent as mcpAgentTool - Add MCPToolManager.ExecuteTool() for framework-agnostic tool execution - Remove dead fantasy.LanguageModel field from MCPConnectionPool - Remove MCPToolManager.SetModel() (was only feeding the dead field) internal/tools is now a pure MCP client library with no LLM framework dependency. The fantasy-to-MCP bridging is confined to the agent layer where it belongs. --- internal/agent/agent.go | 11 +- internal/agent/mcp_adapter.go | 65 +++++++ internal/tools/connection_pool.go | 6 +- internal/tools/fantasy_adapter.go | 109 ----------- internal/tools/mcp.go | 173 +++++++++++++----- .../tools/mcp_dynamic_integration_test.go | 6 +- internal/tools/mcp_dynamic_test.go | 2 +- internal/tools/mcp_test.go | 6 +- 8 files changed, 205 insertions(+), 173 deletions(-) create mode 100644 internal/agent/mcp_adapter.go delete mode 100644 internal/tools/fantasy_adapter.go diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 84b15cbd..6cdbbecb 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -245,7 +245,6 @@ func NewAgent(ctx context.Context, agentConfig *AgentConfig) (*Agent, error) { // The mcpReady channel is closed when loading completes (success or failure). if agentConfig.MCPConfig != nil && len(agentConfig.MCPConfig.MCPServers) > 0 { toolManager := tools.NewMCPToolManager() - toolManager.SetModel(providerResult.Model) if agentConfig.AuthHandler != nil { toolManager.SetAuthHandler(agentConfig.AuthHandler) } @@ -325,7 +324,7 @@ func (a *Agent) rebuildFantasyAgent() { allTools := make([]fantasy.AgentTool, len(a.coreTools)) copy(allTools, a.coreTools) if a.toolManager != nil { - allTools = append(allTools, a.toolManager.GetTools()...) + allTools = append(allTools, mcpToolsToAgentTools(a.toolManager.GetTools(), a.toolManager)...) } if len(a.extraTools) > 0 { allTools = append(allTools, a.extraTools...) @@ -808,7 +807,7 @@ func (a *Agent) GetTools() []fantasy.AgentTool { allTools := make([]fantasy.AgentTool, len(a.coreTools)) copy(allTools, a.coreTools) if a.toolManager != nil { - allTools = append(allTools, a.toolManager.GetTools()...) + allTools = append(allTools, mcpToolsToAgentTools(a.toolManager.GetTools(), a.toolManager)...) } if len(a.extraTools) > 0 { allTools = append(allTools, a.extraTools...) @@ -852,7 +851,6 @@ func (a *Agent) AddMCPServer(ctx context.Context, name string, cfg config.MCPSer if a.toolManager == nil { a.toolManager = tools.NewMCPToolManager() - a.toolManager.SetModel(a.model) if a.authHandler != nil { a.toolManager.SetAuthHandler(a.authHandler) } @@ -933,11 +931,6 @@ func (a *Agent) SetModel(ctx context.Context, config *models.ProviderConfig) err _ = a.providerCloser.Close() } - // Update model info on MCP tool manager. - if a.toolManager != nil { - a.toolManager.SetModel(providerResult.Model) - } - // Swap fields. a.model = providerResult.Model a.providerCloser = providerResult.Closer diff --git a/internal/agent/mcp_adapter.go b/internal/agent/mcp_adapter.go new file mode 100644 index 00000000..aef92832 --- /dev/null +++ b/internal/agent/mcp_adapter.go @@ -0,0 +1,65 @@ +package agent + +import ( + "context" + "fmt" + + "charm.land/fantasy" + + "github.com/mark3labs/kit/internal/tools" +) + +// mcpAgentTool adapts an tools.MCPTool to the fantasy.AgentTool interface. +// This keeps the fantasy dependency confined to the agent layer — the tools +// package is a pure MCP client library with no LLM framework dependency. +type mcpAgentTool struct { + tool tools.MCPTool + manager *tools.MCPToolManager + providerOptions fantasy.ProviderOptions +} + +// Info returns the fantasy tool info including name, description, and parameter schema. +func (t *mcpAgentTool) Info() fantasy.ToolInfo { + return fantasy.ToolInfo{ + Name: t.tool.Name, + Description: t.tool.Description, + Parameters: t.tool.Parameters, + Required: t.tool.Required, + } +} + +// Run executes the MCP tool by delegating to the MCPToolManager. +func (t *mcpAgentTool) Run(ctx context.Context, call fantasy.ToolCall) (fantasy.ToolResponse, error) { + result, err := t.manager.ExecuteTool(ctx, t.tool.Name, call.Input) + if err != nil { + return fantasy.ToolResponse{}, fmt.Errorf("mcp tool execution failed: %w", err) + } + + if result.IsError { + return fantasy.NewTextErrorResponse(result.Content), nil + } + return fantasy.NewTextResponse(result.Content), nil +} + +// ProviderOptions returns provider-specific options for this tool. +func (t *mcpAgentTool) ProviderOptions() fantasy.ProviderOptions { + return t.providerOptions +} + +// SetProviderOptions sets provider-specific options for this tool. +func (t *mcpAgentTool) SetProviderOptions(opts fantasy.ProviderOptions) { + t.providerOptions = opts +} + +// mcpToolsToAgentTools converts a slice of MCPTool to fantasy.AgentTool +// implementations that route execution through the MCPToolManager. +func mcpToolsToAgentTools(mcpTools []tools.MCPTool, manager *tools.MCPToolManager) []fantasy.AgentTool { + agentTools := make([]fantasy.AgentTool, len(mcpTools)) + for i, t := range mcpTools { + agentTools[i] = &mcpAgentTool{ + tool: t, + manager: manager, + } + } + return agentTools +} diff --git a/internal/tools/connection_pool.go b/internal/tools/connection_pool.go index 5e17f878..f4b7fae9 100644 --- a/internal/tools/connection_pool.go +++ b/internal/tools/connection_pool.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "charm.land/fantasy" "github.com/mark3labs/kit/internal/config" "github.com/mark3labs/mcp-go/client" "github.com/mark3labs/mcp-go/client/transport" @@ -63,7 +62,6 @@ type MCPConnectionPool struct { connections map[string]*MCPConnection config *ConnectionPoolConfig mu sync.RWMutex - model fantasy.LanguageModel ctx context.Context cancel context.CancelFunc debug bool @@ -75,9 +73,8 @@ type MCPConnectionPool struct { // NewMCPConnectionPool creates a new MCP connection pool with the specified configuration. // If config is nil, default configuration values will be used. The pool starts a background // goroutine for periodic health checks that runs until Close is called. -// The model parameter is used for MCP servers that require sampling support. // Thread-safe for concurrent use immediately after creation. -func NewMCPConnectionPool(config *ConnectionPoolConfig, model fantasy.LanguageModel, debug bool, authHandler MCPAuthHandler, tokenStoreFactory TokenStoreFactory) *MCPConnectionPool { +func NewMCPConnectionPool(config *ConnectionPoolConfig, debug bool, authHandler MCPAuthHandler, tokenStoreFactory TokenStoreFactory) *MCPConnectionPool { if config == nil { config = DefaultConnectionPoolConfig() } @@ -86,7 +83,6 @@ func NewMCPConnectionPool(config *ConnectionPoolConfig, model fantasy.LanguageMo pool := &MCPConnectionPool{ connections: make(map[string]*MCPConnection), config: config, - model: model, ctx: ctx, cancel: cancel, debug: debug, diff --git a/internal/tools/fantasy_adapter.go b/internal/tools/fantasy_adapter.go deleted file mode 100644 index e89e6d90..00000000 --- a/internal/tools/fantasy_adapter.go +++ /dev/null @@ -1,109 +0,0 @@ -package tools - -import ( - "context" - "encoding/json" - "fmt" - - "charm.land/fantasy" - "github.com/mark3labs/mcp-go/mcp" -) - -// mcpFantasyTool adapts an MCP tool to the fantasy.AgentTool interface. -// It bridges the MCP tool protocol with fantasy's agent tool system, handling -// name prefixing, schema conversion, connection pooling, and result marshaling. -type mcpFantasyTool struct { - toolInfo fantasy.ToolInfo - mapping *toolMapping - providerOptions fantasy.ProviderOptions -} - -// Info returns the fantasy tool info including name, description, and parameter schema. -func (t *mcpFantasyTool) Info() fantasy.ToolInfo { - return t.toolInfo -} - -// Run executes the MCP tool by routing through the connection pool. -// It maps the prefixed tool name back to the original name, retrieves a healthy -// connection, invokes the tool, and converts the MCP result to a fantasy ToolResponse. -func (t *mcpFantasyTool) Run(ctx context.Context, call fantasy.ToolCall) (fantasy.ToolResponse, error) { - // Parse and validate JSON arguments - var arguments any - input := call.Input - if input == "" || input == "{}" { - arguments = nil - } else { - var temp any - if err := json.Unmarshal([]byte(input), &temp); err != nil { - return fantasy.NewTextErrorResponse(fmt.Sprintf("invalid JSON arguments: %v", err)), nil - } - arguments = json.RawMessage(input) - } - - // Get connection from pool with health check - conn, err := t.mapping.manager.connectionPool.GetConnectionWithHealthCheck( - ctx, t.mapping.serverName, t.mapping.serverConfig, - ) - if err != nil { - return fantasy.ToolResponse{}, fmt.Errorf("failed to get healthy connection from pool: %w", err) - } - - // Call the MCP tool using the original (unprefixed) name - result, err := conn.client.CallTool(ctx, mcp.CallToolRequest{ - Request: mcp.Request{ - Method: "tools/call", - }, - Params: mcp.CallToolParams{ - Name: t.mapping.originalName, - Arguments: arguments, - }, - }) - if err != nil { - // Handle OAuth re-authorization: token may have expired mid-session. - if t.mapping.manager.connectionPool.oauthFlow != nil && IsOAuthError(err) { - if flowErr := t.mapping.manager.connectionPool.oauthFlow.RunAuthFlow(ctx, t.mapping.serverName, err); flowErr != nil { - return fantasy.ToolResponse{}, fmt.Errorf("OAuth re-authorization failed for tool %s: %w", t.mapping.originalName, flowErr) - } - // Retry the tool call after successful re-auth. - result, err = conn.client.CallTool(ctx, mcp.CallToolRequest{ - Request: mcp.Request{ - Method: "tools/call", - }, - Params: mcp.CallToolParams{ - Name: t.mapping.originalName, - Arguments: arguments, - }, - }) - if err != nil { - t.mapping.manager.connectionPool.HandleConnectionError(t.mapping.serverName, err) - return fantasy.ToolResponse{}, fmt.Errorf("failed to call mcp tool after re-auth: %w", err) - } - } else { - // Mark connection as unhealthy for automatic recovery - t.mapping.manager.connectionPool.HandleConnectionError(t.mapping.serverName, err) - return fantasy.ToolResponse{}, fmt.Errorf("failed to call mcp tool: %w", err) - } - } - - // Marshal the MCP result to JSON string - marshaledResult, err := json.Marshal(result) - if err != nil { - return fantasy.ToolResponse{}, fmt.Errorf("failed to marshal mcp tool result: %w", err) - } - - // Return as text response, preserving error status from MCP - if result.IsError { - return fantasy.NewTextErrorResponse(string(marshaledResult)), nil - } - return fantasy.NewTextResponse(string(marshaledResult)), nil -} - -// ProviderOptions returns provider-specific options for this tool. -func (t *mcpFantasyTool) ProviderOptions() fantasy.ProviderOptions { - return t.providerOptions -} - -// SetProviderOptions sets provider-specific options for this tool. -func (t *mcpFantasyTool) SetProviderOptions(opts fantasy.ProviderOptions) { - t.providerOptions = opts -} diff --git a/internal/tools/mcp.go b/internal/tools/mcp.go index 7702c995..4adebde2 100644 --- a/internal/tools/mcp.go +++ b/internal/tools/mcp.go @@ -9,22 +9,46 @@ import ( "strings" "sync" - "charm.land/fantasy" "github.com/mark3labs/kit/internal/config" "github.com/mark3labs/mcp-go/mcp" ) +// MCPTool represents a tool discovered from an MCP server. It contains all +// the metadata needed to present the tool to an LLM (name, description, JSON +// schema) plus the server origin information needed to execute it. +type MCPTool struct { + // Name is the prefixed tool name: "serverName__toolName". + Name string + // Description is the human-readable tool description. + Description string + // Parameters is the JSON Schema properties for the tool's input. + Parameters map[string]any + // Required lists the required parameter names. + Required []string + // ServerName is the MCP server this tool belongs to. + ServerName string + // OriginalName is the unprefixed tool name on the MCP server. + OriginalName string +} + +// MCPToolResult is the result of executing an MCP tool via ExecuteTool. +type MCPToolResult struct { + // Content is the JSON-encoded result from the MCP server. + Content string + // IsError indicates the MCP server reported a tool-level error. + IsError bool +} + // MCPToolManager manages MCP (Model Context Protocol) tools and clients across multiple servers. // It provides a unified interface for loading, managing, and executing tools from various MCP servers, // including stdio, SSE, streamable HTTP, and built-in server types. The manager handles connection -// pooling, health checks, tool name prefixing to avoid conflicts, and sampling support for LLM interactions. +// pooling, health checks, tool name prefixing to avoid conflicts, and OAuth re-authorization. // Thread-safe for concurrent tool invocations. type MCPToolManager struct { connectionPool *MCPConnectionPool - tools []fantasy.AgentTool + tools []MCPTool toolMap map[string]*toolMapping // maps prefixed tool names to their server and original name mu sync.Mutex // protects tools and toolMap during parallel loading - model fantasy.LanguageModel // LLM model for sampling authHandler MCPAuthHandler // OAuth handler for remote servers (nil = no OAuth) tokenStoreFactory TokenStoreFactory // factory for creating per-server token stores (nil = default FileTokenStore) config *config.Config @@ -36,8 +60,8 @@ type MCPToolManager struct { onServerLoaded func(serverName string, toolCount int, err error) // onToolsChanged, if non-nil, is called after AddServer or RemoveServer - // mutates the tool list. The agent layer uses this to trigger a - // rebuildFantasyAgent so the LLM sees the updated tools. + // mutates the tool list. The agent layer uses this to trigger a rebuild + // so the LLM sees the updated tools. onToolsChanged func() } @@ -46,27 +70,18 @@ type toolMapping struct { serverName string originalName string serverConfig config.MCPServerConfig - manager *MCPToolManager } // NewMCPToolManager creates a new MCP tool manager instance. // Returns an initialized manager with empty tool collections ready to load tools from MCP servers. -// The manager must be configured with SetModel and LoadTools before use. +// The manager must be configured with LoadTools before use. func NewMCPToolManager() *MCPToolManager { return &MCPToolManager{ - tools: make([]fantasy.AgentTool, 0), + tools: make([]MCPTool, 0), toolMap: make(map[string]*toolMapping), } } -// SetModel sets the LLM model for sampling support. -// The model is used when MCP servers request sampling operations, allowing them to -// leverage the host's LLM capabilities for text generation tasks. -// This method should be called before LoadTools if any MCP servers require sampling support. -func (m *MCPToolManager) SetModel(model fantasy.LanguageModel) { - m.model = model -} - // SetAuthHandler sets the OAuth handler for remote MCP server authentication. // When set, remote transports (streamable HTTP, SSE) are configured with OAuth // support, enabling automatic authorization flows when servers require authentication. @@ -109,7 +124,7 @@ func (m *MCPToolManager) SetOnServerLoaded(cb func(serverName string, toolCount // SetOnToolsChanged sets the callback that's invoked after AddServer or // RemoveServer mutates the tool list. The agent layer uses this to trigger -// a rebuild of the fantasy agent so the LLM sees the updated tool set. +// a rebuild so the LLM sees the updated tool set. func (m *MCPToolManager) SetOnToolsChanged(cb func()) { m.onToolsChanged = cb } @@ -182,9 +197,9 @@ func (m *MCPToolManager) RemoveServer(name string) error { } // Remove tools belonging to this server. - newTools := make([]fantasy.AgentTool, 0, len(m.tools)) + newTools := make([]MCPTool, 0, len(m.tools)) for _, t := range m.tools { - if len(t.Info().Name) < len(prefix) || t.Info().Name[:len(prefix)] != prefix { + if len(t.Name) < len(prefix) || t.Name[:len(prefix)] != prefix { newTools = append(newTools, t) } } @@ -223,7 +238,7 @@ func (m *MCPToolManager) ensureConnectionPool() { if m.debugLogger == nil { m.debugLogger = NewSimpleDebugLogger(debug) } - m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), m.model, debug, m.authHandler, m.tokenStoreFactory) + m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), debug, m.authHandler, m.tokenStoreFactory) m.connectionPool.SetDebugLogger(m.debugLogger) } @@ -239,7 +254,7 @@ func (m *MCPToolManager) LoadTools(ctx context.Context, cfg *config.Config) erro if m.debugLogger == nil { m.debugLogger = NewSimpleDebugLogger(cfg.Debug) } - m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), m.model, cfg.Debug, m.authHandler, m.tokenStoreFactory) + m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), cfg.Debug, m.authHandler, m.tokenStoreFactory) m.connectionPool.SetDebugLogger(m.debugLogger) // Load all servers in parallel. Each server connection (subprocess @@ -321,10 +336,10 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, } // Build tools locally before acquiring the lock. - var localTools []fantasy.AgentTool + var localTools []MCPTool localMap := make(map[string]*toolMapping) - // Convert MCP tools to fantasy AgentTools with prefixed names + // Convert MCP tools to MCPTool structs with prefixed names for _, mcpTool := range listResults.Tools { // Filter tools based on allowedTools/excludedTools if len(serverConfig.AllowedTools) > 0 { @@ -338,7 +353,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, continue } - // Convert MCP InputSchema to map[string]any for fantasy ToolInfo + // Convert MCP InputSchema to map[string]any marshaledSchema, err := json.Marshal(mcpTool.InputSchema) if err != nil { return -1, fmt.Errorf("conv mcp tool input schema fail(marshal): %w, tool name: %s", err, mcpTool.Name) @@ -347,7 +362,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, // Fix for JSON Schema draft-07 vs draft-04 compatibility marshaledSchema = convertExclusiveBoundsToBoolean(marshaledSchema) - // Parse into map[string]any for fantasy's parameters format + // Parse into map[string]any var schemaMap map[string]any if err := json.Unmarshal(marshaledSchema, &schemaMap); err != nil { return -1, fmt.Errorf("conv mcp tool input schema fail(unmarshal): %w, tool name: %s", err, mcpTool.Name) @@ -363,7 +378,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, // Fix for issue #89: Ensure object schemas have a properties field. // When schema type is "object" with no properties, we keep the - // empty parameters map — fantasy handles this fine. + // empty parameters map. if req, ok := schemaMap["required"].([]any); ok { for _, r := range req { @@ -381,22 +396,18 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, serverName: serverName, originalName: mcpTool.Name, serverConfig: serverConfig, - manager: m, } localMap[prefixedName] = mapping - // Create fantasy AgentTool - fantasyTool := &mcpFantasyTool{ - toolInfo: fantasy.ToolInfo{ - Name: prefixedName, - Description: mcpTool.Description, - Parameters: parameters, - Required: required, - }, - mapping: mapping, - } - - localTools = append(localTools, fantasyTool) + // Create MCPTool + localTools = append(localTools, MCPTool{ + Name: prefixedName, + Description: mcpTool.Description, + Parameters: parameters, + Required: required, + ServerName: serverName, + OriginalName: mcpTool.Name, + }) } // Merge into the manager under the lock. @@ -408,9 +419,87 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, return len(localTools), nil } -// GetTools returns all loaded tools as fantasy AgentTools from all configured MCP servers. +// ExecuteTool calls an MCP tool through the connection pool, handling health +// checks, OAuth re-authorization, and connection error tracking. +// The inputJSON parameter is the raw JSON arguments from the LLM. +// Returns the result content, error flag, and any execution error. +func (m *MCPToolManager) ExecuteTool(ctx context.Context, prefixedName, inputJSON string) (*MCPToolResult, error) { + m.mu.Lock() + mapping, ok := m.toolMap[prefixedName] + m.mu.Unlock() + if !ok { + return nil, fmt.Errorf("tool %q not found", prefixedName) + } + + // Parse and validate JSON arguments + var arguments any + if inputJSON == "" || inputJSON == "{}" { + arguments = nil + } else { + var temp any + if err := json.Unmarshal([]byte(inputJSON), &temp); err != nil { + return &MCPToolResult{ + Content: fmt.Sprintf("invalid JSON arguments: %v", err), + IsError: true, + }, nil + } + arguments = json.RawMessage(inputJSON) + } + + // Get connection from pool with health check + conn, err := m.connectionPool.GetConnectionWithHealthCheck( + ctx, mapping.serverName, mapping.serverConfig, + ) + if err != nil { + return nil, fmt.Errorf("failed to get healthy connection from pool: %w", err) + } + + callRequest := mcp.CallToolRequest{ + Request: mcp.Request{ + Method: "tools/call", + }, + Params: mcp.CallToolParams{ + Name: mapping.originalName, + Arguments: arguments, + }, + } + + // Call the MCP tool using the original (unprefixed) name + result, err := conn.client.CallTool(ctx, callRequest) + if err != nil { + // Handle OAuth re-authorization: token may have expired mid-session. + if m.connectionPool.oauthFlow != nil && IsOAuthError(err) { + if flowErr := m.connectionPool.oauthFlow.RunAuthFlow(ctx, mapping.serverName, err); flowErr != nil { + return nil, fmt.Errorf("OAuth re-authorization failed for tool %s: %w", mapping.originalName, flowErr) + } + // Retry the tool call after successful re-auth. + result, err = conn.client.CallTool(ctx, callRequest) + if err != nil { + m.connectionPool.HandleConnectionError(mapping.serverName, err) + return nil, fmt.Errorf("failed to call mcp tool after re-auth: %w", err) + } + } else { + // Mark connection as unhealthy for automatic recovery + m.connectionPool.HandleConnectionError(mapping.serverName, err) + return nil, fmt.Errorf("failed to call mcp tool: %w", err) + } + } + + // Marshal the MCP result to JSON string + marshaledResult, err := json.Marshal(result) + if err != nil { + return nil, fmt.Errorf("failed to marshal mcp tool result: %w", err) + } + + return &MCPToolResult{ + Content: string(marshaledResult), + IsError: result.IsError, + }, nil +} + +// GetTools returns all loaded MCP tools from all configured MCP servers. // Tools are returned with their prefixed names (serverName__toolName) to ensure uniqueness. -func (m *MCPToolManager) GetTools() []fantasy.AgentTool { +func (m *MCPToolManager) GetTools() []MCPTool { return m.tools } diff --git a/internal/tools/mcp_dynamic_integration_test.go b/internal/tools/mcp_dynamic_integration_test.go index 0a43270d..ae3fc034 100644 --- a/internal/tools/mcp_dynamic_integration_test.go +++ b/internal/tools/mcp_dynamic_integration_test.go @@ -101,7 +101,7 @@ func TestMCPToolManager_AddServer_Integration(t *testing.T) { // Verify tool names are prefixed. toolNames := make(map[string]bool) for _, tool := range tools { - toolNames[tool.Info().Name] = true + toolNames[tool.Name] = true } if !toolNames["echo__echo"] { t.Error("Expected tool 'echo__echo'") @@ -234,8 +234,8 @@ func TestMCPToolManager_AddRemoveMultiple_Integration(t *testing.T) { // Remaining tools should all be from server-b. for _, tool := range tools { - if !strings.HasPrefix(tool.Info().Name, "server-b__") { - t.Errorf("Expected tool from server-b, got: %s", tool.Info().Name) + if !strings.HasPrefix(tool.Name, "server-b__") { + t.Errorf("Expected tool from server-b, got: %s", tool.Name) } } diff --git a/internal/tools/mcp_dynamic_test.go b/internal/tools/mcp_dynamic_test.go index 257e1ed7..bfff6576 100644 --- a/internal/tools/mcp_dynamic_test.go +++ b/internal/tools/mcp_dynamic_test.go @@ -122,7 +122,7 @@ func TestMCPToolManager_Close_NilPool(t *testing.T) { // TestMCPConnectionPool_RemoveConnection_NotFound verifies that removing a // non-existent connection returns an error. func TestMCPConnectionPool_RemoveConnection_NotFound(t *testing.T) { - pool := NewMCPConnectionPool(DefaultConnectionPoolConfig(), nil, false, nil, nil) + pool := NewMCPConnectionPool(DefaultConnectionPoolConfig(), false, nil, nil) defer func() { _ = pool.Close() }() err := pool.RemoveConnection("nonexistent") diff --git a/internal/tools/mcp_test.go b/internal/tools/mcp_test.go index 09899bc0..90897409 100644 --- a/internal/tools/mcp_test.go +++ b/internal/tools/mcp_test.go @@ -103,14 +103,12 @@ func TestMCPToolManager_EmptyConfig(t *testing.T) { // Test that we can get tool info for each tool for _, tool := range tools { - info := tool.Info() - // Check that the tool has a valid name - if info.Name == "" { + if tool.Name == "" { t.Error("Tool has empty name") } - t.Logf("Tool: %s, Description: %s", info.Name, info.Description) + t.Logf("Tool: %s, Description: %s", tool.Name, tool.Description) } }