Skip to main content
Glama
tool-catalog-resource.ts6.23 kB
/** * Tool Catalog Resource - Comprehensive tool metadata registry * URI Pattern: adr://tools/catalog */ import { URLSearchParams } from 'url'; import { McpAdrError } from '../types/index.js'; import { resourceCache, generateETag } from './resource-cache.js'; import { ResourceGenerationResult } from './index.js'; import { resourceRouter } from './resource-router.js'; export interface ToolCatalogData { summary: { totalTools: number; byCategory: Record<string, number>; cemcpEnabled: number; highTokenCost: number; }; tools: Array<{ name: string; description: string; category: string; complexity: string; tokenCost: { min: number; max: number }; hasCEMCPDirective: boolean; requiresAI: boolean; relatedTools: string[]; keywords: string[]; }>; timestamp: string; } /** * Generate tool catalog resource with comprehensive tool metadata. * * Returns a complete catalog of all available MCP tools with: * - Tool metadata (name, description, category, complexity) * - Token cost estimates and CE-MCP availability * - Related tools and keyword tags * - Summary statistics by category * * **URI Pattern:** `adr://tools/catalog` * * **Query Parameters:** * - `category`: Filter by tool category (optional) * - `includeSchema`: Include full input schemas (default: false) * - `lightweight`: Return minimal metadata only (default: false) * * @param params - URL path parameters (none for this resource) * @param searchParams - URL query parameters for filtering * * @returns Promise resolving to resource generation result containing: * - data: Complete tool catalog with metadata * - contentType: "application/json" * - lastModified: ISO timestamp of generation * - cacheKey: Unique identifier "tool-catalog" or "tool-catalog:{category}" * - ttl: Cache duration (300 seconds / 5 minutes) * - etag: Entity tag for cache validation * * @throws {McpAdrError} When catalog generation fails * * @example * ```typescript * // Get full tool catalog * const catalog = await generateToolCatalogResource( * {}, * new URLSearchParams() * ); * * console.log(`Total tools: ${catalog.data.summary.totalTools}`); * console.log(`CE-MCP enabled: ${catalog.data.summary.cemcpEnabled}`); * * // Filter by category * const adrTools = await generateToolCatalogResource( * {}, * new URLSearchParams('category=adr') * ); * * // Get lightweight catalog (minimal metadata) * const lightweight = await generateToolCatalogResource( * {}, * new URLSearchParams('lightweight=true') * ); * * // Expected output structure: * { * data: { * summary: { * totalTools: 60, * byCategory: { * analysis: 10, * adr: 15, * deployment: 8, * ... * }, * cemcpEnabled: 25, * highTokenCost: 12 * }, * tools: [ * { * name: "analyze_project_ecosystem", * description: "Comprehensive project analysis...", * category: "analysis", * complexity: "complex", * tokenCost: { min: 5000, max: 15000 }, * hasCEMCPDirective: true, * requiresAI: true, * relatedTools: ["get_architectural_context"], * keywords: ["analysis", "ecosystem", "project"] * }, * ... * ], * timestamp: "2025-12-16T04:30:00.000Z" * }, * contentType: "application/json", * cacheKey: "tool-catalog", * ttl: 300 * } * ``` * * @since v2.2.0 * @see {@link TOOL_CATALOG} for the underlying tool registry */ export async function generateToolCatalogResource( _params: Record<string, string>, searchParams: URLSearchParams ): Promise<ResourceGenerationResult> { const category = searchParams.get('category'); const includeSchema = searchParams.get('includeSchema') === 'true'; const lightweight = searchParams.get('lightweight') === 'true'; const cacheKey = category ? `tool-catalog:${category}` : 'tool-catalog'; // Check cache const cached = await resourceCache.get<ResourceGenerationResult>(cacheKey); if (cached) { return cached; } try { // Dynamically import the tool catalog to avoid circular dependencies const { getCatalogSummary, searchTools } = await import('../tools/tool-catalog.js'); // Get summary statistics const summary = getCatalogSummary(); // Get tools (filtered by category if specified) const searchResult = category ? searchTools({ category: category as any, includeSchema, limit: 1000 }) : searchTools({ includeSchema, limit: 1000 }); // Format tools based on lightweight flag const tools = searchResult.tools.map(tool => { if (lightweight) { return { name: tool.name, description: tool.shortDescription, category: tool.category, hasCEMCPDirective: tool.hasCEMCPDirective, }; } const formatted: any = { name: tool.name, description: tool.fullDescription, category: tool.category, complexity: tool.complexity, tokenCost: tool.tokenCost, hasCEMCPDirective: tool.hasCEMCPDirective, requiresAI: tool.requiresAI, relatedTools: tool.relatedTools, keywords: tool.keywords, }; if (includeSchema) { formatted.inputSchema = tool.inputSchema; } return formatted; }); const catalogData: ToolCatalogData = { summary, tools, timestamp: new Date().toISOString(), }; const result: ResourceGenerationResult = { data: catalogData, contentType: 'application/json', lastModified: new Date().toISOString(), cacheKey, ttl: 300, // 5 minutes cache (catalog is relatively static) etag: generateETag(catalogData), }; // Cache result resourceCache.set(cacheKey, result, result.ttl); return result; } catch (error) { throw new McpAdrError( `Failed to generate tool catalog: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_GENERATION_ERROR' ); } } // Register route resourceRouter.register('/tools/catalog', generateToolCatalogResource, 'Comprehensive tool metadata registry');

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tosin2013/mcp-adr-analysis-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server