@librechat/agents 3.0.69 → 3.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -398,24 +398,24 @@ function parseSearchResults(stdout) {
398
398
  return parsed;
399
399
  }
400
400
  /**
401
- * Formats search results into a human-readable string.
401
+ * Formats search results as structured JSON for efficient parsing.
402
402
  * @param searchResponse - The parsed search response
403
- * @returns Formatted string for LLM consumption
403
+ * @returns JSON string with search results
404
404
  */
405
405
  function formatSearchResults(searchResponse) {
406
406
  const { tool_references, total_tools_searched, pattern_used } = searchResponse;
407
- if (tool_references.length === 0) {
408
- return `No tools matched the pattern "${pattern_used}".\nTotal tools searched: ${total_tools_searched}`;
409
- }
410
- let response = `Found ${tool_references.length} matching tools:\n\n`;
411
- for (const ref of tool_references) {
412
- response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\n`;
413
- response += ` Matched in: ${ref.matched_field}\n`;
414
- response += ` Snippet: ${ref.snippet}\n\n`;
415
- }
416
- response += `Total tools searched: ${total_tools_searched}\n`;
417
- response += `Pattern used: ${pattern_used}`;
418
- return response;
407
+ const output = {
408
+ found: tool_references.length,
409
+ tools: tool_references.map((ref) => ({
410
+ name: ref.tool_name,
411
+ score: Number(ref.match_score.toFixed(2)),
412
+ matched_in: ref.matched_field,
413
+ snippet: ref.snippet,
414
+ })),
415
+ total_searched: total_tools_searched,
416
+ query: pattern_used,
417
+ };
418
+ return JSON.stringify(output, null, 2);
419
419
  }
420
420
  /**
421
421
  * Extracts the base tool name (without MCP server suffix) from a full tool name.
@@ -430,50 +430,44 @@ function getBaseToolName(toolName) {
430
430
  return toolName.substring(0, delimiterIndex);
431
431
  }
432
432
  /**
433
- * Formats a server listing response when listing all tools from MCP server(s).
434
- * Provides a cohesive view of all tools grouped by server.
433
+ * Formats a server listing response as structured JSON.
435
434
  * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
436
435
  * @param tools - Array of tool metadata from the server(s)
437
436
  * @param serverNames - The MCP server name(s)
438
- * @returns Formatted string showing all tools from the server(s)
437
+ * @returns JSON string showing all tools grouped by server
439
438
  */
440
439
  function formatServerListing(tools, serverNames) {
441
440
  const servers = Array.isArray(serverNames) ? serverNames : [serverNames];
442
441
  if (tools.length === 0) {
443
- return `No tools found from MCP server(s): ${servers.join(', ')}.`;
442
+ return JSON.stringify({
443
+ listing_mode: true,
444
+ servers,
445
+ total_tools: 0,
446
+ tools_by_server: {},
447
+ hint: 'No tools found from the specified MCP server(s).',
448
+ }, null, 2);
444
449
  }
445
- const toolsByServer = new Map();
450
+ const toolsByServer = {};
446
451
  for (const tool of tools) {
447
452
  const server = extractMcpServerName(tool.name) ?? 'unknown';
448
- const existing = toolsByServer.get(server) ?? [];
449
- existing.push(tool);
450
- toolsByServer.set(server, existing);
451
- }
452
- let response = servers.length === 1
453
- ? `## Tools from MCP server: ${servers[0]}\n\n`
454
- : `## Tools from MCP servers: ${servers.join(', ')}\n\n`;
455
- response += `Found ${tools.length} tool(s) (preview only - not yet loaded):\n\n`;
456
- for (const [server, serverTools] of toolsByServer) {
457
- if (servers.length > 1) {
458
- response += `### ${server}\n\n`;
459
- }
460
- for (const tool of serverTools) {
461
- const baseName = getBaseToolName(tool.name);
462
- response += `- **${baseName}**`;
463
- if (tool.description) {
464
- const shortDesc = tool.description.length > 80
465
- ? tool.description.substring(0, 77) + '...'
466
- : tool.description;
467
- response += `: ${shortDesc}`;
468
- }
469
- response += '\n';
470
- }
471
- if (servers.length > 1) {
472
- response += '\n';
453
+ if (!(server in toolsByServer)) {
454
+ toolsByServer[server] = [];
473
455
  }
456
+ toolsByServer[server].push({
457
+ name: getBaseToolName(tool.name),
458
+ description: tool.description.length > 100
459
+ ? tool.description.substring(0, 97) + '...'
460
+ : tool.description,
461
+ });
474
462
  }
475
- response += `\n_To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it._`;
476
- return response;
463
+ const output = {
464
+ listing_mode: true,
465
+ servers,
466
+ total_tools: tools.length,
467
+ tools_by_server: toolsByServer,
468
+ hint: `To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it.`,
469
+ };
470
+ return JSON.stringify(output, null, 2);
477
471
  }
478
472
  /**
479
473
  * Creates a Tool Search tool for discovering tools from a large registry.
@@ -1 +1 @@
1
- {"version":3,"file":"ToolSearch.cjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport { config } from 'dotenv';\nimport fetch, { RequestInit } from 'node-fetch';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getEnvironmentVariable } from '@langchain/core/utils/env';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { getCodeBaseURL } from './CodeExecutor';\nimport { EnvVar, Constants } from '@/common';\n\nconfig();\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 200;\n\n/** Maximum allowed regex nesting depth */\nconst MAX_REGEX_COMPLEXITY = 5;\n\n/** Default search timeout in milliseconds */\nconst SEARCH_TIMEOUT = 5000;\n\n/** Zod schema type for tool search parameters */\ntype ToolSearchSchema = z.ZodObject<{\n query: z.ZodDefault<z.ZodOptional<z.ZodString>>;\n fields: z.ZodDefault<\n z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>\n >;\n max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;\n mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\n}>;\n\n/**\n * Creates the Zod schema with dynamic query description based on mode.\n * @param mode - The search mode determining query interpretation\n * @returns Zod schema for tool search parameters\n */\nfunction createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {\n const queryDescription =\n mode === 'local'\n ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .describe(queryDescription),\n fields: z\n .array(z.enum(['name', 'description', 'parameters']))\n .optional()\n .default(['name', 'description'])\n .describe('Which fields to search. Default: name and description'),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .default(10)\n .describe('Maximum number of matching tools to return'),\n mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\n}\n\n/**\n * Escapes special regex characters in a string to use as a literal pattern.\n * @param pattern - The string to escape\n * @returns The escaped string safe for use in a RegExp\n */\nfunction escapeRegexSpecialChars(pattern: string): string {\n return pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Counts the maximum nesting depth of groups in a regex pattern.\n * @param pattern - The regex pattern to analyze\n * @returns The maximum nesting depth\n */\nfunction countNestedGroups(pattern: string): number {\n let maxDepth = 0;\n let currentDepth = 0;\n\n for (let i = 0; i < pattern.length; i++) {\n if (pattern[i] === '(' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth++;\n maxDepth = Math.max(maxDepth, currentDepth);\n } else if (pattern[i] === ')' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth = Math.max(0, currentDepth - 1);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Detects nested quantifiers that can cause catastrophic backtracking.\n * Patterns like (a+)+, (a*)*, (a+)*, etc.\n * @param pattern - The regex pattern to check\n * @returns True if nested quantifiers are detected\n */\nfunction hasNestedQuantifiers(pattern: string): boolean {\n const nestedQuantifierPattern = /\\([^)]*[+*][^)]*\\)[+*?]/;\n return nestedQuantifierPattern.test(pattern);\n}\n\n/**\n * Checks if a regex pattern contains potentially dangerous constructs.\n * @param pattern - The regex pattern to validate\n * @returns True if the pattern is dangerous\n */\nfunction isDangerousPattern(pattern: string): boolean {\n if (hasNestedQuantifiers(pattern)) {\n return true;\n }\n\n if (countNestedGroups(pattern) > MAX_REGEX_COMPLEXITY) {\n return true;\n }\n\n const dangerousPatterns = [\n /\\.\\{1000,\\}/, // Excessive wildcards\n /\\(\\?=\\.\\{100,\\}\\)/, // Runaway lookaheads\n /\\([^)]*\\|\\s*\\){20,}/, // Excessive alternation (rough check)\n /\\(\\.\\*\\)\\+/, // (.*)+\n /\\(\\.\\+\\)\\+/, // (.+)+\n /\\(\\.\\*\\)\\*/, // (.*)*\n /\\(\\.\\+\\)\\*/, // (.+)*\n ];\n\n for (const dangerous of dangerousPatterns) {\n if (dangerous.test(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a regex pattern for safe execution.\n * If the pattern is dangerous, it will be escaped to a literal string search.\n * @param pattern - The regex pattern to sanitize\n * @returns Object containing the safe pattern and whether it was escaped\n */\nfunction sanitizeRegex(pattern: string): { safe: string; wasEscaped: boolean } {\n if (isDangerousPattern(pattern)) {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n\n try {\n new RegExp(pattern);\n return { safe: pattern, wasEscaped: false };\n } catch {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n}\n\n/**\n * Simplifies tool parameters for search purposes.\n * Extracts only the essential structure needed for parameter name searching.\n * @param parameters - The tool's JSON schema parameters\n * @returns Simplified parameters object\n */\nfunction simplifyParametersForSearch(\n parameters?: t.JsonSchemaType\n): t.JsonSchemaType | undefined {\n if (!parameters) {\n return undefined;\n }\n\n if (parameters.properties) {\n return {\n type: parameters.type,\n properties: Object.fromEntries(\n Object.entries(parameters.properties).map(([key, value]) => [\n key,\n { type: (value as t.JsonSchemaType).type },\n ])\n ),\n } as t.JsonSchemaType;\n }\n\n return { type: parameters.type };\n}\n\n/**\n * Performs safe local substring search without regex.\n * Uses case-insensitive String.includes() for complete safety against ReDoS.\n * @param tools - Array of tool metadata to search\n * @param query - The search term (treated as literal substring)\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n const lowerQuery = query.toLowerCase();\n const results: t.ToolSearchResult[] = [];\n\n for (const tool of tools) {\n let bestScore = 0;\n let matchedField = '';\n let snippet = '';\n\n if (fields.includes('name')) {\n const lowerName = tool.name.toLowerCase();\n if (lowerName.includes(lowerQuery)) {\n const isExactMatch = lowerName === lowerQuery;\n const startsWithQuery = lowerName.startsWith(lowerQuery);\n bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;\n matchedField = 'name';\n snippet = tool.name;\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const lowerDesc = tool.description.toLowerCase();\n if (lowerDesc.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.7;\n matchedField = 'description';\n snippet = tool.description.substring(0, 100);\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties)\n .join(' ')\n .toLowerCase();\n if (paramNames.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.55;\n matchedField = 'parameters';\n snippet = Object.keys(tool.parameters.properties).join(' ');\n }\n }\n\n if (bestScore > 0) {\n results.push({\n tool_name: tool.name,\n match_score: bestScore,\n matched_field: matchedField,\n snippet,\n });\n }\n }\n\n results.sort((a, b) => b.match_score - a.match_score);\n const topResults = results.slice(0, maxResults);\n\n return {\n tool_references: topResults,\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n}\n\n/**\n * Generates the JavaScript search script to be executed in the sandbox.\n * Uses plain JavaScript for maximum compatibility with the Code API.\n * @param deferredTools - Array of tool metadata to search through\n * @param fields - Which fields to search\n * @param maxResults - Maximum number of results to return\n * @param sanitizedPattern - The sanitized regex pattern\n * @returns The JavaScript code string\n */\nfunction generateSearchScript(\n deferredTools: t.ToolMetadata[],\n fields: string[],\n maxResults: number,\n sanitizedPattern: string\n): string {\n const lines = [\n '// Tool definitions (injected)',\n 'var tools = ' + JSON.stringify(deferredTools) + ';',\n 'var searchFields = ' + JSON.stringify(fields) + ';',\n 'var maxResults = ' + maxResults + ';',\n 'var pattern = ' + JSON.stringify(sanitizedPattern) + ';',\n '',\n '// Compile regex (pattern is sanitized client-side)',\n 'var regex;',\n 'try {',\n ' regex = new RegExp(pattern, \\'i\\');',\n '} catch (e) {',\n ' regex = new RegExp(pattern.replace(/[.*+?^${}()[\\\\]\\\\\\\\|]/g, \"\\\\\\\\$&\"), \"i\");',\n '}',\n '',\n '// Search logic',\n 'var results = [];',\n '',\n 'for (var j = 0; j < tools.length; j++) {',\n ' var tool = tools[j];',\n ' var bestScore = 0;',\n ' var matchedField = \\'\\';',\n ' var snippet = \\'\\';',\n '',\n ' // Search name (highest priority)',\n ' if (searchFields.indexOf(\\'name\\') >= 0 && regex.test(tool.name)) {',\n ' bestScore = 0.95;',\n ' matchedField = \\'name\\';',\n ' snippet = tool.name;',\n ' }',\n '',\n ' // Search description (medium priority)',\n ' if (searchFields.indexOf(\\'description\\') >= 0 && tool.description && regex.test(tool.description)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.75;',\n ' matchedField = \\'description\\';',\n ' snippet = tool.description.substring(0, 100);',\n ' }',\n ' }',\n '',\n ' // Search parameter names (lower priority)',\n ' if (searchFields.indexOf(\\'parameters\\') >= 0 && tool.parameters && tool.parameters.properties) {',\n ' var paramNames = Object.keys(tool.parameters.properties).join(\\' \\');',\n ' if (regex.test(paramNames)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.60;',\n ' matchedField = \\'parameters\\';',\n ' snippet = paramNames;',\n ' }',\n ' }',\n ' }',\n '',\n ' if (bestScore > 0) {',\n ' results.push({',\n ' tool_name: tool.name,',\n ' match_score: bestScore,',\n ' matched_field: matchedField,',\n ' snippet: snippet',\n ' });',\n ' }',\n '}',\n '',\n '// Sort by score (descending) and limit results',\n 'results.sort(function(a, b) { return b.match_score - a.match_score; });',\n 'var topResults = results.slice(0, maxResults);',\n '',\n '// Output as JSON',\n 'console.log(JSON.stringify({',\n ' tool_references: topResults.map(function(r) {',\n ' return {',\n ' tool_name: r.tool_name,',\n ' match_score: r.match_score,',\n ' matched_field: r.matched_field,',\n ' snippet: r.snippet',\n ' };',\n ' }),',\n ' total_tools_searched: tools.length,',\n ' pattern_used: pattern',\n '}));',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Parses the search results from stdout JSON.\n * @param stdout - The stdout string containing JSON results\n * @returns Parsed search response\n */\nfunction parseSearchResults(stdout: string): t.ToolSearchResponse {\n const jsonMatch = stdout.trim();\n const parsed = JSON.parse(jsonMatch) as t.ToolSearchResponse;\n return parsed;\n}\n\n/**\n * Formats search results into a human-readable string.\n * @param searchResponse - The parsed search response\n * @returns Formatted string for LLM consumption\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n if (tool_references.length === 0) {\n return `No tools matched the pattern \"${pattern_used}\".\\nTotal tools searched: ${total_tools_searched}`;\n }\n\n let response = `Found ${tool_references.length} matching tools:\\n\\n`;\n\n for (const ref of tool_references) {\n response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\\n`;\n response += ` Matched in: ${ref.matched_field}\\n`;\n response += ` Snippet: ${ref.snippet}\\n\\n`;\n }\n\n response += `Total tools searched: ${total_tools_searched}\\n`;\n response += `Pattern used: ${pattern_used}`;\n\n return response;\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Formats a server listing response when listing all tools from MCP server(s).\n * Provides a cohesive view of all tools grouped by server.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns Formatted string showing all tools from the server(s)\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return `No tools found from MCP server(s): ${servers.join(', ')}.`;\n }\n\n const toolsByServer = new Map<string, t.ToolMetadata[]>();\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n const existing = toolsByServer.get(server) ?? [];\n existing.push(tool);\n toolsByServer.set(server, existing);\n }\n\n let response =\n servers.length === 1\n ? `## Tools from MCP server: ${servers[0]}\\n\\n`\n : `## Tools from MCP servers: ${servers.join(', ')}\\n\\n`;\n\n response += `Found ${tools.length} tool(s) (preview only - not yet loaded):\\n\\n`;\n\n for (const [server, serverTools] of toolsByServer) {\n if (servers.length > 1) {\n response += `### ${server}\\n\\n`;\n }\n for (const tool of serverTools) {\n const baseName = getBaseToolName(tool.name);\n response += `- **${baseName}**`;\n if (tool.description) {\n const shortDesc =\n tool.description.length > 80\n ? tool.description.substring(0, 77) + '...'\n : tool.description;\n response += `: ${shortDesc}`;\n }\n response += '\\n';\n }\n if (servers.length > 1) {\n response += '\\n';\n }\n }\n\n response += `\\n_To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it._`;\n\n return response;\n}\n\n/**\n * Creates a Tool Search tool for discovering tools from a large registry.\n *\n * This tool enables AI agents to dynamically discover tools from a large library\n * without loading all tool definitions into the LLM context window. The agent\n * can search for relevant tools on-demand.\n *\n * **Modes:**\n * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.\n * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.\n *\n * The tool registry can be provided either:\n * 1. At initialization time via params.toolRegistry\n * 2. At runtime via config.configurable.toolRegistry when invoking\n *\n * @param params - Configuration parameters for the tool (toolRegistry is optional)\n * @returns A LangChain DynamicStructuredTool for tool searching\n *\n * @example\n * // Option 1: Code interpreter mode (regex via sandbox)\n * const tool = createToolSearch({ apiKey, toolRegistry });\n * await tool.invoke({ query: 'expense.*report' });\n *\n * @example\n * // Option 2: Local mode (safe substring search, no API key needed)\n * const tool = createToolSearch({ mode: 'local', toolRegistry });\n * await tool.invoke({ query: 'expense' });\n */\nfunction createToolSearch(\n initParams: t.ToolSearchParams = {}\n): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {\n const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';\n const defaultOnlyDeferred = initParams.onlyDeferred ?? true;\n const schema = createToolSearchSchema(mode);\n\n const apiKey: string =\n mode === 'code_interpreter'\n ? ((initParams[EnvVar.CODE_API_KEY] as string | undefined) ??\n initParams.apiKey ??\n getEnvironmentVariable(EnvVar.CODE_API_KEY) ??\n '')\n : '';\n\n if (mode === 'code_interpreter' && !apiKey) {\n throw new Error(\n 'No API key provided for tool search in code_interpreter mode. Use mode: \"local\" to search without an API key.'\n );\n }\n\n const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();\n const EXEC_ENDPOINT = `${baseEndpoint}/exec`;\n\n const availableServers = getAvailableMcpServers(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const serverListText =\n availableServers.length > 0\n ? `\\n- Available MCP servers: ${availableServers.join(', ')}`\n : '';\n\n const mcpInstructions = `\n\nMCP Server Tools:\n- Tools from MCP servers follow the naming convention: toolName${Constants.MCP_DELIMITER}serverName\n- Example: \"get_weather${Constants.MCP_DELIMITER}weather-api\" is the \"get_weather\" tool from the \"weather-api\" server\n- Use mcp_server parameter to filter by server (e.g., mcp_server: \"weather-api\")\n- If mcp_server is provided without a query, lists ALL tools from that server${serverListText}`;\n\n const description =\n mode === 'local'\n ? `\nSearches through available tools to find ones matching your search term.\n\nUsage:\n- Provide a search term to find in tool names and descriptions.\n- Uses case-insensitive substring matching (fast and safe).\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.\n${mcpInstructions}\n`.trim()\n : `\nSearches through available tools to find ones matching your query pattern.\n\nUsage:\n- Provide a regex pattern to search tool names and descriptions.\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.9+) indicate name matches, medium scores (0.7+) indicate description matches.\n${mcpInstructions}\n`.trim();\n\n return tool<typeof schema>(\n async (params, config) => {\n const {\n query,\n fields = ['name', 'description'],\n max_results = 10,\n mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\n\n if (toolRegistry == null) {\n return [\n 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n error: 'No tool registry provided',\n },\n },\n ];\n }\n\n const toolsArray: t.LCTool[] = Array.from(toolRegistry.values());\n const deferredTools: t.ToolMetadata[] = toolsArray\n .filter((lcTool) => {\n if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return true;\n })\n .map((lcTool) => ({\n name: lcTool.name,\n description: lcTool.description ?? '',\n parameters: simplifyParametersForSearch(lcTool.parameters),\n }));\n\n if (deferredTools.length === 0) {\n const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\n },\n ];\n }\n\n if (mode === 'local') {\n const searchResponse = performLocalSearch(\n deferredTools,\n query,\n fields,\n max_results\n );\n const formattedOutput = formatSearchResults(searchResponse);\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\n },\n },\n ];\n }\n\n const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);\n let warningMessage = '';\n if (wasEscaped) {\n warningMessage =\n 'Note: The provided pattern was converted to a literal search for safety.\\n\\n';\n }\n\n const searchScript = generateSearchScript(\n deferredTools,\n fields,\n max_results,\n sanitizedPattern\n );\n\n const postData = {\n lang: 'js',\n code: searchScript,\n timeout: SEARCH_TIMEOUT,\n };\n\n try {\n const fetchOptions: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'LibreChat/1.0',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(postData),\n };\n\n if (process.env.PROXY != null && process.env.PROXY !== '') {\n fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);\n }\n\n const response = await fetch(EXEC_ENDPOINT, fetchOptions);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const result: t.ExecuteResult = await response.json();\n\n if (result.stderr && result.stderr.trim()) {\n // eslint-disable-next-line no-console\n console.warn('[ToolSearch] stderr:', result.stderr);\n }\n\n if (!result.stdout || !result.stdout.trim()) {\n return [\n `${warningMessage}No tools matched the pattern \"${sanitizedPattern}\".\\nTotal tools searched: ${deferredTools.length}`,\n {\n tool_references: [],\n metadata: {\n total_searched: deferredTools.length,\n pattern: sanitizedPattern,\n },\n },\n ];\n }\n\n const searchResponse = parseSearchResults(result.stdout);\n const formattedOutput = `${warningMessage}${formatSearchResults(searchResponse)}`;\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[ToolSearch] Error:', error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return [\n `Tool search failed: ${errorMessage}\\n\\nSuggestion: Try a simpler search pattern or search for specific tool names.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: sanitizedPattern,\n error: errorMessage,\n },\n },\n ];\n }\n },\n {\n name: Constants.TOOL_SEARCH,\n description,\n schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport {\n createToolSearch,\n performLocalSearch,\n extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":["config","z","Constants","EnvVar","getEnvironmentVariable","getCodeBaseURL","tool","HttpsProxyAgent"],"mappings":"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"}
1
+ {"version":3,"file":"ToolSearch.cjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport { config } from 'dotenv';\nimport fetch, { RequestInit } from 'node-fetch';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getEnvironmentVariable } from '@langchain/core/utils/env';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { getCodeBaseURL } from './CodeExecutor';\nimport { EnvVar, Constants } from '@/common';\n\nconfig();\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 200;\n\n/** Maximum allowed regex nesting depth */\nconst MAX_REGEX_COMPLEXITY = 5;\n\n/** Default search timeout in milliseconds */\nconst SEARCH_TIMEOUT = 5000;\n\n/** Zod schema type for tool search parameters */\ntype ToolSearchSchema = z.ZodObject<{\n query: z.ZodDefault<z.ZodOptional<z.ZodString>>;\n fields: z.ZodDefault<\n z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>\n >;\n max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;\n mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\n}>;\n\n/**\n * Creates the Zod schema with dynamic query description based on mode.\n * @param mode - The search mode determining query interpretation\n * @returns Zod schema for tool search parameters\n */\nfunction createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {\n const queryDescription =\n mode === 'local'\n ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .describe(queryDescription),\n fields: z\n .array(z.enum(['name', 'description', 'parameters']))\n .optional()\n .default(['name', 'description'])\n .describe('Which fields to search. Default: name and description'),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .default(10)\n .describe('Maximum number of matching tools to return'),\n mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\n}\n\n/**\n * Escapes special regex characters in a string to use as a literal pattern.\n * @param pattern - The string to escape\n * @returns The escaped string safe for use in a RegExp\n */\nfunction escapeRegexSpecialChars(pattern: string): string {\n return pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Counts the maximum nesting depth of groups in a regex pattern.\n * @param pattern - The regex pattern to analyze\n * @returns The maximum nesting depth\n */\nfunction countNestedGroups(pattern: string): number {\n let maxDepth = 0;\n let currentDepth = 0;\n\n for (let i = 0; i < pattern.length; i++) {\n if (pattern[i] === '(' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth++;\n maxDepth = Math.max(maxDepth, currentDepth);\n } else if (pattern[i] === ')' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth = Math.max(0, currentDepth - 1);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Detects nested quantifiers that can cause catastrophic backtracking.\n * Patterns like (a+)+, (a*)*, (a+)*, etc.\n * @param pattern - The regex pattern to check\n * @returns True if nested quantifiers are detected\n */\nfunction hasNestedQuantifiers(pattern: string): boolean {\n const nestedQuantifierPattern = /\\([^)]*[+*][^)]*\\)[+*?]/;\n return nestedQuantifierPattern.test(pattern);\n}\n\n/**\n * Checks if a regex pattern contains potentially dangerous constructs.\n * @param pattern - The regex pattern to validate\n * @returns True if the pattern is dangerous\n */\nfunction isDangerousPattern(pattern: string): boolean {\n if (hasNestedQuantifiers(pattern)) {\n return true;\n }\n\n if (countNestedGroups(pattern) > MAX_REGEX_COMPLEXITY) {\n return true;\n }\n\n const dangerousPatterns = [\n /\\.\\{1000,\\}/, // Excessive wildcards\n /\\(\\?=\\.\\{100,\\}\\)/, // Runaway lookaheads\n /\\([^)]*\\|\\s*\\){20,}/, // Excessive alternation (rough check)\n /\\(\\.\\*\\)\\+/, // (.*)+\n /\\(\\.\\+\\)\\+/, // (.+)+\n /\\(\\.\\*\\)\\*/, // (.*)*\n /\\(\\.\\+\\)\\*/, // (.+)*\n ];\n\n for (const dangerous of dangerousPatterns) {\n if (dangerous.test(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a regex pattern for safe execution.\n * If the pattern is dangerous, it will be escaped to a literal string search.\n * @param pattern - The regex pattern to sanitize\n * @returns Object containing the safe pattern and whether it was escaped\n */\nfunction sanitizeRegex(pattern: string): { safe: string; wasEscaped: boolean } {\n if (isDangerousPattern(pattern)) {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n\n try {\n new RegExp(pattern);\n return { safe: pattern, wasEscaped: false };\n } catch {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n}\n\n/**\n * Simplifies tool parameters for search purposes.\n * Extracts only the essential structure needed for parameter name searching.\n * @param parameters - The tool's JSON schema parameters\n * @returns Simplified parameters object\n */\nfunction simplifyParametersForSearch(\n parameters?: t.JsonSchemaType\n): t.JsonSchemaType | undefined {\n if (!parameters) {\n return undefined;\n }\n\n if (parameters.properties) {\n return {\n type: parameters.type,\n properties: Object.fromEntries(\n Object.entries(parameters.properties).map(([key, value]) => [\n key,\n { type: (value as t.JsonSchemaType).type },\n ])\n ),\n } as t.JsonSchemaType;\n }\n\n return { type: parameters.type };\n}\n\n/**\n * Performs safe local substring search without regex.\n * Uses case-insensitive String.includes() for complete safety against ReDoS.\n * @param tools - Array of tool metadata to search\n * @param query - The search term (treated as literal substring)\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n const lowerQuery = query.toLowerCase();\n const results: t.ToolSearchResult[] = [];\n\n for (const tool of tools) {\n let bestScore = 0;\n let matchedField = '';\n let snippet = '';\n\n if (fields.includes('name')) {\n const lowerName = tool.name.toLowerCase();\n if (lowerName.includes(lowerQuery)) {\n const isExactMatch = lowerName === lowerQuery;\n const startsWithQuery = lowerName.startsWith(lowerQuery);\n bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;\n matchedField = 'name';\n snippet = tool.name;\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const lowerDesc = tool.description.toLowerCase();\n if (lowerDesc.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.7;\n matchedField = 'description';\n snippet = tool.description.substring(0, 100);\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties)\n .join(' ')\n .toLowerCase();\n if (paramNames.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.55;\n matchedField = 'parameters';\n snippet = Object.keys(tool.parameters.properties).join(' ');\n }\n }\n\n if (bestScore > 0) {\n results.push({\n tool_name: tool.name,\n match_score: bestScore,\n matched_field: matchedField,\n snippet,\n });\n }\n }\n\n results.sort((a, b) => b.match_score - a.match_score);\n const topResults = results.slice(0, maxResults);\n\n return {\n tool_references: topResults,\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n}\n\n/**\n * Generates the JavaScript search script to be executed in the sandbox.\n * Uses plain JavaScript for maximum compatibility with the Code API.\n * @param deferredTools - Array of tool metadata to search through\n * @param fields - Which fields to search\n * @param maxResults - Maximum number of results to return\n * @param sanitizedPattern - The sanitized regex pattern\n * @returns The JavaScript code string\n */\nfunction generateSearchScript(\n deferredTools: t.ToolMetadata[],\n fields: string[],\n maxResults: number,\n sanitizedPattern: string\n): string {\n const lines = [\n '// Tool definitions (injected)',\n 'var tools = ' + JSON.stringify(deferredTools) + ';',\n 'var searchFields = ' + JSON.stringify(fields) + ';',\n 'var maxResults = ' + maxResults + ';',\n 'var pattern = ' + JSON.stringify(sanitizedPattern) + ';',\n '',\n '// Compile regex (pattern is sanitized client-side)',\n 'var regex;',\n 'try {',\n ' regex = new RegExp(pattern, \\'i\\');',\n '} catch (e) {',\n ' regex = new RegExp(pattern.replace(/[.*+?^${}()[\\\\]\\\\\\\\|]/g, \"\\\\\\\\$&\"), \"i\");',\n '}',\n '',\n '// Search logic',\n 'var results = [];',\n '',\n 'for (var j = 0; j < tools.length; j++) {',\n ' var tool = tools[j];',\n ' var bestScore = 0;',\n ' var matchedField = \\'\\';',\n ' var snippet = \\'\\';',\n '',\n ' // Search name (highest priority)',\n ' if (searchFields.indexOf(\\'name\\') >= 0 && regex.test(tool.name)) {',\n ' bestScore = 0.95;',\n ' matchedField = \\'name\\';',\n ' snippet = tool.name;',\n ' }',\n '',\n ' // Search description (medium priority)',\n ' if (searchFields.indexOf(\\'description\\') >= 0 && tool.description && regex.test(tool.description)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.75;',\n ' matchedField = \\'description\\';',\n ' snippet = tool.description.substring(0, 100);',\n ' }',\n ' }',\n '',\n ' // Search parameter names (lower priority)',\n ' if (searchFields.indexOf(\\'parameters\\') >= 0 && tool.parameters && tool.parameters.properties) {',\n ' var paramNames = Object.keys(tool.parameters.properties).join(\\' \\');',\n ' if (regex.test(paramNames)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.60;',\n ' matchedField = \\'parameters\\';',\n ' snippet = paramNames;',\n ' }',\n ' }',\n ' }',\n '',\n ' if (bestScore > 0) {',\n ' results.push({',\n ' tool_name: tool.name,',\n ' match_score: bestScore,',\n ' matched_field: matchedField,',\n ' snippet: snippet',\n ' });',\n ' }',\n '}',\n '',\n '// Sort by score (descending) and limit results',\n 'results.sort(function(a, b) { return b.match_score - a.match_score; });',\n 'var topResults = results.slice(0, maxResults);',\n '',\n '// Output as JSON',\n 'console.log(JSON.stringify({',\n ' tool_references: topResults.map(function(r) {',\n ' return {',\n ' tool_name: r.tool_name,',\n ' match_score: r.match_score,',\n ' matched_field: r.matched_field,',\n ' snippet: r.snippet',\n ' };',\n ' }),',\n ' total_tools_searched: tools.length,',\n ' pattern_used: pattern',\n '}));',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Parses the search results from stdout JSON.\n * @param stdout - The stdout string containing JSON results\n * @returns Parsed search response\n */\nfunction parseSearchResults(stdout: string): t.ToolSearchResponse {\n const jsonMatch = stdout.trim();\n const parsed = JSON.parse(jsonMatch) as t.ToolSearchResponse;\n return parsed;\n}\n\n/**\n * Formats search results as structured JSON for efficient parsing.\n * @param searchResponse - The parsed search response\n * @returns JSON string with search results\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n const output = {\n found: tool_references.length,\n tools: tool_references.map((ref) => ({\n name: ref.tool_name,\n score: Number(ref.match_score.toFixed(2)),\n matched_in: ref.matched_field,\n snippet: ref.snippet,\n })),\n total_searched: total_tools_searched,\n query: pattern_used,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Formats a server listing response as structured JSON.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns JSON string showing all tools grouped by server\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return JSON.stringify(\n {\n listing_mode: true,\n servers,\n total_tools: 0,\n tools_by_server: {},\n hint: 'No tools found from the specified MCP server(s).',\n },\n null,\n 2\n );\n }\n\n const toolsByServer: Record<\n string,\n Array<{ name: string; description: string }>\n > = {};\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n if (!(server in toolsByServer)) {\n toolsByServer[server] = [];\n }\n toolsByServer[server].push({\n name: getBaseToolName(tool.name),\n description:\n tool.description.length > 100\n ? tool.description.substring(0, 97) + '...'\n : tool.description,\n });\n }\n\n const output = {\n listing_mode: true,\n servers,\n total_tools: tools.length,\n tools_by_server: toolsByServer,\n hint: `To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it.`,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Creates a Tool Search tool for discovering tools from a large registry.\n *\n * This tool enables AI agents to dynamically discover tools from a large library\n * without loading all tool definitions into the LLM context window. The agent\n * can search for relevant tools on-demand.\n *\n * **Modes:**\n * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.\n * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.\n *\n * The tool registry can be provided either:\n * 1. At initialization time via params.toolRegistry\n * 2. At runtime via config.configurable.toolRegistry when invoking\n *\n * @param params - Configuration parameters for the tool (toolRegistry is optional)\n * @returns A LangChain DynamicStructuredTool for tool searching\n *\n * @example\n * // Option 1: Code interpreter mode (regex via sandbox)\n * const tool = createToolSearch({ apiKey, toolRegistry });\n * await tool.invoke({ query: 'expense.*report' });\n *\n * @example\n * // Option 2: Local mode (safe substring search, no API key needed)\n * const tool = createToolSearch({ mode: 'local', toolRegistry });\n * await tool.invoke({ query: 'expense' });\n */\nfunction createToolSearch(\n initParams: t.ToolSearchParams = {}\n): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {\n const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';\n const defaultOnlyDeferred = initParams.onlyDeferred ?? true;\n const schema = createToolSearchSchema(mode);\n\n const apiKey: string =\n mode === 'code_interpreter'\n ? ((initParams[EnvVar.CODE_API_KEY] as string | undefined) ??\n initParams.apiKey ??\n getEnvironmentVariable(EnvVar.CODE_API_KEY) ??\n '')\n : '';\n\n if (mode === 'code_interpreter' && !apiKey) {\n throw new Error(\n 'No API key provided for tool search in code_interpreter mode. Use mode: \"local\" to search without an API key.'\n );\n }\n\n const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();\n const EXEC_ENDPOINT = `${baseEndpoint}/exec`;\n\n const availableServers = getAvailableMcpServers(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const serverListText =\n availableServers.length > 0\n ? `\\n- Available MCP servers: ${availableServers.join(', ')}`\n : '';\n\n const mcpInstructions = `\n\nMCP Server Tools:\n- Tools from MCP servers follow the naming convention: toolName${Constants.MCP_DELIMITER}serverName\n- Example: \"get_weather${Constants.MCP_DELIMITER}weather-api\" is the \"get_weather\" tool from the \"weather-api\" server\n- Use mcp_server parameter to filter by server (e.g., mcp_server: \"weather-api\")\n- If mcp_server is provided without a query, lists ALL tools from that server${serverListText}`;\n\n const description =\n mode === 'local'\n ? `\nSearches through available tools to find ones matching your search term.\n\nUsage:\n- Provide a search term to find in tool names and descriptions.\n- Uses case-insensitive substring matching (fast and safe).\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.\n${mcpInstructions}\n`.trim()\n : `\nSearches through available tools to find ones matching your query pattern.\n\nUsage:\n- Provide a regex pattern to search tool names and descriptions.\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.9+) indicate name matches, medium scores (0.7+) indicate description matches.\n${mcpInstructions}\n`.trim();\n\n return tool<typeof schema>(\n async (params, config) => {\n const {\n query,\n fields = ['name', 'description'],\n max_results = 10,\n mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\n\n if (toolRegistry == null) {\n return [\n 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n error: 'No tool registry provided',\n },\n },\n ];\n }\n\n const toolsArray: t.LCTool[] = Array.from(toolRegistry.values());\n const deferredTools: t.ToolMetadata[] = toolsArray\n .filter((lcTool) => {\n if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return true;\n })\n .map((lcTool) => ({\n name: lcTool.name,\n description: lcTool.description ?? '',\n parameters: simplifyParametersForSearch(lcTool.parameters),\n }));\n\n if (deferredTools.length === 0) {\n const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\n },\n ];\n }\n\n if (mode === 'local') {\n const searchResponse = performLocalSearch(\n deferredTools,\n query,\n fields,\n max_results\n );\n const formattedOutput = formatSearchResults(searchResponse);\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\n },\n },\n ];\n }\n\n const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);\n let warningMessage = '';\n if (wasEscaped) {\n warningMessage =\n 'Note: The provided pattern was converted to a literal search for safety.\\n\\n';\n }\n\n const searchScript = generateSearchScript(\n deferredTools,\n fields,\n max_results,\n sanitizedPattern\n );\n\n const postData = {\n lang: 'js',\n code: searchScript,\n timeout: SEARCH_TIMEOUT,\n };\n\n try {\n const fetchOptions: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'LibreChat/1.0',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(postData),\n };\n\n if (process.env.PROXY != null && process.env.PROXY !== '') {\n fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);\n }\n\n const response = await fetch(EXEC_ENDPOINT, fetchOptions);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const result: t.ExecuteResult = await response.json();\n\n if (result.stderr && result.stderr.trim()) {\n // eslint-disable-next-line no-console\n console.warn('[ToolSearch] stderr:', result.stderr);\n }\n\n if (!result.stdout || !result.stdout.trim()) {\n return [\n `${warningMessage}No tools matched the pattern \"${sanitizedPattern}\".\\nTotal tools searched: ${deferredTools.length}`,\n {\n tool_references: [],\n metadata: {\n total_searched: deferredTools.length,\n pattern: sanitizedPattern,\n },\n },\n ];\n }\n\n const searchResponse = parseSearchResults(result.stdout);\n const formattedOutput = `${warningMessage}${formatSearchResults(searchResponse)}`;\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[ToolSearch] Error:', error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return [\n `Tool search failed: ${errorMessage}\\n\\nSuggestion: Try a simpler search pattern or search for specific tool names.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: sanitizedPattern,\n error: errorMessage,\n },\n },\n ];\n }\n },\n {\n name: Constants.TOOL_SEARCH,\n description,\n schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport {\n createToolSearch,\n performLocalSearch,\n extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":["config","z","Constants","EnvVar","getEnvironmentVariable","getCodeBaseURL","tool","HttpsProxyAgent"],"mappings":"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"}
@@ -396,24 +396,24 @@ function parseSearchResults(stdout) {
396
396
  return parsed;
397
397
  }
398
398
  /**
399
- * Formats search results into a human-readable string.
399
+ * Formats search results as structured JSON for efficient parsing.
400
400
  * @param searchResponse - The parsed search response
401
- * @returns Formatted string for LLM consumption
401
+ * @returns JSON string with search results
402
402
  */
403
403
  function formatSearchResults(searchResponse) {
404
404
  const { tool_references, total_tools_searched, pattern_used } = searchResponse;
405
- if (tool_references.length === 0) {
406
- return `No tools matched the pattern "${pattern_used}".\nTotal tools searched: ${total_tools_searched}`;
407
- }
408
- let response = `Found ${tool_references.length} matching tools:\n\n`;
409
- for (const ref of tool_references) {
410
- response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\n`;
411
- response += ` Matched in: ${ref.matched_field}\n`;
412
- response += ` Snippet: ${ref.snippet}\n\n`;
413
- }
414
- response += `Total tools searched: ${total_tools_searched}\n`;
415
- response += `Pattern used: ${pattern_used}`;
416
- return response;
405
+ const output = {
406
+ found: tool_references.length,
407
+ tools: tool_references.map((ref) => ({
408
+ name: ref.tool_name,
409
+ score: Number(ref.match_score.toFixed(2)),
410
+ matched_in: ref.matched_field,
411
+ snippet: ref.snippet,
412
+ })),
413
+ total_searched: total_tools_searched,
414
+ query: pattern_used,
415
+ };
416
+ return JSON.stringify(output, null, 2);
417
417
  }
418
418
  /**
419
419
  * Extracts the base tool name (without MCP server suffix) from a full tool name.
@@ -428,50 +428,44 @@ function getBaseToolName(toolName) {
428
428
  return toolName.substring(0, delimiterIndex);
429
429
  }
430
430
  /**
431
- * Formats a server listing response when listing all tools from MCP server(s).
432
- * Provides a cohesive view of all tools grouped by server.
431
+ * Formats a server listing response as structured JSON.
433
432
  * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
434
433
  * @param tools - Array of tool metadata from the server(s)
435
434
  * @param serverNames - The MCP server name(s)
436
- * @returns Formatted string showing all tools from the server(s)
435
+ * @returns JSON string showing all tools grouped by server
437
436
  */
438
437
  function formatServerListing(tools, serverNames) {
439
438
  const servers = Array.isArray(serverNames) ? serverNames : [serverNames];
440
439
  if (tools.length === 0) {
441
- return `No tools found from MCP server(s): ${servers.join(', ')}.`;
440
+ return JSON.stringify({
441
+ listing_mode: true,
442
+ servers,
443
+ total_tools: 0,
444
+ tools_by_server: {},
445
+ hint: 'No tools found from the specified MCP server(s).',
446
+ }, null, 2);
442
447
  }
443
- const toolsByServer = new Map();
448
+ const toolsByServer = {};
444
449
  for (const tool of tools) {
445
450
  const server = extractMcpServerName(tool.name) ?? 'unknown';
446
- const existing = toolsByServer.get(server) ?? [];
447
- existing.push(tool);
448
- toolsByServer.set(server, existing);
449
- }
450
- let response = servers.length === 1
451
- ? `## Tools from MCP server: ${servers[0]}\n\n`
452
- : `## Tools from MCP servers: ${servers.join(', ')}\n\n`;
453
- response += `Found ${tools.length} tool(s) (preview only - not yet loaded):\n\n`;
454
- for (const [server, serverTools] of toolsByServer) {
455
- if (servers.length > 1) {
456
- response += `### ${server}\n\n`;
457
- }
458
- for (const tool of serverTools) {
459
- const baseName = getBaseToolName(tool.name);
460
- response += `- **${baseName}**`;
461
- if (tool.description) {
462
- const shortDesc = tool.description.length > 80
463
- ? tool.description.substring(0, 77) + '...'
464
- : tool.description;
465
- response += `: ${shortDesc}`;
466
- }
467
- response += '\n';
468
- }
469
- if (servers.length > 1) {
470
- response += '\n';
451
+ if (!(server in toolsByServer)) {
452
+ toolsByServer[server] = [];
471
453
  }
454
+ toolsByServer[server].push({
455
+ name: getBaseToolName(tool.name),
456
+ description: tool.description.length > 100
457
+ ? tool.description.substring(0, 97) + '...'
458
+ : tool.description,
459
+ });
472
460
  }
473
- response += `\n_To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it._`;
474
- return response;
461
+ const output = {
462
+ listing_mode: true,
463
+ servers,
464
+ total_tools: tools.length,
465
+ tools_by_server: toolsByServer,
466
+ hint: `To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it.`,
467
+ };
468
+ return JSON.stringify(output, null, 2);
475
469
  }
476
470
  /**
477
471
  * Creates a Tool Search tool for discovering tools from a large registry.
@@ -1 +1 @@
1
- {"version":3,"file":"ToolSearch.mjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport { config } from 'dotenv';\nimport fetch, { RequestInit } from 'node-fetch';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getEnvironmentVariable } from '@langchain/core/utils/env';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { getCodeBaseURL } from './CodeExecutor';\nimport { EnvVar, Constants } from '@/common';\n\nconfig();\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 200;\n\n/** Maximum allowed regex nesting depth */\nconst MAX_REGEX_COMPLEXITY = 5;\n\n/** Default search timeout in milliseconds */\nconst SEARCH_TIMEOUT = 5000;\n\n/** Zod schema type for tool search parameters */\ntype ToolSearchSchema = z.ZodObject<{\n query: z.ZodDefault<z.ZodOptional<z.ZodString>>;\n fields: z.ZodDefault<\n z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>\n >;\n max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;\n mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\n}>;\n\n/**\n * Creates the Zod schema with dynamic query description based on mode.\n * @param mode - The search mode determining query interpretation\n * @returns Zod schema for tool search parameters\n */\nfunction createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {\n const queryDescription =\n mode === 'local'\n ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .describe(queryDescription),\n fields: z\n .array(z.enum(['name', 'description', 'parameters']))\n .optional()\n .default(['name', 'description'])\n .describe('Which fields to search. Default: name and description'),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .default(10)\n .describe('Maximum number of matching tools to return'),\n mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\n}\n\n/**\n * Escapes special regex characters in a string to use as a literal pattern.\n * @param pattern - The string to escape\n * @returns The escaped string safe for use in a RegExp\n */\nfunction escapeRegexSpecialChars(pattern: string): string {\n return pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Counts the maximum nesting depth of groups in a regex pattern.\n * @param pattern - The regex pattern to analyze\n * @returns The maximum nesting depth\n */\nfunction countNestedGroups(pattern: string): number {\n let maxDepth = 0;\n let currentDepth = 0;\n\n for (let i = 0; i < pattern.length; i++) {\n if (pattern[i] === '(' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth++;\n maxDepth = Math.max(maxDepth, currentDepth);\n } else if (pattern[i] === ')' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth = Math.max(0, currentDepth - 1);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Detects nested quantifiers that can cause catastrophic backtracking.\n * Patterns like (a+)+, (a*)*, (a+)*, etc.\n * @param pattern - The regex pattern to check\n * @returns True if nested quantifiers are detected\n */\nfunction hasNestedQuantifiers(pattern: string): boolean {\n const nestedQuantifierPattern = /\\([^)]*[+*][^)]*\\)[+*?]/;\n return nestedQuantifierPattern.test(pattern);\n}\n\n/**\n * Checks if a regex pattern contains potentially dangerous constructs.\n * @param pattern - The regex pattern to validate\n * @returns True if the pattern is dangerous\n */\nfunction isDangerousPattern(pattern: string): boolean {\n if (hasNestedQuantifiers(pattern)) {\n return true;\n }\n\n if (countNestedGroups(pattern) > MAX_REGEX_COMPLEXITY) {\n return true;\n }\n\n const dangerousPatterns = [\n /\\.\\{1000,\\}/, // Excessive wildcards\n /\\(\\?=\\.\\{100,\\}\\)/, // Runaway lookaheads\n /\\([^)]*\\|\\s*\\){20,}/, // Excessive alternation (rough check)\n /\\(\\.\\*\\)\\+/, // (.*)+\n /\\(\\.\\+\\)\\+/, // (.+)+\n /\\(\\.\\*\\)\\*/, // (.*)*\n /\\(\\.\\+\\)\\*/, // (.+)*\n ];\n\n for (const dangerous of dangerousPatterns) {\n if (dangerous.test(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a regex pattern for safe execution.\n * If the pattern is dangerous, it will be escaped to a literal string search.\n * @param pattern - The regex pattern to sanitize\n * @returns Object containing the safe pattern and whether it was escaped\n */\nfunction sanitizeRegex(pattern: string): { safe: string; wasEscaped: boolean } {\n if (isDangerousPattern(pattern)) {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n\n try {\n new RegExp(pattern);\n return { safe: pattern, wasEscaped: false };\n } catch {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n}\n\n/**\n * Simplifies tool parameters for search purposes.\n * Extracts only the essential structure needed for parameter name searching.\n * @param parameters - The tool's JSON schema parameters\n * @returns Simplified parameters object\n */\nfunction simplifyParametersForSearch(\n parameters?: t.JsonSchemaType\n): t.JsonSchemaType | undefined {\n if (!parameters) {\n return undefined;\n }\n\n if (parameters.properties) {\n return {\n type: parameters.type,\n properties: Object.fromEntries(\n Object.entries(parameters.properties).map(([key, value]) => [\n key,\n { type: (value as t.JsonSchemaType).type },\n ])\n ),\n } as t.JsonSchemaType;\n }\n\n return { type: parameters.type };\n}\n\n/**\n * Performs safe local substring search without regex.\n * Uses case-insensitive String.includes() for complete safety against ReDoS.\n * @param tools - Array of tool metadata to search\n * @param query - The search term (treated as literal substring)\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n const lowerQuery = query.toLowerCase();\n const results: t.ToolSearchResult[] = [];\n\n for (const tool of tools) {\n let bestScore = 0;\n let matchedField = '';\n let snippet = '';\n\n if (fields.includes('name')) {\n const lowerName = tool.name.toLowerCase();\n if (lowerName.includes(lowerQuery)) {\n const isExactMatch = lowerName === lowerQuery;\n const startsWithQuery = lowerName.startsWith(lowerQuery);\n bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;\n matchedField = 'name';\n snippet = tool.name;\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const lowerDesc = tool.description.toLowerCase();\n if (lowerDesc.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.7;\n matchedField = 'description';\n snippet = tool.description.substring(0, 100);\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties)\n .join(' ')\n .toLowerCase();\n if (paramNames.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.55;\n matchedField = 'parameters';\n snippet = Object.keys(tool.parameters.properties).join(' ');\n }\n }\n\n if (bestScore > 0) {\n results.push({\n tool_name: tool.name,\n match_score: bestScore,\n matched_field: matchedField,\n snippet,\n });\n }\n }\n\n results.sort((a, b) => b.match_score - a.match_score);\n const topResults = results.slice(0, maxResults);\n\n return {\n tool_references: topResults,\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n}\n\n/**\n * Generates the JavaScript search script to be executed in the sandbox.\n * Uses plain JavaScript for maximum compatibility with the Code API.\n * @param deferredTools - Array of tool metadata to search through\n * @param fields - Which fields to search\n * @param maxResults - Maximum number of results to return\n * @param sanitizedPattern - The sanitized regex pattern\n * @returns The JavaScript code string\n */\nfunction generateSearchScript(\n deferredTools: t.ToolMetadata[],\n fields: string[],\n maxResults: number,\n sanitizedPattern: string\n): string {\n const lines = [\n '// Tool definitions (injected)',\n 'var tools = ' + JSON.stringify(deferredTools) + ';',\n 'var searchFields = ' + JSON.stringify(fields) + ';',\n 'var maxResults = ' + maxResults + ';',\n 'var pattern = ' + JSON.stringify(sanitizedPattern) + ';',\n '',\n '// Compile regex (pattern is sanitized client-side)',\n 'var regex;',\n 'try {',\n ' regex = new RegExp(pattern, \\'i\\');',\n '} catch (e) {',\n ' regex = new RegExp(pattern.replace(/[.*+?^${}()[\\\\]\\\\\\\\|]/g, \"\\\\\\\\$&\"), \"i\");',\n '}',\n '',\n '// Search logic',\n 'var results = [];',\n '',\n 'for (var j = 0; j < tools.length; j++) {',\n ' var tool = tools[j];',\n ' var bestScore = 0;',\n ' var matchedField = \\'\\';',\n ' var snippet = \\'\\';',\n '',\n ' // Search name (highest priority)',\n ' if (searchFields.indexOf(\\'name\\') >= 0 && regex.test(tool.name)) {',\n ' bestScore = 0.95;',\n ' matchedField = \\'name\\';',\n ' snippet = tool.name;',\n ' }',\n '',\n ' // Search description (medium priority)',\n ' if (searchFields.indexOf(\\'description\\') >= 0 && tool.description && regex.test(tool.description)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.75;',\n ' matchedField = \\'description\\';',\n ' snippet = tool.description.substring(0, 100);',\n ' }',\n ' }',\n '',\n ' // Search parameter names (lower priority)',\n ' if (searchFields.indexOf(\\'parameters\\') >= 0 && tool.parameters && tool.parameters.properties) {',\n ' var paramNames = Object.keys(tool.parameters.properties).join(\\' \\');',\n ' if (regex.test(paramNames)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.60;',\n ' matchedField = \\'parameters\\';',\n ' snippet = paramNames;',\n ' }',\n ' }',\n ' }',\n '',\n ' if (bestScore > 0) {',\n ' results.push({',\n ' tool_name: tool.name,',\n ' match_score: bestScore,',\n ' matched_field: matchedField,',\n ' snippet: snippet',\n ' });',\n ' }',\n '}',\n '',\n '// Sort by score (descending) and limit results',\n 'results.sort(function(a, b) { return b.match_score - a.match_score; });',\n 'var topResults = results.slice(0, maxResults);',\n '',\n '// Output as JSON',\n 'console.log(JSON.stringify({',\n ' tool_references: topResults.map(function(r) {',\n ' return {',\n ' tool_name: r.tool_name,',\n ' match_score: r.match_score,',\n ' matched_field: r.matched_field,',\n ' snippet: r.snippet',\n ' };',\n ' }),',\n ' total_tools_searched: tools.length,',\n ' pattern_used: pattern',\n '}));',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Parses the search results from stdout JSON.\n * @param stdout - The stdout string containing JSON results\n * @returns Parsed search response\n */\nfunction parseSearchResults(stdout: string): t.ToolSearchResponse {\n const jsonMatch = stdout.trim();\n const parsed = JSON.parse(jsonMatch) as t.ToolSearchResponse;\n return parsed;\n}\n\n/**\n * Formats search results into a human-readable string.\n * @param searchResponse - The parsed search response\n * @returns Formatted string for LLM consumption\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n if (tool_references.length === 0) {\n return `No tools matched the pattern \"${pattern_used}\".\\nTotal tools searched: ${total_tools_searched}`;\n }\n\n let response = `Found ${tool_references.length} matching tools:\\n\\n`;\n\n for (const ref of tool_references) {\n response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\\n`;\n response += ` Matched in: ${ref.matched_field}\\n`;\n response += ` Snippet: ${ref.snippet}\\n\\n`;\n }\n\n response += `Total tools searched: ${total_tools_searched}\\n`;\n response += `Pattern used: ${pattern_used}`;\n\n return response;\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Formats a server listing response when listing all tools from MCP server(s).\n * Provides a cohesive view of all tools grouped by server.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns Formatted string showing all tools from the server(s)\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return `No tools found from MCP server(s): ${servers.join(', ')}.`;\n }\n\n const toolsByServer = new Map<string, t.ToolMetadata[]>();\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n const existing = toolsByServer.get(server) ?? [];\n existing.push(tool);\n toolsByServer.set(server, existing);\n }\n\n let response =\n servers.length === 1\n ? `## Tools from MCP server: ${servers[0]}\\n\\n`\n : `## Tools from MCP servers: ${servers.join(', ')}\\n\\n`;\n\n response += `Found ${tools.length} tool(s) (preview only - not yet loaded):\\n\\n`;\n\n for (const [server, serverTools] of toolsByServer) {\n if (servers.length > 1) {\n response += `### ${server}\\n\\n`;\n }\n for (const tool of serverTools) {\n const baseName = getBaseToolName(tool.name);\n response += `- **${baseName}**`;\n if (tool.description) {\n const shortDesc =\n tool.description.length > 80\n ? tool.description.substring(0, 77) + '...'\n : tool.description;\n response += `: ${shortDesc}`;\n }\n response += '\\n';\n }\n if (servers.length > 1) {\n response += '\\n';\n }\n }\n\n response += `\\n_To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it._`;\n\n return response;\n}\n\n/**\n * Creates a Tool Search tool for discovering tools from a large registry.\n *\n * This tool enables AI agents to dynamically discover tools from a large library\n * without loading all tool definitions into the LLM context window. The agent\n * can search for relevant tools on-demand.\n *\n * **Modes:**\n * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.\n * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.\n *\n * The tool registry can be provided either:\n * 1. At initialization time via params.toolRegistry\n * 2. At runtime via config.configurable.toolRegistry when invoking\n *\n * @param params - Configuration parameters for the tool (toolRegistry is optional)\n * @returns A LangChain DynamicStructuredTool for tool searching\n *\n * @example\n * // Option 1: Code interpreter mode (regex via sandbox)\n * const tool = createToolSearch({ apiKey, toolRegistry });\n * await tool.invoke({ query: 'expense.*report' });\n *\n * @example\n * // Option 2: Local mode (safe substring search, no API key needed)\n * const tool = createToolSearch({ mode: 'local', toolRegistry });\n * await tool.invoke({ query: 'expense' });\n */\nfunction createToolSearch(\n initParams: t.ToolSearchParams = {}\n): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {\n const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';\n const defaultOnlyDeferred = initParams.onlyDeferred ?? true;\n const schema = createToolSearchSchema(mode);\n\n const apiKey: string =\n mode === 'code_interpreter'\n ? ((initParams[EnvVar.CODE_API_KEY] as string | undefined) ??\n initParams.apiKey ??\n getEnvironmentVariable(EnvVar.CODE_API_KEY) ??\n '')\n : '';\n\n if (mode === 'code_interpreter' && !apiKey) {\n throw new Error(\n 'No API key provided for tool search in code_interpreter mode. Use mode: \"local\" to search without an API key.'\n );\n }\n\n const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();\n const EXEC_ENDPOINT = `${baseEndpoint}/exec`;\n\n const availableServers = getAvailableMcpServers(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const serverListText =\n availableServers.length > 0\n ? `\\n- Available MCP servers: ${availableServers.join(', ')}`\n : '';\n\n const mcpInstructions = `\n\nMCP Server Tools:\n- Tools from MCP servers follow the naming convention: toolName${Constants.MCP_DELIMITER}serverName\n- Example: \"get_weather${Constants.MCP_DELIMITER}weather-api\" is the \"get_weather\" tool from the \"weather-api\" server\n- Use mcp_server parameter to filter by server (e.g., mcp_server: \"weather-api\")\n- If mcp_server is provided without a query, lists ALL tools from that server${serverListText}`;\n\n const description =\n mode === 'local'\n ? `\nSearches through available tools to find ones matching your search term.\n\nUsage:\n- Provide a search term to find in tool names and descriptions.\n- Uses case-insensitive substring matching (fast and safe).\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.\n${mcpInstructions}\n`.trim()\n : `\nSearches through available tools to find ones matching your query pattern.\n\nUsage:\n- Provide a regex pattern to search tool names and descriptions.\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.9+) indicate name matches, medium scores (0.7+) indicate description matches.\n${mcpInstructions}\n`.trim();\n\n return tool<typeof schema>(\n async (params, config) => {\n const {\n query,\n fields = ['name', 'description'],\n max_results = 10,\n mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\n\n if (toolRegistry == null) {\n return [\n 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n error: 'No tool registry provided',\n },\n },\n ];\n }\n\n const toolsArray: t.LCTool[] = Array.from(toolRegistry.values());\n const deferredTools: t.ToolMetadata[] = toolsArray\n .filter((lcTool) => {\n if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return true;\n })\n .map((lcTool) => ({\n name: lcTool.name,\n description: lcTool.description ?? '',\n parameters: simplifyParametersForSearch(lcTool.parameters),\n }));\n\n if (deferredTools.length === 0) {\n const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\n },\n ];\n }\n\n if (mode === 'local') {\n const searchResponse = performLocalSearch(\n deferredTools,\n query,\n fields,\n max_results\n );\n const formattedOutput = formatSearchResults(searchResponse);\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\n },\n },\n ];\n }\n\n const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);\n let warningMessage = '';\n if (wasEscaped) {\n warningMessage =\n 'Note: The provided pattern was converted to a literal search for safety.\\n\\n';\n }\n\n const searchScript = generateSearchScript(\n deferredTools,\n fields,\n max_results,\n sanitizedPattern\n );\n\n const postData = {\n lang: 'js',\n code: searchScript,\n timeout: SEARCH_TIMEOUT,\n };\n\n try {\n const fetchOptions: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'LibreChat/1.0',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(postData),\n };\n\n if (process.env.PROXY != null && process.env.PROXY !== '') {\n fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);\n }\n\n const response = await fetch(EXEC_ENDPOINT, fetchOptions);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const result: t.ExecuteResult = await response.json();\n\n if (result.stderr && result.stderr.trim()) {\n // eslint-disable-next-line no-console\n console.warn('[ToolSearch] stderr:', result.stderr);\n }\n\n if (!result.stdout || !result.stdout.trim()) {\n return [\n `${warningMessage}No tools matched the pattern \"${sanitizedPattern}\".\\nTotal tools searched: ${deferredTools.length}`,\n {\n tool_references: [],\n metadata: {\n total_searched: deferredTools.length,\n pattern: sanitizedPattern,\n },\n },\n ];\n }\n\n const searchResponse = parseSearchResults(result.stdout);\n const formattedOutput = `${warningMessage}${formatSearchResults(searchResponse)}`;\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[ToolSearch] Error:', error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return [\n `Tool search failed: ${errorMessage}\\n\\nSuggestion: Try a simpler search pattern or search for specific tool names.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: sanitizedPattern,\n error: errorMessage,\n },\n },\n ];\n }\n },\n {\n name: Constants.TOOL_SEARCH,\n description,\n schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport {\n createToolSearch,\n performLocalSearch,\n extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolSearch.mjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport { config } from 'dotenv';\nimport fetch, { RequestInit } from 'node-fetch';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getEnvironmentVariable } from '@langchain/core/utils/env';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { getCodeBaseURL } from './CodeExecutor';\nimport { EnvVar, Constants } from '@/common';\n\nconfig();\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 200;\n\n/** Maximum allowed regex nesting depth */\nconst MAX_REGEX_COMPLEXITY = 5;\n\n/** Default search timeout in milliseconds */\nconst SEARCH_TIMEOUT = 5000;\n\n/** Zod schema type for tool search parameters */\ntype ToolSearchSchema = z.ZodObject<{\n query: z.ZodDefault<z.ZodOptional<z.ZodString>>;\n fields: z.ZodDefault<\n z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>\n >;\n max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;\n mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\n}>;\n\n/**\n * Creates the Zod schema with dynamic query description based on mode.\n * @param mode - The search mode determining query interpretation\n * @returns Zod schema for tool search parameters\n */\nfunction createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {\n const queryDescription =\n mode === 'local'\n ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .describe(queryDescription),\n fields: z\n .array(z.enum(['name', 'description', 'parameters']))\n .optional()\n .default(['name', 'description'])\n .describe('Which fields to search. Default: name and description'),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .default(10)\n .describe('Maximum number of matching tools to return'),\n mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\n}\n\n/**\n * Escapes special regex characters in a string to use as a literal pattern.\n * @param pattern - The string to escape\n * @returns The escaped string safe for use in a RegExp\n */\nfunction escapeRegexSpecialChars(pattern: string): string {\n return pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Counts the maximum nesting depth of groups in a regex pattern.\n * @param pattern - The regex pattern to analyze\n * @returns The maximum nesting depth\n */\nfunction countNestedGroups(pattern: string): number {\n let maxDepth = 0;\n let currentDepth = 0;\n\n for (let i = 0; i < pattern.length; i++) {\n if (pattern[i] === '(' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth++;\n maxDepth = Math.max(maxDepth, currentDepth);\n } else if (pattern[i] === ')' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth = Math.max(0, currentDepth - 1);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Detects nested quantifiers that can cause catastrophic backtracking.\n * Patterns like (a+)+, (a*)*, (a+)*, etc.\n * @param pattern - The regex pattern to check\n * @returns True if nested quantifiers are detected\n */\nfunction hasNestedQuantifiers(pattern: string): boolean {\n const nestedQuantifierPattern = /\\([^)]*[+*][^)]*\\)[+*?]/;\n return nestedQuantifierPattern.test(pattern);\n}\n\n/**\n * Checks if a regex pattern contains potentially dangerous constructs.\n * @param pattern - The regex pattern to validate\n * @returns True if the pattern is dangerous\n */\nfunction isDangerousPattern(pattern: string): boolean {\n if (hasNestedQuantifiers(pattern)) {\n return true;\n }\n\n if (countNestedGroups(pattern) > MAX_REGEX_COMPLEXITY) {\n return true;\n }\n\n const dangerousPatterns = [\n /\\.\\{1000,\\}/, // Excessive wildcards\n /\\(\\?=\\.\\{100,\\}\\)/, // Runaway lookaheads\n /\\([^)]*\\|\\s*\\){20,}/, // Excessive alternation (rough check)\n /\\(\\.\\*\\)\\+/, // (.*)+\n /\\(\\.\\+\\)\\+/, // (.+)+\n /\\(\\.\\*\\)\\*/, // (.*)*\n /\\(\\.\\+\\)\\*/, // (.+)*\n ];\n\n for (const dangerous of dangerousPatterns) {\n if (dangerous.test(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a regex pattern for safe execution.\n * If the pattern is dangerous, it will be escaped to a literal string search.\n * @param pattern - The regex pattern to sanitize\n * @returns Object containing the safe pattern and whether it was escaped\n */\nfunction sanitizeRegex(pattern: string): { safe: string; wasEscaped: boolean } {\n if (isDangerousPattern(pattern)) {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n\n try {\n new RegExp(pattern);\n return { safe: pattern, wasEscaped: false };\n } catch {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n}\n\n/**\n * Simplifies tool parameters for search purposes.\n * Extracts only the essential structure needed for parameter name searching.\n * @param parameters - The tool's JSON schema parameters\n * @returns Simplified parameters object\n */\nfunction simplifyParametersForSearch(\n parameters?: t.JsonSchemaType\n): t.JsonSchemaType | undefined {\n if (!parameters) {\n return undefined;\n }\n\n if (parameters.properties) {\n return {\n type: parameters.type,\n properties: Object.fromEntries(\n Object.entries(parameters.properties).map(([key, value]) => [\n key,\n { type: (value as t.JsonSchemaType).type },\n ])\n ),\n } as t.JsonSchemaType;\n }\n\n return { type: parameters.type };\n}\n\n/**\n * Performs safe local substring search without regex.\n * Uses case-insensitive String.includes() for complete safety against ReDoS.\n * @param tools - Array of tool metadata to search\n * @param query - The search term (treated as literal substring)\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n const lowerQuery = query.toLowerCase();\n const results: t.ToolSearchResult[] = [];\n\n for (const tool of tools) {\n let bestScore = 0;\n let matchedField = '';\n let snippet = '';\n\n if (fields.includes('name')) {\n const lowerName = tool.name.toLowerCase();\n if (lowerName.includes(lowerQuery)) {\n const isExactMatch = lowerName === lowerQuery;\n const startsWithQuery = lowerName.startsWith(lowerQuery);\n bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;\n matchedField = 'name';\n snippet = tool.name;\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const lowerDesc = tool.description.toLowerCase();\n if (lowerDesc.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.7;\n matchedField = 'description';\n snippet = tool.description.substring(0, 100);\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties)\n .join(' ')\n .toLowerCase();\n if (paramNames.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.55;\n matchedField = 'parameters';\n snippet = Object.keys(tool.parameters.properties).join(' ');\n }\n }\n\n if (bestScore > 0) {\n results.push({\n tool_name: tool.name,\n match_score: bestScore,\n matched_field: matchedField,\n snippet,\n });\n }\n }\n\n results.sort((a, b) => b.match_score - a.match_score);\n const topResults = results.slice(0, maxResults);\n\n return {\n tool_references: topResults,\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n}\n\n/**\n * Generates the JavaScript search script to be executed in the sandbox.\n * Uses plain JavaScript for maximum compatibility with the Code API.\n * @param deferredTools - Array of tool metadata to search through\n * @param fields - Which fields to search\n * @param maxResults - Maximum number of results to return\n * @param sanitizedPattern - The sanitized regex pattern\n * @returns The JavaScript code string\n */\nfunction generateSearchScript(\n deferredTools: t.ToolMetadata[],\n fields: string[],\n maxResults: number,\n sanitizedPattern: string\n): string {\n const lines = [\n '// Tool definitions (injected)',\n 'var tools = ' + JSON.stringify(deferredTools) + ';',\n 'var searchFields = ' + JSON.stringify(fields) + ';',\n 'var maxResults = ' + maxResults + ';',\n 'var pattern = ' + JSON.stringify(sanitizedPattern) + ';',\n '',\n '// Compile regex (pattern is sanitized client-side)',\n 'var regex;',\n 'try {',\n ' regex = new RegExp(pattern, \\'i\\');',\n '} catch (e) {',\n ' regex = new RegExp(pattern.replace(/[.*+?^${}()[\\\\]\\\\\\\\|]/g, \"\\\\\\\\$&\"), \"i\");',\n '}',\n '',\n '// Search logic',\n 'var results = [];',\n '',\n 'for (var j = 0; j < tools.length; j++) {',\n ' var tool = tools[j];',\n ' var bestScore = 0;',\n ' var matchedField = \\'\\';',\n ' var snippet = \\'\\';',\n '',\n ' // Search name (highest priority)',\n ' if (searchFields.indexOf(\\'name\\') >= 0 && regex.test(tool.name)) {',\n ' bestScore = 0.95;',\n ' matchedField = \\'name\\';',\n ' snippet = tool.name;',\n ' }',\n '',\n ' // Search description (medium priority)',\n ' if (searchFields.indexOf(\\'description\\') >= 0 && tool.description && regex.test(tool.description)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.75;',\n ' matchedField = \\'description\\';',\n ' snippet = tool.description.substring(0, 100);',\n ' }',\n ' }',\n '',\n ' // Search parameter names (lower priority)',\n ' if (searchFields.indexOf(\\'parameters\\') >= 0 && tool.parameters && tool.parameters.properties) {',\n ' var paramNames = Object.keys(tool.parameters.properties).join(\\' \\');',\n ' if (regex.test(paramNames)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.60;',\n ' matchedField = \\'parameters\\';',\n ' snippet = paramNames;',\n ' }',\n ' }',\n ' }',\n '',\n ' if (bestScore > 0) {',\n ' results.push({',\n ' tool_name: tool.name,',\n ' match_score: bestScore,',\n ' matched_field: matchedField,',\n ' snippet: snippet',\n ' });',\n ' }',\n '}',\n '',\n '// Sort by score (descending) and limit results',\n 'results.sort(function(a, b) { return b.match_score - a.match_score; });',\n 'var topResults = results.slice(0, maxResults);',\n '',\n '// Output as JSON',\n 'console.log(JSON.stringify({',\n ' tool_references: topResults.map(function(r) {',\n ' return {',\n ' tool_name: r.tool_name,',\n ' match_score: r.match_score,',\n ' matched_field: r.matched_field,',\n ' snippet: r.snippet',\n ' };',\n ' }),',\n ' total_tools_searched: tools.length,',\n ' pattern_used: pattern',\n '}));',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Parses the search results from stdout JSON.\n * @param stdout - The stdout string containing JSON results\n * @returns Parsed search response\n */\nfunction parseSearchResults(stdout: string): t.ToolSearchResponse {\n const jsonMatch = stdout.trim();\n const parsed = JSON.parse(jsonMatch) as t.ToolSearchResponse;\n return parsed;\n}\n\n/**\n * Formats search results as structured JSON for efficient parsing.\n * @param searchResponse - The parsed search response\n * @returns JSON string with search results\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n const output = {\n found: tool_references.length,\n tools: tool_references.map((ref) => ({\n name: ref.tool_name,\n score: Number(ref.match_score.toFixed(2)),\n matched_in: ref.matched_field,\n snippet: ref.snippet,\n })),\n total_searched: total_tools_searched,\n query: pattern_used,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Formats a server listing response as structured JSON.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns JSON string showing all tools grouped by server\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return JSON.stringify(\n {\n listing_mode: true,\n servers,\n total_tools: 0,\n tools_by_server: {},\n hint: 'No tools found from the specified MCP server(s).',\n },\n null,\n 2\n );\n }\n\n const toolsByServer: Record<\n string,\n Array<{ name: string; description: string }>\n > = {};\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n if (!(server in toolsByServer)) {\n toolsByServer[server] = [];\n }\n toolsByServer[server].push({\n name: getBaseToolName(tool.name),\n description:\n tool.description.length > 100\n ? tool.description.substring(0, 97) + '...'\n : tool.description,\n });\n }\n\n const output = {\n listing_mode: true,\n servers,\n total_tools: tools.length,\n tools_by_server: toolsByServer,\n hint: `To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it.`,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Creates a Tool Search tool for discovering tools from a large registry.\n *\n * This tool enables AI agents to dynamically discover tools from a large library\n * without loading all tool definitions into the LLM context window. The agent\n * can search for relevant tools on-demand.\n *\n * **Modes:**\n * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.\n * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.\n *\n * The tool registry can be provided either:\n * 1. At initialization time via params.toolRegistry\n * 2. At runtime via config.configurable.toolRegistry when invoking\n *\n * @param params - Configuration parameters for the tool (toolRegistry is optional)\n * @returns A LangChain DynamicStructuredTool for tool searching\n *\n * @example\n * // Option 1: Code interpreter mode (regex via sandbox)\n * const tool = createToolSearch({ apiKey, toolRegistry });\n * await tool.invoke({ query: 'expense.*report' });\n *\n * @example\n * // Option 2: Local mode (safe substring search, no API key needed)\n * const tool = createToolSearch({ mode: 'local', toolRegistry });\n * await tool.invoke({ query: 'expense' });\n */\nfunction createToolSearch(\n initParams: t.ToolSearchParams = {}\n): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {\n const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';\n const defaultOnlyDeferred = initParams.onlyDeferred ?? true;\n const schema = createToolSearchSchema(mode);\n\n const apiKey: string =\n mode === 'code_interpreter'\n ? ((initParams[EnvVar.CODE_API_KEY] as string | undefined) ??\n initParams.apiKey ??\n getEnvironmentVariable(EnvVar.CODE_API_KEY) ??\n '')\n : '';\n\n if (mode === 'code_interpreter' && !apiKey) {\n throw new Error(\n 'No API key provided for tool search in code_interpreter mode. Use mode: \"local\" to search without an API key.'\n );\n }\n\n const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();\n const EXEC_ENDPOINT = `${baseEndpoint}/exec`;\n\n const availableServers = getAvailableMcpServers(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const serverListText =\n availableServers.length > 0\n ? `\\n- Available MCP servers: ${availableServers.join(', ')}`\n : '';\n\n const mcpInstructions = `\n\nMCP Server Tools:\n- Tools from MCP servers follow the naming convention: toolName${Constants.MCP_DELIMITER}serverName\n- Example: \"get_weather${Constants.MCP_DELIMITER}weather-api\" is the \"get_weather\" tool from the \"weather-api\" server\n- Use mcp_server parameter to filter by server (e.g., mcp_server: \"weather-api\")\n- If mcp_server is provided without a query, lists ALL tools from that server${serverListText}`;\n\n const description =\n mode === 'local'\n ? `\nSearches through available tools to find ones matching your search term.\n\nUsage:\n- Provide a search term to find in tool names and descriptions.\n- Uses case-insensitive substring matching (fast and safe).\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.\n${mcpInstructions}\n`.trim()\n : `\nSearches through available tools to find ones matching your query pattern.\n\nUsage:\n- Provide a regex pattern to search tool names and descriptions.\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.9+) indicate name matches, medium scores (0.7+) indicate description matches.\n${mcpInstructions}\n`.trim();\n\n return tool<typeof schema>(\n async (params, config) => {\n const {\n query,\n fields = ['name', 'description'],\n max_results = 10,\n mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\n\n if (toolRegistry == null) {\n return [\n 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n error: 'No tool registry provided',\n },\n },\n ];\n }\n\n const toolsArray: t.LCTool[] = Array.from(toolRegistry.values());\n const deferredTools: t.ToolMetadata[] = toolsArray\n .filter((lcTool) => {\n if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return true;\n })\n .map((lcTool) => ({\n name: lcTool.name,\n description: lcTool.description ?? '',\n parameters: simplifyParametersForSearch(lcTool.parameters),\n }));\n\n if (deferredTools.length === 0) {\n const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\n },\n ];\n }\n\n if (mode === 'local') {\n const searchResponse = performLocalSearch(\n deferredTools,\n query,\n fields,\n max_results\n );\n const formattedOutput = formatSearchResults(searchResponse);\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\n },\n },\n ];\n }\n\n const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);\n let warningMessage = '';\n if (wasEscaped) {\n warningMessage =\n 'Note: The provided pattern was converted to a literal search for safety.\\n\\n';\n }\n\n const searchScript = generateSearchScript(\n deferredTools,\n fields,\n max_results,\n sanitizedPattern\n );\n\n const postData = {\n lang: 'js',\n code: searchScript,\n timeout: SEARCH_TIMEOUT,\n };\n\n try {\n const fetchOptions: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'LibreChat/1.0',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(postData),\n };\n\n if (process.env.PROXY != null && process.env.PROXY !== '') {\n fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);\n }\n\n const response = await fetch(EXEC_ENDPOINT, fetchOptions);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const result: t.ExecuteResult = await response.json();\n\n if (result.stderr && result.stderr.trim()) {\n // eslint-disable-next-line no-console\n console.warn('[ToolSearch] stderr:', result.stderr);\n }\n\n if (!result.stdout || !result.stdout.trim()) {\n return [\n `${warningMessage}No tools matched the pattern \"${sanitizedPattern}\".\\nTotal tools searched: ${deferredTools.length}`,\n {\n tool_references: [],\n metadata: {\n total_searched: deferredTools.length,\n pattern: sanitizedPattern,\n },\n },\n ];\n }\n\n const searchResponse = parseSearchResults(result.stdout);\n const formattedOutput = `${warningMessage}${formatSearchResults(searchResponse)}`;\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[ToolSearch] Error:', error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return [\n `Tool search failed: ${errorMessage}\\n\\nSuggestion: Try a simpler search pattern or search for specific tool names.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: sanitizedPattern,\n error: errorMessage,\n },\n },\n ];\n }\n },\n {\n name: Constants.TOOL_SEARCH,\n description,\n schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport {\n createToolSearch,\n performLocalSearch,\n extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":[],"mappings":"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"}
@@ -100,12 +100,11 @@ declare function performLocalSearch(tools: t.ToolMetadata[], query: string, fiel
100
100
  */
101
101
  declare function getBaseToolName(toolName: string): string;
102
102
  /**
103
- * Formats a server listing response when listing all tools from MCP server(s).
104
- * Provides a cohesive view of all tools grouped by server.
103
+ * Formats a server listing response as structured JSON.
105
104
  * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
106
105
  * @param tools - Array of tool metadata from the server(s)
107
106
  * @param serverNames - The MCP server name(s)
108
- * @returns Formatted string showing all tools from the server(s)
107
+ * @returns JSON string showing all tools grouped by server
109
108
  */
110
109
  declare function formatServerListing(tools: t.ToolMetadata[], serverNames: string | string[]): string;
111
110
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.0.69",
3
+ "version": "3.0.70",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -465,30 +465,27 @@ function parseSearchResults(stdout: string): t.ToolSearchResponse {
465
465
  }
466
466
 
467
467
  /**
468
- * Formats search results into a human-readable string.
468
+ * Formats search results as structured JSON for efficient parsing.
469
469
  * @param searchResponse - The parsed search response
470
- * @returns Formatted string for LLM consumption
470
+ * @returns JSON string with search results
471
471
  */
472
472
  function formatSearchResults(searchResponse: t.ToolSearchResponse): string {
473
473
  const { tool_references, total_tools_searched, pattern_used } =
474
474
  searchResponse;
475
475
 
476
- if (tool_references.length === 0) {
477
- return `No tools matched the pattern "${pattern_used}".\nTotal tools searched: ${total_tools_searched}`;
478
- }
479
-
480
- let response = `Found ${tool_references.length} matching tools:\n\n`;
481
-
482
- for (const ref of tool_references) {
483
- response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\n`;
484
- response += ` Matched in: ${ref.matched_field}\n`;
485
- response += ` Snippet: ${ref.snippet}\n\n`;
486
- }
487
-
488
- response += `Total tools searched: ${total_tools_searched}\n`;
489
- response += `Pattern used: ${pattern_used}`;
476
+ const output = {
477
+ found: tool_references.length,
478
+ tools: tool_references.map((ref) => ({
479
+ name: ref.tool_name,
480
+ score: Number(ref.match_score.toFixed(2)),
481
+ matched_in: ref.matched_field,
482
+ snippet: ref.snippet,
483
+ })),
484
+ total_searched: total_tools_searched,
485
+ query: pattern_used,
486
+ };
490
487
 
491
- return response;
488
+ return JSON.stringify(output, null, 2);
492
489
  }
493
490
 
494
491
  /**
@@ -505,12 +502,11 @@ function getBaseToolName(toolName: string): string {
505
502
  }
506
503
 
507
504
  /**
508
- * Formats a server listing response when listing all tools from MCP server(s).
509
- * Provides a cohesive view of all tools grouped by server.
505
+ * Formats a server listing response as structured JSON.
510
506
  * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
511
507
  * @param tools - Array of tool metadata from the server(s)
512
508
  * @param serverNames - The MCP server name(s)
513
- * @returns Formatted string showing all tools from the server(s)
509
+ * @returns JSON string showing all tools grouped by server
514
510
  */
515
511
  function formatServerListing(
516
512
  tools: t.ToolMetadata[],
@@ -519,48 +515,46 @@ function formatServerListing(
519
515
  const servers = Array.isArray(serverNames) ? serverNames : [serverNames];
520
516
 
521
517
  if (tools.length === 0) {
522
- return `No tools found from MCP server(s): ${servers.join(', ')}.`;
518
+ return JSON.stringify(
519
+ {
520
+ listing_mode: true,
521
+ servers,
522
+ total_tools: 0,
523
+ tools_by_server: {},
524
+ hint: 'No tools found from the specified MCP server(s).',
525
+ },
526
+ null,
527
+ 2
528
+ );
523
529
  }
524
530
 
525
- const toolsByServer = new Map<string, t.ToolMetadata[]>();
531
+ const toolsByServer: Record<
532
+ string,
533
+ Array<{ name: string; description: string }>
534
+ > = {};
526
535
  for (const tool of tools) {
527
536
  const server = extractMcpServerName(tool.name) ?? 'unknown';
528
- const existing = toolsByServer.get(server) ?? [];
529
- existing.push(tool);
530
- toolsByServer.set(server, existing);
531
- }
532
-
533
- let response =
534
- servers.length === 1
535
- ? `## Tools from MCP server: ${servers[0]}\n\n`
536
- : `## Tools from MCP servers: ${servers.join(', ')}\n\n`;
537
-
538
- response += `Found ${tools.length} tool(s) (preview only - not yet loaded):\n\n`;
539
-
540
- for (const [server, serverTools] of toolsByServer) {
541
- if (servers.length > 1) {
542
- response += `### ${server}\n\n`;
543
- }
544
- for (const tool of serverTools) {
545
- const baseName = getBaseToolName(tool.name);
546
- response += `- **${baseName}**`;
547
- if (tool.description) {
548
- const shortDesc =
549
- tool.description.length > 80
550
- ? tool.description.substring(0, 77) + '...'
551
- : tool.description;
552
- response += `: ${shortDesc}`;
553
- }
554
- response += '\n';
555
- }
556
- if (servers.length > 1) {
557
- response += '\n';
537
+ if (!(server in toolsByServer)) {
538
+ toolsByServer[server] = [];
558
539
  }
540
+ toolsByServer[server].push({
541
+ name: getBaseToolName(tool.name),
542
+ description:
543
+ tool.description.length > 100
544
+ ? tool.description.substring(0, 97) + '...'
545
+ : tool.description,
546
+ });
559
547
  }
560
548
 
561
- response += `\n_To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it._`;
549
+ const output = {
550
+ listing_mode: true,
551
+ servers,
552
+ total_tools: tools.length,
553
+ tools_by_server: toolsByServer,
554
+ hint: `To use a tool, search for it by name (e.g., query: "${getBaseToolName(tools[0]?.name ?? 'tool_name')}") to load it.`,
555
+ };
562
556
 
563
- return response;
557
+ return JSON.stringify(output, null, 2);
564
558
  }
565
559
 
566
560
  /**
@@ -732,34 +732,41 @@ describe('ToolSearch', () => {
732
732
  },
733
733
  ];
734
734
 
735
- it('formats server listing with tool names and descriptions', () => {
735
+ it('returns valid JSON with tool listing', () => {
736
736
  const result = formatServerListing(serverTools, 'weather-api');
737
+ const parsed = JSON.parse(result);
737
738
 
738
- expect(result).toContain('Tools from MCP server: weather-api');
739
- expect(result).toContain('2 tool(s)');
740
- expect(result).toContain('get_weather');
741
- expect(result).toContain('get_forecast');
742
- expect(result).toContain('preview only');
739
+ expect(parsed.listing_mode).toBe(true);
740
+ expect(parsed.servers).toEqual(['weather-api']);
741
+ expect(parsed.total_tools).toBe(2);
742
+ expect(parsed.tools_by_server['weather-api']).toHaveLength(2);
743
743
  });
744
744
 
745
745
  it('includes hint to search for specific tool to load it', () => {
746
746
  const result = formatServerListing(serverTools, 'weather-api');
747
+ const parsed = JSON.parse(result);
747
748
 
748
- expect(result).toContain('To use a tool, search for it by name');
749
+ expect(parsed.hint).toContain('To use a tool, search for it by name');
749
750
  });
750
751
 
751
752
  it('uses base tool name (without MCP suffix) in display', () => {
752
753
  const result = formatServerListing(serverTools, 'weather-api');
754
+ const parsed = JSON.parse(result);
753
755
 
754
- expect(result).toContain('**get_weather**');
755
- expect(result).not.toContain('**get_weather_mcp_weather-api**');
756
+ const toolNames = parsed.tools_by_server['weather-api'].map(
757
+ (t: { name: string }) => t.name
758
+ );
759
+ expect(toolNames).toContain('get_weather');
760
+ expect(toolNames).not.toContain('get_weather_mcp_weather-api');
756
761
  });
757
762
 
758
763
  it('handles empty tools array', () => {
759
764
  const result = formatServerListing([], 'empty-server');
765
+ const parsed = JSON.parse(result);
760
766
 
761
- expect(result).toContain('No tools found');
762
- expect(result).toContain('empty-server');
767
+ expect(parsed.total_tools).toBe(0);
768
+ expect(parsed.servers).toContain('empty-server');
769
+ expect(parsed.hint).toContain('No tools found');
763
770
  });
764
771
 
765
772
  it('truncates long descriptions', () => {
@@ -767,17 +774,17 @@ describe('ToolSearch', () => {
767
774
  {
768
775
  name: 'long_tool_mcp_server',
769
776
  description:
770
- 'This is a very long description that exceeds 80 characters and should be truncated to keep the listing compact and readable.',
777
+ 'This is a very long description that exceeds 100 characters and should be truncated to keep the listing compact and readable for the LLM.',
771
778
  parameters: undefined,
772
779
  },
773
780
  ];
774
781
 
775
782
  const result = formatServerListing(toolsWithLongDesc, 'server');
783
+ const parsed = JSON.parse(result);
776
784
 
777
- expect(result).toContain('...');
778
- expect(result.length).toBeLessThan(
779
- toolsWithLongDesc[0].description.length + 200
780
- );
785
+ const toolDesc = parsed.tools_by_server['server'][0].description;
786
+ expect(toolDesc).toContain('...');
787
+ expect(toolDesc.length).toBeLessThanOrEqual(100);
781
788
  });
782
789
 
783
790
  it('handles multiple servers with grouped output', () => {
@@ -803,21 +810,20 @@ describe('ToolSearch', () => {
803
810
  'weather-api',
804
811
  'gmail',
805
812
  ]);
813
+ const parsed = JSON.parse(result);
806
814
 
807
- expect(result).toContain('Tools from MCP servers: weather-api, gmail');
808
- expect(result).toContain('3 tool(s)');
809
- expect(result).toContain('### weather-api');
810
- expect(result).toContain('### gmail');
811
- expect(result).toContain('get_weather');
812
- expect(result).toContain('send_email');
813
- expect(result).toContain('read_inbox');
815
+ expect(parsed.servers).toEqual(['weather-api', 'gmail']);
816
+ expect(parsed.total_tools).toBe(3);
817
+ expect(parsed.tools_by_server['weather-api']).toHaveLength(1);
818
+ expect(parsed.tools_by_server['gmail']).toHaveLength(2);
814
819
  });
815
820
 
816
821
  it('accepts single server as array', () => {
817
822
  const result = formatServerListing(serverTools, ['weather-api']);
823
+ const parsed = JSON.parse(result);
818
824
 
819
- expect(result).toContain('Tools from MCP server: weather-api');
820
- expect(result).not.toContain('###');
825
+ expect(parsed.servers).toEqual(['weather-api']);
826
+ expect(parsed.tools_by_server['weather-api']).toBeDefined();
821
827
  });
822
828
  });
823
829
  });