mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2024-12-22 18:16:52 +03:00
Revert filesystem back to original cli arg sandboxing
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user