llm_web_search
Perform web searches using LLM optimization for architectural decision research, extracting relevant content to support technical documentation.
Instructions
LLM-managed web search using Firecrawl for cross-platform support
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The search query to execute | |
| maxResults | No | Maximum results to return | |
| includeContent | No | Include full content in results | |
| llmInstructions | No | LLM instructions for search optimization | |
| projectPath | No | Path to project directory | . |
| adrDirectory | No | Directory containing ADR files | docs/adrs |
Implementation Reference
- src/tools/llm-web-search-tool.ts:55-162 (handler)The core handler function `llmWebSearch` that executes the tool logic: validates input, initializes ResearchOrchestrator with Firecrawl, performs web search, limits results, generates LLM analysis, and formats markdown output with progress reporting.export async function llmWebSearch( args: { query: string; maxResults?: number; includeContent?: boolean; llmInstructions?: string; projectPath?: string; adrDirectory?: string; }, context?: ToolContext ): Promise<any> { const { query, maxResults = 5, includeContent = true, llmInstructions, projectPath, adrDirectory, } = args; if (!query || query.trim().length === 0) { throw new McpAdrError('Query parameter is required and cannot be empty', 'INVALID_QUERY'); } try { context?.info(`🌐 Initializing web search for: ${query}`); context?.report_progress(0, 100); // Initialize research orchestrator with Firecrawl const orchestrator = new ResearchOrchestrator(projectPath, adrDirectory); // Enhance query with LLM instructions if provided context?.info('🤖 Optimizing search query with LLM guidance...'); context?.report_progress(25, 100); let enhancedQuery = query; if (llmInstructions) { enhancedQuery = `${query}\n\nLLM Instructions: ${llmInstructions}`; } // Perform web search using research orchestrator context?.info('🔍 Executing web search with Firecrawl...'); context?.report_progress(50, 100); const researchResult = await orchestrator.answerResearchQuestion(enhancedQuery); // Extract web search results const webSearchSource = researchResult.sources.find(source => source.type === 'web_search'); const webResults = webSearchSource?.data?.results || []; // Limit results const limitedResults = webResults.slice(0, maxResults); // Generate LLM analysis of results context?.info('📊 Analyzing search results with LLM...'); context?.report_progress(75, 100); const llmAnalysis = await generateLLMAnalysis(query, limitedResults, llmInstructions); context?.info('✅ Web search complete!'); context?.report_progress(100, 100); return { content: [ { type: 'text', text: `# LLM-Managed Web Search Results ## Query ${query} ${llmInstructions ? `## LLM Instructions\n${llmInstructions}\n` : ''} ## Search Results (${limitedResults.length} found) ${limitedResults .map( (result: any, index: number) => ` ### ${index + 1}. ${result.title} - **URL**: ${result.url} - **Relevance**: ${(result.relevance * 100).toFixed(1)}% - **Content**: ${includeContent ? result.content?.substring(0, 500) + '...' : 'Content available'} --- ` ) .join('\n')} ## LLM Analysis ${llmAnalysis} ## Search Metadata - **Provider**: Firecrawl - **Total Results**: ${webResults.length} - **Returned Results**: ${limitedResults.length} - **Confidence**: ${(researchResult.confidence * 100).toFixed(1)}% - **Timestamp**: ${new Date().toISOString()} `, }, ], }; } catch (error) { throw new McpAdrError( `Web search failed: ${error instanceof Error ? error.message : String(error)}`, 'WEB_SEARCH_ERROR' ); } }
- src/tools/tool-catalog.ts:681-700 (schema)Tool registration in the central TOOL_CATALOG with metadata, JSON input schema, category 'research', and related tools.TOOL_CATALOG.set('llm_web_search', { name: 'llm_web_search', shortDescription: 'Web search via LLM', fullDescription: 'Performs web searches with LLM-enhanced result analysis.', category: 'research', complexity: 'moderate', tokenCost: { min: 2000, max: 5000 }, hasCEMCPDirective: true, // Phase 4.3: Moderate tool - LLM web search relatedTools: ['perform_research', 'llm_cloud_management'], keywords: ['search', 'web', 'llm', 'internet'], requiresAI: true, inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query' }, maxResults: { type: 'number', default: 10 }, }, required: ['query'], }, });
- Supporting helper function for generating LLM analysis of search results (currently stubbed).async function generateLLMAnalysis( _query: string, _results: unknown[], _instructions?: string ): Promise<string> { // TODO: Implement LLM analysis when AI executor is available // const { loadAIConfig, getAIExecutor } = await import('../config/ai-config.js'); // const aiConfig = loadAIConfig(); // const executor = getAIExecutor(); // const prompt = ` // Analyze these web search results for the query: "${query}" // // ${instructions ? `Additional Instructions: ${instructions}` : ''} // // Search Results: // ${results.map((result, index) => ` // ${index + 1}. ${result.title} // URL: ${result.url} // Relevance: ${(result.relevance * 100).toFixed(1)}% // Content Preview: ${result.content?.substring(0, 300)}... // `).join('\n')} // // Provide analysis covering: // 1. Overall quality and relevance of results // 2. Key insights and findings // 3. Gaps or missing information // 4. Recommendations for further research // 5. Summary of most valuable sources // // Keep analysis concise but comprehensive. // `; // const result = await executor.executeStructuredPrompt(prompt, { // type: 'object', // properties: { // analysis: { type: 'string' } // } // }); // return result.data.analysis || 'Analysis unavailable'; return 'LLM analysis is not yet available. Results are available but require manual review.'; }
- src/tools/tool-dispatcher.ts:192-230 (registration)The tool dispatcher that generates the MCP tool list using the TOOL_CATALOG, including llm_web_search schema via toMCPTool.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 }; }