Skip to content

Commit 9500885

Browse files
CopilotOEvortex
andcommitted
Implement comprehensive MCP auto-configuration system with global tool sharing
Co-authored-by: OEvortex <158988478+OEvortex@users.noreply.github.com>
1 parent a09a756 commit 9500885

File tree

1 file changed

+71
-15
lines changed

1 file changed

+71
-15
lines changed

HelpingAI/client.py

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import platform
55
import os
6+
import threading
67
from typing import Optional, Dict, Any, Union, Iterator, List, Literal, cast, TYPE_CHECKING
78

89
import requests
@@ -510,8 +511,11 @@ def _convert_tools_parameter(
510511
return None
511512

512513
# Cache the tools configuration for direct calling
513-
self._tools_config = tools
514-
self._mcp_manager = None # Clear cached MCP manager
514+
self._client._tools_config = tools
515+
self._client._mcp_manager = None # Clear cached MCP manager
516+
517+
# Also store in global configuration for cross-client access
518+
self._client._store_global_tools_config(tools)
515519

516520
try:
517521
from .tools.compatibility import ensure_openai_format
@@ -869,6 +873,11 @@ class HAI(BaseClient):
869873
870874
This is the main entry point for interacting with the HelpingAI API.
871875
"""
876+
877+
# Global tools configuration storage for cross-client access
878+
_global_tools_config = None
879+
_global_config_lock = threading.Lock()
880+
872881
def __init__(
873882
self,
874883
api_key: Optional[str] = None,
@@ -915,6 +924,46 @@ def configure_tools(self, tools: Optional[Union[List[Dict[str, Any]], List, str]
915924
# Clear cached MCP manager to force reinitialization
916925
self._mcp_manager = None
917926

927+
# Also store in global configuration for cross-client access
928+
self._store_global_tools_config(tools)
929+
930+
def _store_global_tools_config(self, tools: Optional[Union[List[Dict[str, Any]], List, str]]) -> None:
931+
"""Store tools configuration globally for cross-client access.
932+
933+
Args:
934+
tools: Tools configuration to store globally
935+
"""
936+
with self._global_config_lock:
937+
self.__class__._global_tools_config = tools
938+
939+
def _get_effective_tools_config(self) -> Optional[Union[List[Dict[str, Any]], List, str]]:
940+
"""Get effective tools configuration, checking instance and global storage.
941+
942+
Returns:
943+
Tools configuration from instance or global storage
944+
"""
945+
# First check instance configuration
946+
if self._tools_config is not None:
947+
return self._tools_config
948+
949+
# Fall back to global configuration
950+
with self._global_config_lock:
951+
return self.__class__._global_tools_config
952+
953+
def _convert_tools_parameter(
954+
self,
955+
tools: Optional[Union[List[Dict[str, Any]], List, str]]
956+
) -> Optional[List[Dict[str, Any]]]:
957+
"""Convenience method to access ChatCompletions tool conversion.
958+
959+
Args:
960+
tools: Tools in various formats
961+
962+
Returns:
963+
List of OpenAI-compatible tool definitions or None
964+
"""
965+
return self.chat.completions._convert_tools_parameter(tools)
966+
918967
def call(self, tool_name: str, arguments: Union[Dict[str, Any], str, set]) -> Any:
919968
"""
920969
Directly call a tool by name with the given arguments.
@@ -964,13 +1013,14 @@ def call(self, tool_name: str, arguments: Union[Dict[str, Any], str, set]) -> An
9641013
result = fn_tool.call(processed_args)
9651014
return result
9661015

967-
# If not found, check if it's an MCP tool using cached configuration
1016+
# If not found, check if it's an MCP tool using effective configuration
9681017
# MCP tools are named with pattern: {server_name}-{tool_name}
969-
if self._tools_config:
1018+
effective_tools_config = self._get_effective_tools_config()
1019+
if effective_tools_config:
9701020
try:
971-
# Initialize MCP manager with cached configuration if needed
1021+
# Initialize MCP manager with effective configuration if needed
9721022
if not self._mcp_manager:
973-
self._mcp_manager = self._get_mcp_manager_for_tools()
1023+
self._mcp_manager = self._get_mcp_manager_for_tools(effective_tools_config)
9741024

9751025
if self._mcp_manager and self._mcp_manager.clients:
9761026
# Check if any MCP client has this tool
@@ -1000,33 +1050,39 @@ def call(self, tool_name: str, arguments: Union[Dict[str, Any], str, set]) -> An
10001050
error_msg = f"Tool '{tool_name}' not found"
10011051

10021052
# Check if this looks like an MCP tool name pattern
1003-
if '-' in tool_name and self._tools_config:
1053+
if '-' in tool_name and effective_tools_config:
10041054
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:
1055+
elif '-' in tool_name and not effective_tools_config:
1056+
error_msg += f". Tool '{tool_name}' appears to be an MCP tool but no tools are configured. Use client.configure_tools() or pass tools to chat.completions.create()"
1057+
elif not effective_tools_config:
10081058
error_msg += ". No tools configured - use client.configure_tools() or pass tools to chat.completions.create()"
10091059
else:
10101060
error_msg += " in registry, built-in tools, or configured MCP tools"
10111061

10121062
raise ValueError(error_msg)
10131063

1014-
def _get_mcp_manager_for_tools(self) -> Optional[Any]:
1015-
"""Get or create MCP manager using cached tools configuration.
1064+
def _get_mcp_manager_for_tools(self, tools_config: Optional[Union[List[Dict[str, Any]], List, str]] = None) -> Optional[Any]:
1065+
"""Get or create MCP manager using specified or cached tools configuration.
1066+
1067+
Args:
1068+
tools_config: Optional tools configuration to use. If None, uses effective config.
10161069
10171070
Returns:
10181071
MCPManager instance with tools configured, or None if no MCP config found
10191072
"""
1020-
if not self._tools_config:
1073+
if tools_config is None:
1074+
tools_config = self._get_effective_tools_config()
1075+
1076+
if not tools_config:
10211077
return None
10221078

10231079
try:
10241080
from .tools.mcp_manager import MCPManager
10251081

10261082
# Find MCP server configs in the tools configuration
10271083
mcp_configs = []
1028-
if isinstance(self._tools_config, list):
1029-
for item in self._tools_config:
1084+
if isinstance(tools_config, list):
1085+
for item in tools_config:
10301086
if isinstance(item, dict) and "mcpServers" in item:
10311087
mcp_configs.append(item)
10321088

0 commit comments

Comments
 (0)