@@ -19,6 +19,8 @@ import { ResourceScoring } from "../../services/resourceScoring";
1919import { RemixMCPServer } from '@remix/remix-ai-core' ;
2020import { endpointUrls } from "@remix-endpoints-helper"
2121import { text } from "stream/consumers" ;
22+ import { CodeExecutor } from "./codeExecutor" ;
23+ import { ToolApiGenerator } from "./toolApiGenerator" ;
2224
2325// Helper function to track events using MatomoManager instance
2426function trackMatomoEvent ( category : string , action : string , name ?: string ) {
@@ -1362,29 +1364,51 @@ export class MCPInferencer extends RemoteInferencer implements ICompletions, IGe
13621364 async getToolsForLLMRequest ( provider ?: string ) : Promise < any [ ] > {
13631365 const mcpTools = await this . getAvailableToolsForLLM ( ) ;
13641366
1365- // Format tools based on provider
1366- let convertedTools : any [ ] ;
1367+ if ( mcpTools . length === 0 ) {
1368+ return [ ] ;
1369+ }
1370+
1371+ // Generate compact tool descriptions
1372+ const apiGenerator = new ToolApiGenerator ( ) ;
1373+ const apiDescription = apiGenerator . generateAPIDescription ( ) ;
1374+ const toolsList = apiGenerator . generateToolsList ( mcpTools ) ;
1375+
1376+ console . log ( 'toolsList' , toolsList ) ;
13671377
1378+ // Create single execute_tool with TypeScript API definitions
1379+ const executeToolDef = {
1380+ name : "execute_tool" ,
1381+ description : `Execute TypeScript code to interact with the Remix IDE API.
1382+
1383+ ${ apiDescription }
1384+
1385+ ${ toolsList } `,
1386+ input_schema : {
1387+ type : "object" ,
1388+ properties : {
1389+ code : {
1390+ type : "string" ,
1391+ description : "TypeScript code to execute. Use callMCPTool(toolName, args) to call available tools."
1392+ }
1393+ } ,
1394+ required : [ "code" ]
1395+ }
1396+ } ;
1397+
1398+ // Format based on provider
13681399 if ( provider === 'anthropic' ) {
1369- // Anthropic format: direct object with name, description, input_schema
1370- convertedTools = mcpTools . map ( tool => ( {
1371- name : tool . name ,
1372- description : tool . description ,
1373- input_schema : tool . inputSchema
1374- } ) ) ;
1400+ return [ executeToolDef ] ;
13751401 } else {
1376- // OpenAI and other providers format: type + function wrapper
1377- convertedTools = mcpTools . map ( tool => ( {
1402+ // OpenAI and other providers format
1403+ return [ {
13781404 type : "function" ,
13791405 function : {
1380- name : tool . name ,
1381- description : tool . description ,
1382- parameters : tool . inputSchema
1406+ name : executeToolDef . name ,
1407+ description : executeToolDef . description ,
1408+ parameters : executeToolDef . input_schema
13831409 }
1384- } ) ) ;
1410+ } ] ;
13851411 }
1386-
1387- return convertedTools ;
13881412 }
13891413
13901414 convertLLMToolCallToMCP ( llmToolCall : any ) : IMCPToolCall {
@@ -1413,7 +1437,137 @@ export class MCPInferencer extends RemoteInferencer implements ICompletions, IGe
14131437 * Execute a tool call from the LLM
14141438 */
14151439 async executeToolForLLM ( toolCall : IMCPToolCall ) : Promise < IMCPToolResult > {
1416- // Find which server has this tool
1440+ // Handle code execution mode
1441+ if ( toolCall . name === 'execute_tool' ) {
1442+ const code = toolCall . arguments ?. code ;
1443+ if ( ! code || typeof code !== 'string' ) {
1444+ throw new Error ( 'execute_tool requires a code argument' ) ;
1445+ }
1446+
1447+ // Create code executor with callback to execute actual MCP tools
1448+ const codeExecutor = new CodeExecutor (
1449+ async ( innerToolCall : IMCPToolCall ) => {
1450+ // Find which server has this tool
1451+ const toolsFromServers = await this . getAllTools ( ) ;
1452+ let targetServer : string | undefined ;
1453+
1454+ for ( const [ serverName , tools ] of Object . entries ( toolsFromServers ) ) {
1455+ if ( tools . some ( tool => tool . name === innerToolCall . name ) ) {
1456+ targetServer = serverName ;
1457+ break ;
1458+ }
1459+ }
1460+
1461+ if ( ! targetServer ) {
1462+ throw new Error ( `Tool '${ innerToolCall . name } ' not found in any connected MCP server` ) ;
1463+ }
1464+
1465+ console . log ( `[MCP Code Mode] Executing tool ${ innerToolCall . name } from server ${ targetServer } ` ) ;
1466+ const result = await this . executeTool ( targetServer , innerToolCall ) ;
1467+ console . log ( `[MCP Code Mode] inner tool ${ innerToolCall . name } produced result` )
1468+ console . log ( result )
1469+ return result
1470+ } ,
1471+ 30000 // 30 second timeout
1472+ ) ;
1473+
1474+ // Execute the code
1475+ const result = await codeExecutor . execute ( code ) ;
1476+ console . log ( `[MCP Code Mode] inner tool executed with result` , result ) ;
1477+
1478+ // Convert code execution result to MCP tool result format
1479+ if ( result . success ) {
1480+ const content = [ ] ;
1481+
1482+ // Add all tool call results with their full payloads
1483+ if ( result . toolCallRecords && result . toolCallRecords . length > 0 ) {
1484+ content . push ( {
1485+ type : 'text' as const ,
1486+ text : `Tool Calls (${ result . toolCallRecords . length } ):`
1487+ } ) ;
1488+
1489+ for ( const record of result . toolCallRecords ) {
1490+ const toolResult = record . result . content
1491+ . map ( ( c : any ) => c . text || JSON . stringify ( c ) )
1492+ . join ( '\n' ) ;
1493+
1494+ content . push ( {
1495+ type : 'text' as const ,
1496+ text : `\n[${ record . name } ] (${ record . executionTime } ms)\nArguments: ${ JSON . stringify ( record . arguments , null , 2 ) } \nResult:\n${ toolResult } `
1497+ } ) ;
1498+ }
1499+ }
1500+
1501+ if ( result . output ) {
1502+ content . push ( {
1503+ type : 'text' as const ,
1504+ text : `\nConsole Output:\n${ result . output } `
1505+ } ) ;
1506+ }
1507+
1508+ if ( result . returnValue !== undefined ) {
1509+ content . push ( {
1510+ type : 'text' as const ,
1511+ text : `\nReturn Value:\n${ JSON . stringify ( result . returnValue , null , 2 ) } `
1512+ } ) ;
1513+ }
1514+
1515+ content . push ( {
1516+ type : 'text' as const ,
1517+ text : `\nExecution Stats:\n- Time: ${ result . executionTime } ms\n- Tools Called: ${ result . toolsCalled . join ( ', ' ) || 'none' } `
1518+ } ) ;
1519+
1520+ return {
1521+ content : content . length > 0 ? content : [ { type : 'text' , text : 'Code executed successfully with no output' } ] ,
1522+ isError : false
1523+ } ;
1524+ } else {
1525+ const content = [ ] ;
1526+
1527+ content . push ( {
1528+ type : 'text' as const ,
1529+ text : `Code Execution Error:\n${ result . error } `
1530+ } ) ;
1531+
1532+ // Include tool call results even on error
1533+ if ( result . toolCallRecords && result . toolCallRecords . length > 0 ) {
1534+ content . push ( {
1535+ type : 'text' as const ,
1536+ text : `\nTool Calls Before Error (${ result . toolCallRecords . length } ):`
1537+ } ) ;
1538+
1539+ for ( const record of result . toolCallRecords ) {
1540+ const toolResult = record . result . content
1541+ . map ( ( c : any ) => c . text || JSON . stringify ( c ) )
1542+ . join ( '\n' ) ;
1543+
1544+ content . push ( {
1545+ type : 'text' as const ,
1546+ text : `\n[${ record . name } ] (${ record . executionTime } ms)\nArguments: ${ JSON . stringify ( record . arguments , null , 2 ) } \nResult:\n${ toolResult } `
1547+ } ) ;
1548+ }
1549+ }
1550+
1551+ if ( result . output ) {
1552+ content . push ( {
1553+ type : 'text' as const ,
1554+ text : `\nConsole Output:\n${ result . output } `
1555+ } ) ;
1556+ }
1557+
1558+ content . push ( {
1559+ type : 'text' as const ,
1560+ text : `\nExecution Time: ${ result . executionTime } ms`
1561+ } ) ;
1562+
1563+ return {
1564+ content,
1565+ isError : true
1566+ } ;
1567+ }
1568+ }
1569+
1570+ // Fallback: Legacy direct tool execution (should not be reached with code mode)
14171571 const toolsFromServers = await this . getAllTools ( ) ;
14181572 let targetServer : string | undefined ;
14191573
@@ -1427,7 +1581,7 @@ export class MCPInferencer extends RemoteInferencer implements ICompletions, IGe
14271581 if ( ! targetServer ) {
14281582 throw new Error ( `Tool '${ toolCall . name } ' not found in any connected MCP server` ) ;
14291583 }
1430- console . log ( `executing tool ${ toolCall . name } from server ${ targetServer } ` )
1584+ console . log ( `[MCP Legacy Mode] Executing tool ${ toolCall . name } from server ${ targetServer } ` )
14311585 return this . executeTool ( targetServer , toolCall ) ;
14321586 }
14331587
0 commit comments