search_tools
Search available tools by category, keyword, or capability to find the right tool for tasks without loading all schemas.
Instructions
Search and discover available tools by category, keyword, or capability. Use this to find the right tool for a task without loading all tool schemas. Returns lightweight tool metadata by default; use includeSchema:true for full schemas.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Filter tools by category | |
| query | No | Search query to match tool names, descriptions, and keywords | |
| complexity | No | Filter by tool complexity level | |
| cemcpOnly | No | Only return tools with CE-MCP directive support (more token-efficient) | |
| includeSchema | No | Include full input schemas in response (increases token count) | |
| limit | No | Maximum number of tools to return |
Implementation Reference
- src/tools/tool-dispatcher.ts:74-128 (handler)Handler function that executes the 'search_tools' MCP tool. Parses args, calls the underlying searchTools helper from tool-catalog, formats the SearchToolsResult.export function executeSearchTools(args: SearchToolsArgs): SearchToolsResult { const { category, query, complexity, cemcpOnly = false, includeSchema = false, limit = 20, } = args; // Build search options, only including defined values const searchOptions: Parameters<typeof searchTools>[0] = { cemcpOnly, includeSchema, limit, }; if (category !== undefined) { searchOptions.category = category; } if (query !== undefined) { searchOptions.query = query; } if (complexity !== undefined) { searchOptions.complexity = complexity; } const result = searchTools(searchOptions); const catalogSummary = getCatalogSummary(); const response: SearchToolsResult = { success: true, tools: result.tools.map(tool => ({ name: tool.name, description: tool.shortDescription, category: tool.category, complexity: tool.complexity, hasCEMCPDirective: tool.hasCEMCPDirective, tokenCost: tool.tokenCost, ...(includeSchema && tool.inputSchema ? { inputSchema: tool.inputSchema } : {}), })), summary: { totalFound: result.totalCount, totalInCatalog: catalogSummary.totalTools, byCategory: result.categories as Record<string, number>, }, }; if (query !== undefined) { response.query = query; } return response; }
- src/tools/tool-dispatcher.ts:133-184 (schema)Schema definition for the 'search_tools' tool returned by getSearchToolsDefinition(). This is the inputSchema exposed to MCP clients.export function getSearchToolsDefinition(): Tool { return { name: 'search_tools', description: 'Search and discover available tools by category, keyword, or capability. Use this to find the right tool for a task without loading all tool schemas. Returns lightweight tool metadata by default; use includeSchema:true for full schemas.', inputSchema: { type: 'object', properties: { category: { type: 'string', enum: [ 'analysis', 'adr', 'content-security', 'research', 'deployment', 'memory', 'file-system', 'rules', 'workflow', 'utility', ], description: 'Filter tools by category', }, query: { type: 'string', description: 'Search query to match tool names, descriptions, and keywords', }, complexity: { type: 'string', enum: ['simple', 'moderate', 'complex'], description: 'Filter by tool complexity level', }, cemcpOnly: { type: 'boolean', description: 'Only return tools with CE-MCP directive support (more token-efficient)', default: false, }, includeSchema: { type: 'boolean', description: 'Include full input schemas in response (increases token count)', default: false, }, limit: { type: 'number', description: 'Maximum number of tools to return', default: 20, }, }, }, }; }
- src/tools/tool-dispatcher.ts:192-230 (registration)Registration via getToolListForMCP function, which dynamically includes 'search_tools' (via getSearchToolsDefinition()) in the MCP tool list for ListTools calls, in summary/lightweight/full modes.export function getToolListForMCP(options: { mode?: 'full' | 'lightweight' | 'summary' }): { tools: Tool[]; } { const { mode = 'lightweight' } = options; if (mode === 'summary') { // Return only the search_tools meta-tool return { tools: [getSearchToolsDefinition()], }; } if (mode === 'lightweight') { // Return lightweight list with search_tools const lightList = getLightweightToolList(); const tools: Tool[] = [ getSearchToolsDefinition(), ...lightList.map(item => ({ name: item.name, description: `[${item.category}] ${item.description}${item.hasCEMCPDirective ? ' (CE-MCP)' : ''}`, inputSchema: { type: 'object' as const, properties: {}, description: `Use search_tools with query:"${item.name}" to get full schema`, }, })), ]; return { tools }; } // Full mode - return all tools with schemas from catalog const tools: Tool[] = [getSearchToolsDefinition()]; for (const [, metadata] of TOOL_CATALOG) { tools.push(toMCPTool(metadata)); } return { tools }; }
- src/tools/tool-catalog.ts:1478-1582 (helper)Core helper function searchTools that performs the actual catalog search/filtering/scoring on TOOL_CATALOG Map. Called by the handler.export function searchTools(options: ToolSearchOptions = {}): ToolSearchResult { const { category, query, complexity, cemcpOnly, limit = 20, includeSchema = false } = options; let results: CatalogEntry[] = []; // Convert map to array and apply filters for (const [_name, metadata] of TOOL_CATALOG) { // Apply category filter if (category && metadata.category !== category) continue; // Apply complexity filter if (complexity && metadata.complexity !== complexity) continue; // Apply CE-MCP filter if (cemcpOnly && !metadata.hasCEMCPDirective) continue; // Create catalog entry const entry: CatalogEntry = { ...metadata, isHighTokenCost: metadata.tokenCost.max > 5000, }; // Apply query filter with scoring if (query) { const lowerQuery = query.toLowerCase(); let score = 0; // Name match (highest priority) if (metadata.name.toLowerCase().includes(lowerQuery)) { score += 100; } // Keyword match for (const keyword of metadata.keywords) { if (keyword.toLowerCase().includes(lowerQuery)) { score += 50; } } // Description match if (metadata.shortDescription.toLowerCase().includes(lowerQuery)) { score += 25; } if (metadata.fullDescription.toLowerCase().includes(lowerQuery)) { score += 10; } if (score === 0) continue; entry.searchScore = score; } // Remove schema if not requested (token savings) if (!includeSchema) { // Create a copy without inputSchema for lighter response const lightEntry = { ...entry }; delete (lightEntry as Record<string, unknown>)['inputSchema']; results.push(lightEntry as CatalogEntry); } else { results.push(entry); } } // Sort by search score if query provided, otherwise by name if (query) { results.sort((a, b) => (b.searchScore || 0) - (a.searchScore || 0)); } else { results.sort((a, b) => a.name.localeCompare(b.name)); } // Calculate category counts const categories: Record<ToolCategory, number> = { analysis: 0, adr: 0, 'content-security': 0, research: 0, deployment: 0, memory: 0, 'file-system': 0, rules: 0, workflow: 0, utility: 0, }; for (const entry of results) { categories[entry.category]++; } // Apply limit const totalCount = results.length; if (limit && results.length > limit) { results = results.slice(0, limit); } const result: ToolSearchResult = { tools: results, totalCount, categories, }; if (query !== undefined) { result.query = query; } return result; }