12
12
from types import FrameType
13
13
from typing import TYPE_CHECKING , Any , Callable , ClassVar , Generic , cast , final , overload
14
14
15
+ from mcp import types as mcp_types
15
16
from opentelemetry .trace import NoOpTracer , use_span
16
17
from pydantic .json_schema import GenerateJsonSchema
17
18
from typing_extensions import Literal , Never , Self , TypeIs , TypeVar , deprecated
70
71
from fasta2a .broker import Broker
71
72
from fasta2a .schema import AgentProvider , Skill
72
73
from fasta2a .storage import Storage
73
- from mcp import types as mcp_types
74
74
from starlette .middleware import Middleware
75
75
from starlette .routing import BaseRoute , Route
76
76
from starlette .types import ExceptionHandler , Lifespan
@@ -1814,6 +1814,20 @@ async def __aenter__(self) -> Self:
1814
1814
async with self ._enter_lock :
1815
1815
if self ._entered_count == 0 :
1816
1816
self ._exit_stack = AsyncExitStack ()
1817
+
1818
+ for toolset in self ._user_toolsets :
1819
+ if isinstance (toolset , MCPServer ):
1820
+ if (
1821
+ hasattr (toolset , 'allow_elicitation' )
1822
+ and toolset .allow_elicitation
1823
+ and toolset .elicitation_callback is None
1824
+ ):
1825
+ toolset .elicitation_callback = self ._create_elicitation_callback ()
1826
+
1827
+ # Also setup auto-tool-injection for run_python_code if not already set
1828
+ if toolset .process_tool_call is None :
1829
+ toolset .process_tool_call = self ._create_auto_tool_injection_callback ()
1830
+
1817
1831
toolset = self ._get_toolset ()
1818
1832
await self ._exit_stack .enter_async_context (toolset )
1819
1833
self ._entered_count += 1
@@ -1866,23 +1880,36 @@ async def elicitation_callback(context: Any, params: Any) -> Any:
1866
1880
1867
1881
return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1868
1882
1869
- # Try MCP tools with name mapping
1870
- actual_tool_name = tool_name .replace ('_' , '-' )
1871
-
1883
+ # Find the MCP server that has this tool
1884
+ target_server = None
1872
1885
for toolset in self ._user_toolsets :
1873
1886
if not isinstance (toolset , MCPServer ):
1874
1887
continue
1875
- mcp_server = toolset
1876
- if 'mcp-run-python' in str (mcp_server ):
1888
+ if 'mcp-run-python' in str (toolset ):
1877
1889
continue
1878
1890
1891
+ # Check if this server has the tool
1879
1892
try :
1880
- result = await mcp_server .direct_call_tool (actual_tool_name , tool_arguments )
1881
- return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1893
+ server_tools = await toolset .list_tools ()
1894
+ for tool_def in server_tools :
1895
+ if tool_def .name == tool_name :
1896
+ target_server = toolset
1897
+ break
1898
+ if target_server :
1899
+ break
1882
1900
except Exception :
1883
1901
continue
1884
1902
1885
- return mcp_types .ErrorData (code = mcp_types .INVALID_PARAMS , message = f'Tool { tool_name } not found' )
1903
+ if target_server :
1904
+ try :
1905
+ result = await target_server .direct_call_tool (tool_name , tool_arguments )
1906
+ return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1907
+ except Exception as e :
1908
+ return mcp_types .ErrorData (
1909
+ code = mcp_types .INTERNAL_ERROR , message = f'Tool execution failed: { str (e )} '
1910
+ )
1911
+ else :
1912
+ return mcp_types .ErrorData (code = mcp_types .INVALID_PARAMS , message = f'Tool { tool_name } not found' )
1886
1913
1887
1914
except Exception as e :
1888
1915
return mcp_types .ErrorData (code = mcp_types .INTERNAL_ERROR , message = f'Tool execution failed: { str (e )} ' )
@@ -1900,30 +1927,37 @@ async def auto_inject_tools_callback(
1900
1927
) -> Any :
1901
1928
"""Auto-inject available tools into run_python_code calls."""
1902
1929
if tool_name == 'run_python_code' :
1903
- # Auto-inject available tools if not already provided
1904
- if 'tools' not in arguments or not arguments ['tools' ]:
1905
- available_tools : list [str ] = []
1906
-
1907
- # Add function tools
1908
- available_tools .extend (list (self ._function_toolset .tools .keys ()))
1909
-
1910
- for toolset in self ._user_toolsets :
1911
- if not isinstance (toolset , MCPServer ):
1912
- continue
1913
- mcp_server = toolset
1914
- if 'mcp-run-python' in str (mcp_server ):
1915
- continue
1916
-
1917
- try :
1918
- server_tools = await mcp_server .list_tools ()
1919
- for tool_def in server_tools :
1920
- python_name = tool_def .name .replace ('-' , '_' )
1921
- available_tools .append (python_name )
1922
- except Exception :
1923
- # Silently continue if we can't get tools from a server
1924
- pass
1925
-
1926
- arguments ['tools' ] = available_tools
1930
+ # Always auto-inject all available tools for Python code execution
1931
+ available_tools : list [str ] = []
1932
+ tool_name_mapping : dict [str , str ] = {}
1933
+
1934
+ # Add function tools
1935
+ function_tools = list (self ._function_toolset .tools .keys ())
1936
+ available_tools .extend (function_tools )
1937
+ for func_tool_name in function_tools :
1938
+ tool_name_mapping [func_tool_name ] = func_tool_name
1939
+
1940
+ # Add MCP server tools with proper name conversion
1941
+ for toolset in self ._user_toolsets :
1942
+ if not isinstance (toolset , MCPServer ):
1943
+ continue
1944
+ if 'mcp-run-python' in str (toolset ):
1945
+ continue
1946
+
1947
+ try :
1948
+ server_tools = await toolset .list_tools ()
1949
+ for tool_def in server_tools :
1950
+ original_name = tool_def .name
1951
+ python_name = original_name .replace ('-' , '_' )
1952
+ available_tools .append (python_name )
1953
+ tool_name_mapping [python_name ] = original_name
1954
+ except Exception :
1955
+ # Silently continue if we can't get tools from a server
1956
+ pass
1957
+
1958
+ # Always provide all available tools and mapping
1959
+ arguments ['tools' ] = available_tools
1960
+ arguments ['tool_name_mapping' ] = tool_name_mapping
1927
1961
1928
1962
# Continue with normal processing
1929
1963
return await call_tool_func (tool_name , arguments , None )
@@ -1954,17 +1988,16 @@ async def run_mcp_servers(
1954
1988
1955
1989
for toolset in self ._user_toolsets :
1956
1990
if isinstance (toolset , MCPServer ):
1957
- mcp_server = toolset
1958
1991
if (
1959
- hasattr (mcp_server , 'allow_elicitation' )
1960
- and mcp_server .allow_elicitation
1961
- and mcp_server .elicitation_callback is None
1992
+ hasattr (toolset , 'allow_elicitation' )
1993
+ and toolset .allow_elicitation
1994
+ and toolset .elicitation_callback is None
1962
1995
):
1963
- mcp_server .elicitation_callback = self ._create_elicitation_callback ()
1996
+ toolset .elicitation_callback = self ._create_elicitation_callback ()
1964
1997
1965
1998
# Also setup auto-tool-injection for run_python_code if not already set
1966
- if mcp_server .process_tool_call is None :
1967
- mcp_server .process_tool_call = self ._create_auto_tool_injection_callback ()
1999
+ if toolset .process_tool_call is None :
2000
+ toolset .process_tool_call = self ._create_auto_tool_injection_callback ()
1968
2001
1969
2002
async with self :
1970
2003
yield
0 commit comments