@@ -509,6 +509,10 @@ def _convert_tools_parameter(
509509 if tools is None :
510510 return None
511511
512+ # Cache the tools configuration for direct calling
513+ self ._tools_config = tools
514+ self ._mcp_manager = None # Clear cached MCP manager
515+
512516 try :
513517 from .tools .compatibility import ensure_openai_format
514518 return ensure_openai_format (tools )
@@ -883,6 +887,33 @@ def __init__(
883887 super ().__init__ (api_key , organization , base_url , timeout )
884888 self .chat : Chat = Chat (self )
885889 self .models : Models = Models (self )
890+ self ._tools_config : Optional [Union [List [Dict [str , Any ]], List , str ]] = None
891+ self ._mcp_manager = None
892+
893+ def configure_tools (self , tools : Optional [Union [List [Dict [str , Any ]], List , str ]]) -> None :
894+ """Configure tools for this client instance.
895+
896+ This makes tools available for direct calling via client.call().
897+
898+ Args:
899+ tools: Tools configuration in any supported format:
900+ - List containing MCP server configs, built-in tool names, OpenAI format tools
901+ - String identifier for built-in tools
902+ - None to clear tools configuration
903+
904+ Example:
905+ client.configure_tools([
906+ {'mcpServers': {
907+ 'time': {'command': 'uvx', 'args': ['mcp-server-time']},
908+ 'fetch': {'command': 'uvx', 'args': ['mcp-server-fetch']}
909+ }},
910+ 'code_interpreter',
911+ 'web_search'
912+ ])
913+ """
914+ self ._tools_config = tools
915+ # Clear cached MCP manager to force reinitialization
916+ self ._mcp_manager = None
886917
887918 def call (self , tool_name : str , arguments : Union [Dict [str , Any ], str , set ]) -> Any :
888919 """
@@ -933,36 +964,91 @@ def call(self, tool_name: str, arguments: Union[Dict[str, Any], str, set]) -> An
933964 result = fn_tool .call (processed_args )
934965 return result
935966
936- # If not found, check if it's an MCP tool
967+ # If not found, check if it's an MCP tool using cached configuration
937968 # MCP tools are named with pattern: {server_name}-{tool_name}
969+ if self ._tools_config :
970+ try :
971+ # Initialize MCP manager with cached configuration if needed
972+ if not self ._mcp_manager :
973+ self ._mcp_manager = self ._get_mcp_manager_for_tools ()
974+
975+ if self ._mcp_manager and self ._mcp_manager .clients :
976+ # Check if any MCP client has this tool
977+ for client_id , client in self ._mcp_manager .clients .items ():
978+ if hasattr (client , 'tools' ):
979+ for mcp_tool in client .tools :
980+ # Extract server name from client_id (format: {server_name}_{uuid})
981+ server_name = client_id .split ('_' )[0 ]
982+ expected_tool_name = f"{ server_name } -{ mcp_tool .name } "
983+
984+ if expected_tool_name == tool_name :
985+ # Found the MCP tool, create an Fn and call it
986+ fn_tool = self ._mcp_manager ._create_mcp_tool_fn (
987+ name = tool_name ,
988+ client_id = client_id ,
989+ mcp_tool_name = mcp_tool .name ,
990+ description = mcp_tool .description if hasattr (mcp_tool , 'description' ) else f"MCP tool: { tool_name } " ,
991+ parameters = mcp_tool .inputSchema if hasattr (mcp_tool , 'inputSchema' ) else {'type' : 'object' , 'properties' : {}, 'required' : []}
992+ )
993+ result = fn_tool .call (processed_args )
994+ return result
995+ except ImportError :
996+ # MCP package not available, skip MCP tool checking
997+ pass
998+
999+ # If still not found, provide a helpful error message
1000+ error_msg = f"Tool '{ tool_name } ' not found"
1001+
1002+ # Check if this looks like an MCP tool name pattern
1003+ if '-' in tool_name and self ._tools_config :
1004+ error_msg += f". Tool '{ tool_name } ' appears to be an MCP tool but MCP servers may not be properly initialized. Check that the MCP server is running and accessible."
1005+ elif '-' in tool_name and not self ._tools_config :
1006+ error_msg += f". Tool '{ tool_name } ' appears to be an MCP tool but no tools are configured. Use client.configure_tools() to set up MCP servers."
1007+ elif not self ._tools_config :
1008+ error_msg += ". No tools configured - use client.configure_tools() or pass tools to chat.completions.create()"
1009+ else :
1010+ error_msg += " in registry, built-in tools, or configured MCP tools"
1011+
1012+ raise ValueError (error_msg )
1013+
1014+ def _get_mcp_manager_for_tools (self ) -> Optional [Any ]:
1015+ """Get or create MCP manager using cached tools configuration.
1016+
1017+ Returns:
1018+ MCPManager instance with tools configured, or None if no MCP config found
1019+ """
1020+ if not self ._tools_config :
1021+ return None
1022+
9381023 try :
939- mcp_manager = MCPManager ()
940- if mcp_manager .clients :
941- # Check if any MCP client has this tool
942- for client_id , client in mcp_manager .clients .items ():
943- if hasattr (client , 'tools' ):
944- for mcp_tool in client .tools :
945- # Extract server name from client_id (format: {server_name}_{uuid})
946- server_name = client_id .split ('_' )[0 ]
947- expected_tool_name = f"{ server_name } -{ mcp_tool .name } "
948-
949- if expected_tool_name == tool_name :
950- # Found the MCP tool, create an Fn and call it
951- fn_tool = mcp_manager ._create_mcp_tool_fn (
952- name = tool_name ,
953- client_id = client_id ,
954- mcp_tool_name = mcp_tool .name ,
955- description = mcp_tool .description if hasattr (mcp_tool , 'description' ) else f"MCP tool: { tool_name } " ,
956- parameters = mcp_tool .inputSchema if hasattr (mcp_tool , 'inputSchema' ) else {'type' : 'object' , 'properties' : {}, 'required' : []}
957- )
958- result = fn_tool .call (processed_args )
959- return result
1024+ from .tools .mcp_manager import MCPManager
1025+
1026+ # Find MCP server configs in the tools configuration
1027+ mcp_configs = []
1028+ if isinstance (self ._tools_config , list ):
1029+ for item in self ._tools_config :
1030+ if isinstance (item , dict ) and "mcpServers" in item :
1031+ mcp_configs .append (item )
1032+
1033+ if not mcp_configs :
1034+ return None
1035+
1036+ # Initialize MCP manager with the found configurations
1037+ manager = MCPManager ()
1038+
1039+ # Initialize each MCP config (this populates manager.clients)
1040+ for config in mcp_configs :
1041+ try :
1042+ manager .init_config (config ) # This returns tools but also populates clients
1043+ except Exception as e :
1044+ # If initialization fails, continue with other configs
1045+ print (f"Warning: Failed to initialize MCP config { config } : { e } " )
1046+ continue
1047+
1048+ return manager if manager .clients else None
1049+
9601050 except ImportError :
961- # MCP package not available, skip MCP tool checking
962- pass
963-
964- # If still not found, raise an error
965- raise ValueError (f"Tool '{ tool_name } ' not found in registry, built-in tools, or MCP tools" )
1051+ return None
9661052
9671053 def _process_arguments (self , arguments : Union [Dict [str , Any ], str , set ], tool_name : str ) -> Dict [str , Any ]:
9681054 """
0 commit comments