UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

96 lines 2.98 kB
/** * Resource Router - URI routing infrastructure for templated resources * Supports parameterized URIs like adr://adr/{id} and adr://research/{topic} */ import { URL } from 'url'; import { McpAdrError } from '../types/index.js'; /** * URI Router for templated resources * Matches URI patterns and extracts parameters */ export class ResourceRouter { routes = []; /** * Register a route pattern with its handler */ register(pattern, handler, description) { // Ensure pattern starts with / const normalizedPattern = pattern.startsWith('/') ? pattern : `/${pattern}`; const registration = { pattern: normalizedPattern, handler, }; if (description !== undefined) { registration.description = description; } this.routes.push(registration); } /** * Route a URI to its handler and execute */ async route(uri) { const url = new URL(uri); const path = url.pathname; // Try to match pattern for (const route of this.routes) { if (this.matchPattern(route.pattern, path)) { const params = this.extractParams(route.pattern, path); return await route.handler(params, url.searchParams); } } throw new McpAdrError(`No route found for: ${uri}`, 'RESOURCE_NOT_FOUND'); } /** * Check if a pattern matches a path */ matchPattern(pattern, path) { // Convert pattern to regex: /adr/{id} -> /adr/([^/]+) const regex = pattern.replace(/\{[^}]+\}/g, '([^/]+)'); return new RegExp(`^${regex}$`).test(path); } /** * Extract parameters from path based on pattern */ extractParams(pattern, path) { const paramNames = pattern.match(/\{([^}]+)\}/g)?.map(p => p.slice(1, -1)) || []; const regex = pattern.replace(/\{[^}]+\}/g, '([^/]+)'); const matches = path.match(new RegExp(`^${regex}$`)); const params = {}; if (matches) { paramNames.forEach((name, i) => { const value = matches[i + 1]; if (value !== undefined) { params[name] = decodeURIComponent(value); } }); } return params; } /** * Get all registered routes */ getRoutes() { return [...this.routes]; } /** * Check if a URI can be routed */ canRoute(uri) { try { const url = new URL(uri); const path = url.pathname; for (const route of this.routes) { if (this.matchPattern(route.pattern, path)) { return true; } } return false; } catch { return false; } } } // Singleton instance export const resourceRouter = new ResourceRouter(); //# sourceMappingURL=resource-router.js.map