@@ -10,6 +10,10 @@ vi.mock("../../prompts/responses", () => ({
1010 toolResult : vi . fn ( ( result : string ) => `Tool result: ${ result } ` ) ,
1111 toolError : vi . fn ( ( error : string ) => `Tool error: ${ error } ` ) ,
1212 invalidMcpToolArgumentError : vi . fn ( ( server : string , tool : string ) => `Invalid args for ${ server } :${ tool } ` ) ,
13+ unknownMcpToolError : vi . fn ( ( server : string , tool : string , availableTools : string [ ] ) => {
14+ const toolsList = availableTools . length > 0 ? availableTools . join ( ", " ) : "No tools available"
15+ return `Tool '${ tool } ' does not exist on server '${ server } '. Available tools: ${ toolsList } `
16+ } ) ,
1317 } ,
1418} ) )
1519
@@ -18,6 +22,9 @@ vi.mock("../../../i18n", () => ({
1822 if ( key === "mcp:errors.invalidJsonArgument" && params ?. toolName ) {
1923 return `Roo tried to use ${ params . toolName } with an invalid JSON argument. Retrying...`
2024 }
25+ if ( key === "mcp:errors.toolNotFound" && params ) {
26+ return `Tool '${ params . toolName } ' does not exist on server '${ params . serverName } '. Available tools: ${ params . availableTools } `
27+ }
2128 return key
2229 } ) ,
2330} ) )
@@ -40,6 +47,7 @@ describe("useMcpToolTool", () => {
4047 deref : vi . fn ( ) . mockReturnValue ( {
4148 getMcpHub : vi . fn ( ) . mockReturnValue ( {
4249 callTool : vi . fn ( ) ,
50+ getAllServers : vi . fn ( ) . mockReturnValue ( [ ] ) ,
4351 } ) ,
4452 postMessageToWebview : vi . fn ( ) ,
4553 } ) ,
@@ -266,5 +274,151 @@ describe("useMcpToolTool", () => {
266274
267275 expect ( mockHandleError ) . toHaveBeenCalledWith ( "executing MCP tool" , error )
268276 } )
277+
278+ it ( "should reject unknown tool names" , async ( ) => {
279+ // Reset consecutiveMistakeCount for this test
280+ mockTask . consecutiveMistakeCount = 0
281+
282+ const mockServers = [
283+ {
284+ name : "test-server" ,
285+ tools : [
286+ { name : "existing-tool-1" , description : "Tool 1" } ,
287+ { name : "existing-tool-2" , description : "Tool 2" } ,
288+ ] ,
289+ } ,
290+ ]
291+
292+ mockProviderRef . deref . mockReturnValue ( {
293+ getMcpHub : ( ) => ( {
294+ getAllServers : vi . fn ( ) . mockReturnValue ( mockServers ) ,
295+ callTool : vi . fn ( ) ,
296+ } ) ,
297+ postMessageToWebview : vi . fn ( ) ,
298+ } )
299+
300+ const block : ToolUse = {
301+ type : "tool_use" ,
302+ name : "use_mcp_tool" ,
303+ params : {
304+ server_name : "test-server" ,
305+ tool_name : "non-existing-tool" ,
306+ arguments : JSON . stringify ( { test : "data" } ) ,
307+ } ,
308+ partial : false ,
309+ }
310+
311+ await useMcpToolTool (
312+ mockTask as Task ,
313+ block ,
314+ mockAskApproval ,
315+ mockHandleError ,
316+ mockPushToolResult ,
317+ mockRemoveClosingTag ,
318+ )
319+
320+ expect ( mockTask . consecutiveMistakeCount ) . toBe ( 1 )
321+ expect ( mockTask . recordToolError ) . toHaveBeenCalledWith ( "use_mcp_tool" )
322+ expect ( mockTask . say ) . toHaveBeenCalledWith ( "error" , expect . stringContaining ( "does not exist" ) )
323+ // Check that the error message contains available tools
324+ expect ( mockPushToolResult ) . toHaveBeenCalledWith ( expect . stringContaining ( "existing-tool-1" ) )
325+ expect ( mockPushToolResult ) . toHaveBeenCalledWith ( expect . stringContaining ( "existing-tool-2" ) )
326+ } )
327+
328+ it ( "should handle server with no tools" , async ( ) => {
329+ // Reset consecutiveMistakeCount for this test
330+ mockTask . consecutiveMistakeCount = 0
331+
332+ const mockServers = [
333+ {
334+ name : "test-server" ,
335+ tools : [ ] ,
336+ } ,
337+ ]
338+
339+ mockProviderRef . deref . mockReturnValue ( {
340+ getMcpHub : ( ) => ( {
341+ getAllServers : vi . fn ( ) . mockReturnValue ( mockServers ) ,
342+ callTool : vi . fn ( ) ,
343+ } ) ,
344+ postMessageToWebview : vi . fn ( ) ,
345+ } )
346+
347+ const block : ToolUse = {
348+ type : "tool_use" ,
349+ name : "use_mcp_tool" ,
350+ params : {
351+ server_name : "test-server" ,
352+ tool_name : "any-tool" ,
353+ arguments : JSON . stringify ( { test : "data" } ) ,
354+ } ,
355+ partial : false ,
356+ }
357+
358+ await useMcpToolTool (
359+ mockTask as Task ,
360+ block ,
361+ mockAskApproval ,
362+ mockHandleError ,
363+ mockPushToolResult ,
364+ mockRemoveClosingTag ,
365+ )
366+
367+ expect ( mockTask . consecutiveMistakeCount ) . toBe ( 1 )
368+ expect ( mockTask . recordToolError ) . toHaveBeenCalledWith ( "use_mcp_tool" )
369+ expect ( mockTask . say ) . toHaveBeenCalledWith ( "error" , expect . stringContaining ( "does not exist" ) )
370+ expect ( mockPushToolResult ) . toHaveBeenCalledWith ( expect . stringContaining ( "No tools available" ) )
371+ } )
372+
373+ it ( "should allow valid tool names" , async ( ) => {
374+ // Reset consecutiveMistakeCount for this test
375+ mockTask . consecutiveMistakeCount = 0
376+
377+ const mockServers = [
378+ {
379+ name : "test-server" ,
380+ tools : [ { name : "valid-tool" , description : "Valid Tool" } ] ,
381+ } ,
382+ ]
383+
384+ const mockToolResult = {
385+ content : [ { type : "text" , text : "Tool executed successfully" } ] ,
386+ }
387+
388+ mockProviderRef . deref . mockReturnValue ( {
389+ getMcpHub : ( ) => ( {
390+ getAllServers : vi . fn ( ) . mockReturnValue ( mockServers ) ,
391+ callTool : vi . fn ( ) . mockResolvedValue ( mockToolResult ) ,
392+ } ) ,
393+ postMessageToWebview : vi . fn ( ) ,
394+ } )
395+
396+ const block : ToolUse = {
397+ type : "tool_use" ,
398+ name : "use_mcp_tool" ,
399+ params : {
400+ server_name : "test-server" ,
401+ tool_name : "valid-tool" ,
402+ arguments : JSON . stringify ( { test : "data" } ) ,
403+ } ,
404+ partial : false ,
405+ }
406+
407+ mockAskApproval . mockResolvedValue ( true )
408+
409+ await useMcpToolTool (
410+ mockTask as Task ,
411+ block ,
412+ mockAskApproval ,
413+ mockHandleError ,
414+ mockPushToolResult ,
415+ mockRemoveClosingTag ,
416+ )
417+
418+ expect ( mockTask . consecutiveMistakeCount ) . toBe ( 0 )
419+ expect ( mockTask . recordToolError ) . not . toHaveBeenCalled ( )
420+ expect ( mockTask . say ) . toHaveBeenCalledWith ( "mcp_server_request_started" )
421+ expect ( mockTask . say ) . toHaveBeenCalledWith ( "mcp_server_response" , "Tool executed successfully" )
422+ } )
269423 } )
270424} )
0 commit comments