Skip to main content
Glama

mcp-adr-analysis-server

by tosin2013
root-manager.ts4.68 kB
/** * Root Manager for MCP File Access Control * * Implements MCP best practices for file system access control using "roots". * Roots are predefined directories that the server is allowed to access, * providing both security and autonomous file discovery for Claude. * * @see https://modelcontextprotocol.io/docs/concepts/roots */ import { resolve, relative } from 'path'; /** * A root is a directory that the MCP server is allowed to access */ export interface Root { /** Unique identifier for the root */ name: string; /** Absolute path to the root directory */ path: string; /** Human-readable description of what this root contains */ description: string; } /** * Manages file system roots for MCP server access control * * @example * ```typescript * const rootManager = new RootManager('/path/to/project', '/path/to/project/docs/adrs'); * * // Check if path is allowed * if (rootManager.isPathAllowed('/path/to/project/src/index.ts')) { * // Access granted * } * * // List all roots for Claude * const roots = rootManager.listRoots(); * ``` */ export class RootManager { private roots: Map<string, Root> = new Map(); /** * Initialize root manager with project and ADR paths * * @param projectPath - Path to the project root directory * @param adrDirectory - Path to the ADR directory */ constructor(projectPath: string, adrDirectory: string) { // Root 1: Project directory (entire codebase) this.roots.set('project', { name: 'project', path: resolve(projectPath), description: 'Project source code, configuration, and documentation', }); // Root 2: ADR directory (may be inside project, but worth explicit access) const resolvedAdrPath = resolve(adrDirectory); this.roots.set('adrs', { name: 'adrs', path: resolvedAdrPath, description: 'Architectural Decision Records', }); } /** * Check if a path is within accessible roots * * @param targetPath - Path to check (can be relative or absolute) * @returns true if path is within any root, false otherwise * * @example * ```typescript * if (!rootManager.isPathAllowed(userPath)) { * throw new Error('Access denied: Path is outside accessible roots'); * } * ``` */ isPathAllowed(targetPath: string): boolean { const resolved = resolve(targetPath); for (const root of this.roots.values()) { if (resolved.startsWith(root.path)) { return true; } } return false; } /** * List all accessible roots * * @returns Array of root definitions * * @example * ```typescript * const roots = rootManager.listRoots(); * roots.forEach(root => { * console.log(`${root.name}: ${root.path}`); * }); * ``` */ listRoots(): Root[] { return Array.from(this.roots.values()); } /** * Get which root a path belongs to * * @param targetPath - Path to check * @returns Root that contains this path, or null if outside all roots * * @example * ```typescript * const root = rootManager.getRootForPath('/path/to/project/src/index.ts'); * if (root) { * console.log(`File is in ${root.name} root`); * } * ``` */ getRootForPath(targetPath: string): Root | null { const resolved = resolve(targetPath); for (const root of this.roots.values()) { if (resolved.startsWith(root.path)) { return root; } } return null; } /** * Get the relative path from root * * @param targetPath - Path to get relative path for * @returns Relative path from root, or null if outside all roots * * @example * ```typescript * const relPath = rootManager.getRelativePathFromRoot('/path/to/project/src/index.ts'); * // Returns: 'src/index.ts' * ``` */ getRelativePathFromRoot(targetPath: string): string | null { const root = this.getRootForPath(targetPath); if (!root) { return null; } return relative(root.path, resolve(targetPath)); } /** * Add a custom root (useful for testing or dynamic root management) * * @param name - Unique identifier for the root * @param path - Absolute path to the root directory * @param description - Human-readable description */ addRoot(name: string, path: string, description: string): void { this.roots.set(name, { name, path: resolve(path), description, }); } /** * Remove a root by name * * @param name - Name of the root to remove * @returns true if root was removed, false if not found */ removeRoot(name: string): boolean { return this.roots.delete(name); } }

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