Revert filesystem back to original cli arg sandboxing

This commit is contained in:
colinmcneil
2024-12-19 13:19:08 -05:00
committed by Jim Clark
parent 4034df774e
commit 0b36cb4b54

View File

@@ -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 <allowed-directory> [additional-directories...]");
process.exit(1);
}
allowedDirectories = args.map(dir =>
normalizePath(path.resolve(expandHome(dir)))
);
if (args.length === 0) {
console.error("Usage: mcp-server-filesystem <allowed-directory> [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<string> {
// 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<TreeEntry[]> {
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<TreeEntry[]> {
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);
});
});