Skip to content

Commit 301c699

Browse files
AnnhilucMarkDaoust
authored andcommitted
feat: Raises an error when there are duplicate tool names.
PiperOrigin-RevId: 758760508
1 parent 2bcca9c commit 301c699

3 files changed

Lines changed: 97 additions & 0 deletions

File tree

google/genai/_extra_utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ def get_function_map(
116116
raise errors.UnsupportedFunctionError(
117117
'MCP tools are not supported in synchronous methods.'
118118
)
119+
for tool_name, _ in mcp_to_genai_tool_adapters.items():
120+
if function_map.get(tool_name):
121+
raise ValueError(
122+
f'Tool {tool_name} is already defined for the request.'
123+
)
119124
function_map.update(mcp_to_genai_tool_adapters)
120125
return function_map
121126

@@ -459,6 +464,11 @@ async def parse_config_for_mcp_tools(
459464
if genai_tool.function_declarations:
460465
for function_declaration in genai_tool.function_declarations:
461466
if function_declaration.name:
467+
if mcp_to_genai_tool_adapters.get(function_declaration.name):
468+
raise ValueError(
469+
f'Tool {function_declaration.name} is already defined for'
470+
' the request.'
471+
)
462472
mcp_to_genai_tool_adapters[function_declaration.name] = (
463473
mcp_to_genai_tool_adapter
464474
)

google/genai/tests/afc/test_get_function_map.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,49 @@ async def list_tools(self):
128128
config, mcp_to_genai_tool_adapters, is_caller_method_async=True
129129
)
130130
assert isinstance(result['tool'], McpToGenAiToolAdapter)
131+
132+
133+
@pytest.mark.asyncio
134+
async def test_duplicate_mcp_tool_raises_error():
135+
if not _is_mcp_imported:
136+
return
137+
138+
class MockMcpClientSession(McpClientSession):
139+
140+
def __init__(self):
141+
self._read_stream = None
142+
self._write_stream = None
143+
144+
async def list_tools(self):
145+
return mcp_types.ListToolsResult(
146+
tools=[
147+
mcp_types.Tool(
148+
name='tool',
149+
description='tool-description',
150+
inputSchema={
151+
'type': 'OBJECT',
152+
'properties': {
153+
'key1': {
154+
'type': 'STRING',
155+
},
156+
'key2': {
157+
'type': 'NUMBER',
158+
},
159+
},
160+
},
161+
)
162+
]
163+
)
164+
165+
def tool():
166+
pass
167+
168+
session = MockMcpClientSession()
169+
config = GenerateContentConfig(tools=[tool, session])
170+
mcp_to_genai_tool_adapters = {
171+
'tool': McpToGenAiToolAdapter(session, [await session.list_tools()]),
172+
}
173+
with pytest.raises(ValueError):
174+
get_function_map(
175+
config, mcp_to_genai_tool_adapters, is_caller_method_async=True
176+
)

google/genai/tests/models/test_generate_content_mcp.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
try:
2222
from mcp import types as mcp_types
23+
from mcp import ClientSession as McpClientSession
2324
except ImportError as e:
2425
import sys
2526

@@ -64,3 +65,43 @@ async def test_mcp_tools_async(client):
6465
args={'location': 'Boston'},
6566
)
6667
]
68+
69+
70+
@pytest.mark.asyncio
71+
async def test_mcp_tools_duplicate_tool_name_raises_error(client):
72+
class MockMcpClientSession(McpClientSession):
73+
74+
def __init__(self):
75+
self._read_stream = None
76+
self._write_stream = None
77+
78+
async def list_tools(self):
79+
return mcp_types.ListToolsResult(
80+
tools=[
81+
mcp_types.Tool(
82+
name='get_weather',
83+
description='Get the weather in a city.',
84+
inputSchema={
85+
'type': 'object',
86+
'properties': {'location': {'type': 'string'}},
87+
},
88+
),
89+
mcp_types.Tool(
90+
name='get_weather',
91+
description='Different tool to get the weather.',
92+
inputSchema={
93+
'type': 'object',
94+
'properties': {'location': {'type': 'string'}},
95+
},
96+
),
97+
]
98+
)
99+
100+
with pytest.raises(ValueError):
101+
await client.aio.models.generate_content(
102+
model='gemini-2.0-flash',
103+
contents=t.t_contents(None, 'What is the weather in Boston?'),
104+
config={
105+
'tools': [MockMcpClientSession()],
106+
},
107+
)

0 commit comments

Comments
 (0)