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
@@ -1795,6 +1795,20 @@ async def __aenter__(self) -> Self:
1795
1795
async with self ._enter_lock :
1796
1796
if self ._entered_count == 0 :
1797
1797
self ._exit_stack = AsyncExitStack ()
1798
+
1799
+ for toolset in self ._user_toolsets :
1800
+ if isinstance (toolset , MCPServer ):
1801
+ if (
1802
+ hasattr (toolset , 'allow_elicitation' )
1803
+ and toolset .allow_elicitation
1804
+ and toolset .elicitation_callback is None
1805
+ ):
1806
+ toolset .elicitation_callback = self ._create_elicitation_callback ()
1807
+
1808
+ # Also setup auto-tool-injection for run_python_code if not already set
1809
+ if toolset .process_tool_call is None :
1810
+ toolset .process_tool_call = self ._create_auto_tool_injection_callback ()
1811
+
1798
1812
toolset = self ._get_toolset ()
1799
1813
await self ._exit_stack .enter_async_context (toolset )
1800
1814
self ._entered_count += 1
@@ -1847,23 +1861,36 @@ async def elicitation_callback(context: Any, params: Any) -> Any:
1847
1861
1848
1862
return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1849
1863
1850
- # Try MCP tools with name mapping
1851
- actual_tool_name = tool_name .replace ('_' , '-' )
1852
-
1864
+ # Find the MCP server that has this tool
1865
+ target_server = None
1853
1866
for toolset in self ._user_toolsets :
1854
1867
if not isinstance (toolset , MCPServer ):
1855
1868
continue
1856
- mcp_server = toolset
1857
- if 'mcp-run-python' in str (mcp_server ):
1869
+ if 'mcp-run-python' in str (toolset ):
1858
1870
continue
1859
1871
1872
+ # Check if this server has the tool
1860
1873
try :
1861
- result = await mcp_server .direct_call_tool (actual_tool_name , tool_arguments )
1862
- return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1874
+ server_tools = await toolset .list_tools ()
1875
+ for tool_def in server_tools :
1876
+ if tool_def .name == tool_name :
1877
+ target_server = toolset
1878
+ break
1879
+ if target_server :
1880
+ break
1863
1881
except Exception :
1864
1882
continue
1865
1883
1866
- return mcp_types .ErrorData (code = mcp_types .INVALID_PARAMS , message = f'Tool { tool_name } not found' )
1884
+ if target_server :
1885
+ try :
1886
+ result = await target_server .direct_call_tool (tool_name , tool_arguments )
1887
+ return mcp_types .ElicitResult (action = 'accept' , content = {'result' : str (result )})
1888
+ except Exception as e :
1889
+ return mcp_types .ErrorData (
1890
+ code = mcp_types .INTERNAL_ERROR , message = f'Tool execution failed: { str (e )} '
1891
+ )
1892
+ else :
1893
+ return mcp_types .ErrorData (code = mcp_types .INVALID_PARAMS , message = f'Tool { tool_name } not found' )
1867
1894
1868
1895
except Exception as e :
1869
1896
return mcp_types .ErrorData (code = mcp_types .INTERNAL_ERROR , message = f'Tool execution failed: { str (e )} ' )
@@ -1881,30 +1908,37 @@ async def auto_inject_tools_callback(
1881
1908
) -> Any :
1882
1909
"""Auto-inject available tools into run_python_code calls."""
1883
1910
if tool_name == 'run_python_code' :
1884
- # Auto-inject available tools if not already provided
1885
- if 'tools' not in arguments or not arguments ['tools' ]:
1886
- available_tools : list [str ] = []
1887
-
1888
- # Add function tools
1889
- available_tools .extend (list (self ._function_toolset .tools .keys ()))
1890
-
1891
- for toolset in self ._user_toolsets :
1892
- if not isinstance (toolset , MCPServer ):
1893
- continue
1894
- mcp_server = toolset
1895
- if 'mcp-run-python' in str (mcp_server ):
1896
- continue
1897
-
1898
- try :
1899
- server_tools = await mcp_server .list_tools ()
1900
- for tool_def in server_tools :
1901
- python_name = tool_def .name .replace ('-' , '_' )
1902
- available_tools .append (python_name )
1903
- except Exception :
1904
- # Silently continue if we can't get tools from a server
1905
- pass
1906
-
1907
- arguments ['tools' ] = available_tools
1911
+ # Always auto-inject all available tools for Python code execution
1912
+ available_tools : list [str ] = []
1913
+ tool_name_mapping : dict [str , str ] = {}
1914
+
1915
+ # Add function tools
1916
+ function_tools = list (self ._function_toolset .tools .keys ())
1917
+ available_tools .extend (function_tools )
1918
+ for func_tool_name in function_tools :
1919
+ tool_name_mapping [func_tool_name ] = func_tool_name
1920
+
1921
+ # Add MCP server tools with proper name conversion
1922
+ for toolset in self ._user_toolsets :
1923
+ if not isinstance (toolset , MCPServer ):
1924
+ continue
1925
+ if 'mcp-run-python' in str (toolset ):
1926
+ continue
1927
+
1928
+ try :
1929
+ server_tools = await toolset .list_tools ()
1930
+ for tool_def in server_tools :
1931
+ original_name = tool_def .name
1932
+ python_name = original_name .replace ('-' , '_' )
1933
+ available_tools .append (python_name )
1934
+ tool_name_mapping [python_name ] = original_name
1935
+ except Exception :
1936
+ # Silently continue if we can't get tools from a server
1937
+ pass
1938
+
1939
+ # Always provide all available tools and mapping
1940
+ arguments ['tools' ] = available_tools
1941
+ arguments ['tool_name_mapping' ] = tool_name_mapping
1908
1942
1909
1943
# Continue with normal processing
1910
1944
return await call_tool_func (tool_name , arguments , None )
@@ -1935,17 +1969,16 @@ async def run_mcp_servers(
1935
1969
1936
1970
for toolset in self ._user_toolsets :
1937
1971
if isinstance (toolset , MCPServer ):
1938
- mcp_server = toolset
1939
1972
if (
1940
- hasattr (mcp_server , 'allow_elicitation' )
1941
- and mcp_server .allow_elicitation
1942
- and mcp_server .elicitation_callback is None
1973
+ hasattr (toolset , 'allow_elicitation' )
1974
+ and toolset .allow_elicitation
1975
+ and toolset .elicitation_callback is None
1943
1976
):
1944
- mcp_server .elicitation_callback = self ._create_elicitation_callback ()
1977
+ toolset .elicitation_callback = self ._create_elicitation_callback ()
1945
1978
1946
1979
# Also setup auto-tool-injection for run_python_code if not already set
1947
- if mcp_server .process_tool_call is None :
1948
- mcp_server .process_tool_call = self ._create_auto_tool_injection_callback ()
1980
+ if toolset .process_tool_call is None :
1981
+ toolset .process_tool_call = self ._create_auto_tool_injection_callback ()
1949
1982
1950
1983
async with self :
1951
1984
yield
0 commit comments