diff --git a/src/filesystem/__tests__/roots-utils.test.ts b/src/filesystem/__tests__/roots-utils.test.ts index 1a39483953..27d500311d 100644 --- a/src/filesystem/__tests__/roots-utils.test.ts +++ b/src/filesystem/__tests__/roots-utils.test.ts @@ -1,10 +1,22 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { getValidRootDirectories } from '../roots-utils.js'; +import { formatEffectiveAllowedDirectories, getValidRootDirectories } from '../roots-utils.js'; import { mkdtempSync, rmSync, mkdirSync, writeFileSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import type { Root } from '@modelcontextprotocol/sdk/types.js'; +describe('formatEffectiveAllowedDirectories', () => { + it('includes the source and effective directories', () => { + expect(formatEffectiveAllowedDirectories(['/workspace', '/data'], 'client-provided MCP Roots')) + .toBe('Effective allowed directories (source: client-provided MCP Roots):\n /workspace\n /data'); + }); + + it('marks an empty effective directory set', () => { + expect(formatEffectiveAllowedDirectories([], 'none')) + .toBe('Effective allowed directories (source: none):\n (none)'); + }); +}); + describe('getValidRootDirectories', () => { let testDir1: string; let testDir2: string; @@ -81,4 +93,4 @@ describe('getValidRootDirectories', () => { expect(result).toHaveLength(1); }); }); -}); \ No newline at end of file +}); diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index 51ac523a66..976c990d03 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -13,7 +13,7 @@ import { pathToFileURL } from "url"; import { z } from "zod"; import { minimatch } from "minimatch"; import { normalizePath, expandHome } from './path-utils.js'; -import { getValidRootDirectories } from './roots-utils.js'; +import { formatEffectiveAllowedDirectories, getValidRootDirectories } from './roots-utils.js'; import { // Function imports formatSize, @@ -90,6 +90,12 @@ if (accessibleDirectories.length === 0 && allowedDirectories.length > 0) { allowedDirectories = accessibleDirectories; +let allowedDirectoriesSource = allowedDirectories.length > 0 ? "server arguments" : "none"; + +function logEffectiveAllowedDirectories() { + console.error(formatEffectiveAllowedDirectories(allowedDirectories, allowedDirectoriesSource)); +} + // Initialize the global allowedDirectories in lib.ts setAllowedDirectories(allowedDirectories); @@ -726,10 +732,13 @@ async function updateAllowedDirectoriesFromRoots(requestedRoots: Root[]) { const validatedRootDirs = await getValidRootDirectories(requestedRoots); if (validatedRootDirs.length > 0) { allowedDirectories = [...validatedRootDirs]; + allowedDirectoriesSource = "client-provided MCP Roots"; setAllowedDirectories(allowedDirectories); // Update the global state in lib.ts console.error(`Updated allowed directories from MCP roots: ${validatedRootDirs.length} valid directories`); + logEffectiveAllowedDirectories(); } else { - console.error("No valid root directories provided by client"); + console.error("No valid root directories provided by client; retaining current allowed directories"); + logEffectiveAllowedDirectories(); } } @@ -757,14 +766,18 @@ server.server.oninitialized = async () => { await updateAllowedDirectoriesFromRoots(response.roots); } else { console.error("Client returned no roots set, keeping current settings"); + logEffectiveAllowedDirectories(); } } catch (error) { console.error("Failed to request initial roots from client:", error instanceof Error ? error.message : String(error)); + logEffectiveAllowedDirectories(); } } else { if (allowedDirectories.length > 0) { - console.error("Client does not support MCP Roots, using allowed directories set from server args:", allowedDirectories); + console.error("Client does not support MCP Roots"); + logEffectiveAllowedDirectories(); }else{ + logEffectiveAllowedDirectories(); throw new Error(`Server cannot operate: No allowed directories available. Server was started without command-line directories and client either does not support MCP roots protocol or provided empty roots. Please either: 1) Start server with directory arguments, or 2) Use a client that supports MCP roots protocol and provides valid root directories.`); } } diff --git a/src/filesystem/roots-utils.ts b/src/filesystem/roots-utils.ts index 5e26bb246b..af214944dd 100644 --- a/src/filesystem/roots-utils.ts +++ b/src/filesystem/roots-utils.ts @@ -5,6 +5,14 @@ import { normalizePath } from './path-utils.js'; import type { Root } from '@modelcontextprotocol/sdk/types.js'; import { fileURLToPath } from "url"; +export function formatEffectiveAllowedDirectories( + directories: readonly string[], + source: string +): string { + const entries = directories.length > 0 ? directories.map(directory => ` ${directory}`) : [" (none)"]; + return [`Effective allowed directories (source: ${source}):`, ...entries].join("\n"); +} + /** * Converts a root URI to a normalized directory path with basic security validation. * @param rootUri - File URI (file://...) or plain directory path @@ -74,4 +82,4 @@ export async function getValidRootDirectories( } return validatedDirectories; -} \ No newline at end of file +}