File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff 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 )
Original file line number Diff line number Diff 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+ )
Original file line number Diff line number Diff line change 2020
2121try :
2222 from mcp import types as mcp_types
23+ from mcp import ClientSession as McpClientSession
2324except 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+ )
You can’t perform that action at this time.
0 commit comments