Skip to main content
Glama

Context Optimizer MCP Server

pathValidator.ts6.28 kB
/** * Path security validation utilities * * Prevents path traversal attacks and unauthorized file access */ import * as path from 'path'; import * as fs from 'fs/promises'; import { ConfigurationManager } from '../config/manager'; export class PathValidator { /** * Get the current platform (allows for easier testing) */ static getPlatform(): NodeJS.Platform { return process.platform; } /** * Normalize a path string for OS-specific comparison */ private static normalizeForComparison(p: string): string { return this.getPlatform() === 'win32' ? p.toLowerCase() : p; } /** * Checks if a resolved path is within a resolved base path (cross-platform, case-aware) */ private static isWithinBase(resolvedPath: string, resolvedBase: string): boolean { const normalizedPath = this.normalizeForComparison(resolvedPath); const normalizedBase = this.normalizeForComparison(resolvedBase); const baseWithSep = normalizedBase.endsWith(path.sep) ? normalizedBase : normalizedBase + path.sep; return normalizedPath === normalizedBase || normalizedPath.startsWith(baseWithSep); } /** * Validates a file path against security boundaries * * @param requestedPath - Path to validate * @returns Validation result with resolved path or error */ static async validateFilePath(requestedPath: string): Promise<{ valid: boolean; resolvedPath?: string; error?: string; }> { try { const config = ConfigurationManager.getConfig(); const resolvedPath = path.resolve(requestedPath); // Check against allowed base paths const isAllowed = config.security.allowedBasePaths.some(basePath => { const resolvedBase = path.resolve(basePath); return PathValidator.isWithinBase(resolvedPath, resolvedBase); }); if (!isAllowed) { return { valid: false, error: `Path '${resolvedPath}' is outside allowed directories: ${config.security.allowedBasePaths.join(', ')}` }; } // Check if file exists try { const stats = await fs.stat(resolvedPath); if (!stats.isFile()) { return { valid: false, error: `Path '${resolvedPath}' is not a file` }; } // Check file size if (stats.size > config.security.maxFileSize) { return { valid: false, error: `File '${resolvedPath}' exceeds maximum size limit (${config.security.maxFileSize} bytes)` }; } } catch { return { valid: false, error: `File '${resolvedPath}' does not exist or is not accessible` }; } return { valid: true, resolvedPath }; } catch (error) { return { valid: false, error: `Path validation error: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Validates a working directory path against security boundaries * * @param requestedPath - Directory path to validate * @returns Validation result with resolved path or error */ static async validateWorkingDirectory(requestedPath: string): Promise<{ valid: boolean; resolvedPath?: string; error?: string; }> { try { const config = ConfigurationManager.getConfig(); const resolvedPath = path.resolve(requestedPath); // Check against allowed base paths const isAllowed = config.security.allowedBasePaths.some(basePath => { const resolvedBase = path.resolve(basePath); return PathValidator.isWithinBase(resolvedPath, resolvedBase); }); if (!isAllowed) { return { valid: false, error: `Working directory '${resolvedPath}' is outside allowed paths: ${config.security.allowedBasePaths.join(', ')}` }; } // Check if directory exists try { const stats = await fs.stat(resolvedPath); if (!stats.isDirectory()) { return { valid: false, error: `Path '${resolvedPath}' is not a directory` }; } } catch { return { valid: false, error: `Directory '${resolvedPath}' does not exist or is not accessible` }; } return { valid: true, resolvedPath }; } catch (error) { return { valid: false, error: `Directory validation error: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Helper method to check if a path is within allowed boundaries (without file system checks) * * @param requestedPath - Path to check * @returns Whether the path is within allowed boundaries */ static isPathAllowed(requestedPath: string): boolean { try { const config = ConfigurationManager.getConfig(); const resolvedPath = path.resolve(requestedPath); return config.security.allowedBasePaths.some(basePath => { const resolvedBase = path.resolve(basePath); return PathValidator.isWithinBase(resolvedPath, resolvedBase); }); } catch { return false; } } /** * Normalize and sanitize a path for logging purposes * * @param filePath - Path to sanitize * @returns Sanitized path safe for logging */ static sanitizePathForLogging(filePath: string): string { try { // Check for obviously invalid characters first if (/[<>:"|?*\0]/.test(filePath)) { return '[INVALID_PATH]'; } const resolved = path.resolve(filePath); // Replace all directory components except the last one with placeholders const parts = resolved.split(path.sep); if (parts.length <= 2) { return resolved; // Too short to sanitize meaningfully } // Keep first part (drive on Windows, root on Unix) and last part (filename) const sanitized = parts.map((part, index) => { if (index === 0 || index === parts.length - 1) { return part; } return '****'; }).join(path.sep); return sanitized; } catch { return '[INVALID_PATH]'; } } }

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/malaksedarous/context-optimizer-mcp-server'

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