diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index f073a83e..b4d5c419 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -17,27 +17,9 @@ import { minimatch } from 'minimatch'; // Command line argument parsing const args = process.argv.slice(2); - -let allowedDirectories: string[] = []; - -let hasProjectsDirectory = false; - -// If the projects directory has contents, use it as the root workspace -const projectsContents = await fs.readdir('/projects'); -if (projectsContents.length > 0) { - hasProjectsDirectory = true; - allowedDirectories = projectsContents.map(dir => - normalizePath(path.resolve(expandHome(dir))) - ); -} -else { - if (args.length === 0) { - console.error("Usage: mcp-server-filesystem [additional-directories...]"); - process.exit(1); - } - allowedDirectories = args.map(dir => - normalizePath(path.resolve(expandHome(dir))) - ); +if (args.length === 0) { + console.error("Usage: mcp-server-filesystem [additional-directories...]"); + process.exit(1); } // Normalize all paths consistently @@ -53,12 +35,15 @@ function expandHome(filepath: string): string { } // Store allowed directories in normalized form +const allowedDirectories = args.map(dir => + normalizePath(path.resolve(expandHome(dir))) +); // Validate that all directories exist and are accessible -await Promise.all(allowedDirectories.map(async (dir) => { +await Promise.all(args.map(async (dir) => { try { const stats = await fs.stat(dir); - if (!stats.isDirectory() && !hasProjectsDirectory) { + if (!stats.isDirectory()) { console.error(`Error: ${dir} is not a directory`); process.exit(1); } @@ -269,7 +254,7 @@ function createUnifiedDiff(originalContent: string, newContent: string, filepath async function applyFileEdits( filePath: string, - edits: Array<{ oldText: string, newText: string }>, + edits: Array<{oldText: string, newText: string}>, dryRun = false ): Promise { // Read file content and normalize line endings @@ -405,10 +390,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { { name: "directory_tree", description: - "Get a recursive tree view of files and directories as a JSON structure. " + - "Each entry includes 'name', 'type' (file/directory), and 'children' for directories. " + - "Files have no children array, while directories always have a children array (which may be empty). " + - "The output is formatted with 2-space indentation for readability. Only works within allowed directories.", + "Get a recursive tree view of files and directories as a JSON structure. " + + "Each entry includes 'name', 'type' (file/directory), and 'children' for directories. " + + "Files have no children array, while directories always have a children array (which may be empty). " + + "The output is formatted with 2-space indentation for readability. Only works within allowed directories.", inputSchema: zodToJsonSchema(DirectoryTreeArgsSchema) as ToolInput, }, { @@ -545,49 +530,49 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }; } - case "directory_tree": { - const parsed = DirectoryTreeArgsSchema.safeParse(args); - if (!parsed.success) { - throw new Error(`Invalid arguments for directory_tree: ${parsed.error}`); - } - - interface TreeEntry { - name: string; - type: 'file' | 'directory'; - children?: TreeEntry[]; - } - - async function buildTree(currentPath: string): Promise { - const validPath = await validatePath(currentPath); - const entries = await fs.readdir(validPath, { withFileTypes: true }); - const result: TreeEntry[] = []; - - for (const entry of entries) { - const entryData: TreeEntry = { - name: entry.name, - type: entry.isDirectory() ? 'directory' : 'file' - }; - - if (entry.isDirectory()) { - const subPath = path.join(currentPath, entry.name); - entryData.children = await buildTree(subPath); + case "directory_tree": { + const parsed = DirectoryTreeArgsSchema.safeParse(args); + if (!parsed.success) { + throw new Error(`Invalid arguments for directory_tree: ${parsed.error}`); } - result.push(entryData); - } + interface TreeEntry { + name: string; + type: 'file' | 'directory'; + children?: TreeEntry[]; + } - return result; + async function buildTree(currentPath: string): Promise { + const validPath = await validatePath(currentPath); + const entries = await fs.readdir(validPath, {withFileTypes: true}); + const result: TreeEntry[] = []; + + for (const entry of entries) { + const entryData: TreeEntry = { + name: entry.name, + type: entry.isDirectory() ? 'directory' : 'file' + }; + + if (entry.isDirectory()) { + const subPath = path.join(currentPath, entry.name); + entryData.children = await buildTree(subPath); + } + + result.push(entryData); + } + + return result; + } + + const treeData = await buildTree(parsed.data.path); + return { + content: [{ + type: "text", + text: JSON.stringify(treeData, null, 2) + }], + }; } - const treeData = await buildTree(parsed.data.path); - return { - content: [{ - type: "text", - text: JSON.stringify(treeData, null, 2) - }], - }; - } - case "move_file": { const parsed = MoveFileArgsSchema.safeParse(args); if (!parsed.success) { @@ -621,11 +606,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { const validPath = await validatePath(parsed.data.path); const info = await getFileStats(validPath); return { - content: [{ - type: "text", text: Object.entries(info) - .map(([key, value]) => `${key}: ${value}`) - .join("\n") - }], + content: [{ type: "text", text: Object.entries(info) + .map(([key, value]) => `${key}: ${value}`) + .join("\n") }], }; } @@ -661,4 +644,4 @@ async function runServer() { runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); -}); \ No newline at end of file +});