UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

225 lines 7.9 kB
/** * Tool Dispatcher - Dynamic Tool Discovery and Routing * * This module provides dynamic tool discovery via the search_tools meta-tool * and enables catalog-based tool listing for token-efficient responses. * * @see ADR-014: CE-MCP Architecture (Phase 3) * @see docs/IMPLEMENTATION-PLAN.md */ import { TOOL_CATALOG, searchTools, getCatalogSummary, getLightweightToolList, toMCPTool, getCEMCPTools, getHighTokenCostTools, } from './tool-catalog.js'; /** * Execute search_tools meta-tool * * This tool enables dynamic discovery of available tools without loading * all tool schemas upfront, significantly reducing token usage. */ export function executeSearchTools(args) { const { category, query, complexity, cemcpOnly = false, includeSchema = false, limit = 20, } = args; // Build search options, only including defined values const searchOptions = { 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 = { 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, }, }; if (query !== undefined) { response.query = query; } return response; } /** * Get the search_tools tool definition for MCP */ export function getSearchToolsDefinition() { 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, }, }, }, }; } /** * Get lightweight tool listing for MCP ListTools * * Returns tools with minimal metadata for token-efficient listing. * Clients can use search_tools to get full schemas when needed. */ export function getToolListForMCP(options) { 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 = [ getSearchToolsDefinition(), ...lightList.map(item => ({ name: item.name, description: `[${item.category}] ${item.description}${item.hasCEMCPDirective ? ' (CE-MCP)' : ''}`, inputSchema: { type: 'object', 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 = [getSearchToolsDefinition()]; for (const [, metadata] of TOOL_CATALOG) { tools.push(toMCPTool(metadata)); } return { tools }; } /** * Get tool categories with counts */ export function getToolCategories() { const summary = getCatalogSummary(); return { analysis: { count: summary.byCategory.analysis, description: 'Project analysis, architecture insights, code quality', }, adr: { count: summary.byCategory.adr, description: 'Architecture Decision Records management', }, 'content-security': { count: summary.byCategory['content-security'], description: 'Content security, masking, sensitive data protection', }, research: { count: summary.byCategory.research, description: 'Research, web search, knowledge integration', }, deployment: { count: summary.byCategory.deployment, description: 'Deployment readiness, CI/CD, git operations', }, memory: { count: summary.byCategory.memory, description: 'Conversation memory, context management', }, 'file-system': { count: summary.byCategory['file-system'], description: 'File and directory operations', }, rules: { count: summary.byCategory.rules, description: 'Rule generation and validation', }, workflow: { count: summary.byCategory.workflow, description: 'Workflow guidance, tool orchestration', }, utility: { count: summary.byCategory.utility, description: 'Utility functions, server status, datetime', }, }; } /** * Get CE-MCP enabled tools summary */ export function getCEMCPSummary() { const cemcpTools = getCEMCPTools(); const highCostTools = getHighTokenCostTools(); return { enabled: cemcpTools.map(t => t.name), highTokenCost: highCostTools.map(t => t.name), totalTokenSavings: 'CE-MCP tools reduce token usage by 60-70% by returning directives instead of executing prompts directly', }; } /** * Check if a tool exists in the catalog */ export function toolExists(toolName) { return TOOL_CATALOG.has(toolName); } /** * Get tool metadata by name */ export function getToolMetadata(toolName) { const metadata = TOOL_CATALOG.get(toolName); if (!metadata) return undefined; return toMCPTool(metadata); } //# sourceMappingURL=tool-dispatcher.js.map