Skip to main content
Glama

filesystem-mcp

by sylphxltd
path-utils.test.ts8.72 kB
import { describe, it, expect } from 'vitest'; // Removed vi, beforeEach import path from 'node:path'; import { ErrorCode } from '@modelcontextprotocol/sdk/types.js'; // Import the functions and constant to test import { resolvePath, PROJECT_ROOT, // Import the constant again } from '../../src/utils/path-utils.ts'; // Define the mock root path for testing overrides const MOCK_PROJECT_ROOT_OVERRIDE = path.resolve('/mock/project/root/override'); const ACTUAL_PROJECT_ROOT = process.cwd(); // Get the actual root for comparison describe('pathUtils', () => { it('should have PROJECT_ROOT set to the actual process.cwd()', () => { // We can no longer easily mock this at the module level with current setup // So we test that it equals the actual cwd expect(PROJECT_ROOT).toBe(ACTUAL_PROJECT_ROOT); }); describe('resolvePath', () => { // Test using the override parameter to simulate different roots it('should resolve a valid relative path using override root', () => { const userPath = 'src/file.ts'; const expectedPath = path.resolve(MOCK_PROJECT_ROOT_OVERRIDE, userPath); // Pass the override root as the second argument expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(expectedPath); }); it('should resolve a valid relative path using default PROJECT_ROOT when override is not provided', () => { const userPath = 'src/file.ts'; const expectedPath = path.resolve(ACTUAL_PROJECT_ROOT, userPath); expect(resolvePath(userPath)).toBe(expectedPath); // No override }); it('should resolve a relative path with "." correctly', () => { const userPath = './src/./file.ts'; const expectedPath = path.resolve(MOCK_PROJECT_ROOT_OVERRIDE, 'src/file.ts'); expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(expectedPath); }); it('should resolve a relative path with "." correctly using default root', () => { const userPath = './src/./file.ts'; const expectedPath = path.resolve(ACTUAL_PROJECT_ROOT, 'src/file.ts'); expect(resolvePath(userPath)).toBe(expectedPath); }); it('should resolve a relative path with ".." correctly if it stays within root', () => { const userPath = 'src/../dist/bundle.js'; const expectedPath = path.resolve(MOCK_PROJECT_ROOT_OVERRIDE, 'dist/bundle.js'); expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(expectedPath); }); it('should resolve a relative path with ".." correctly using default root', () => { const userPath = 'src/../dist/bundle.js'; const expectedPath = path.resolve(ACTUAL_PROJECT_ROOT, 'dist/bundle.js'); expect(resolvePath(userPath)).toBe(expectedPath); }); it('should throw McpError for absolute paths (posix)', () => { const userPath = '/etc/passwd'; // Test with override, should still fail expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidParams, message: 'MCP error -32602: Absolute paths are not allowed: /etc/passwd', data: undefined, }), ); // Test without override expect(() => resolvePath(userPath)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidParams, message: 'MCP error -32602: Absolute paths are not allowed: /etc/passwd', data: undefined, }), ); }); it('should throw McpError for absolute paths (windows)', () => { const userPath = String.raw`C:\Windows\System32`; const normalizedPath = path.normalize(userPath); // Test with override expect(() => resolvePath(normalizedPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ name: 'McpError', code: expect.any(Number), message: expect.stringContaining('Absolute paths are not allowed'), }), ); expect(() => resolvePath(normalizedPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( /Absolute paths are not allowed/, ); expect(() => resolvePath(normalizedPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ code: ErrorCode.InvalidParams }), ); // Test without override expect(() => resolvePath(normalizedPath)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidParams, message: expect.stringContaining('Absolute paths are not allowed'), }), ); }); it('should throw McpError for path traversal attempts (using ..)', () => { const userPath = '../outside/file'; // Test with override expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidRequest, message: 'MCP error -32600: Path traversal detected: ../outside/file', data: undefined, }), ); // Test without override expect(() => resolvePath(userPath)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidRequest, message: 'MCP error -32600: Path traversal detected: ../outside/file', data: undefined, }), ); }); it('should throw McpError for path traversal attempts (using .. multiple times)', () => { const userPath = '../../../../outside/file'; // Test with override expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidRequest, message: 'MCP error -32600: Path traversal detected: ../../../../outside/file', data: undefined, }), ); // Test without override expect(() => resolvePath(userPath)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidRequest, message: 'MCP error -32600: Path traversal detected: ../../../../outside/file', data: undefined, }), ); }); it('should throw McpError if the input path is not a string', () => { const userPath: any = 123; // intentionally testing invalid input // Test with override (should still fail type check before override matters) expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ name: 'McpError', code: expect.any(Number), message: expect.stringContaining('Path must be a string'), }), ); expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( /Path must be a string/, ); expect(() => resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toThrow( expect.objectContaining({ code: ErrorCode.InvalidParams }), ); // Test without override expect(() => resolvePath(userPath)).toThrow( expect.objectContaining({ name: 'McpError', code: ErrorCode.InvalidParams, message: expect.stringContaining('Path must be a string'), }), ); }); it('should handle paths with trailing slashes', () => { const userPath = 'src/subdir/'; const expectedPathOverride = path.resolve(MOCK_PROJECT_ROOT_OVERRIDE, 'src/subdir'); expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(expectedPathOverride); }); it('should handle paths with trailing slashes using default root', () => { const userPath = 'src/subdir/'; const expectedPath = path.resolve(ACTUAL_PROJECT_ROOT, 'src/subdir'); expect(resolvePath(userPath)).toBe(expectedPath); }); it('should handle empty string path', () => { const userPath = ''; // Test with override expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(MOCK_PROJECT_ROOT_OVERRIDE); }); it('should handle empty string path using default root', () => { const userPath = ''; const expectedPath = ACTUAL_PROJECT_ROOT; // Resolves to the root itself expect(resolvePath(userPath)).toBe(expectedPath); }); it('should handle "." path', () => { const userPath = '.'; // Test with override expect(resolvePath(userPath, MOCK_PROJECT_ROOT_OVERRIDE)).toBe(MOCK_PROJECT_ROOT_OVERRIDE); }); it('should handle "." path using default root', () => { const userPath = '.'; const expectedPath = ACTUAL_PROJECT_ROOT; // Resolves to the root itself expect(resolvePath(userPath)).toBe(expectedPath); }); }); });

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/sylphxltd/filesystem-mcp'

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