Skip to main content
Glama
MartinSchlott

BetterMCPFileServer

fileTools.ts4.7 kB
import fs from "fs/promises"; import path from "path"; import { z } from "zod"; import { validatePath, pathAliases, toAliasPath, isWriteOperationToRoot } from "../pathUtils.js"; import { WriteFileSchema, ReadFileContentSchema, EditFileSchema, ManageFileSchema } from "../schemas.js"; import { applyFileEdits } from "../editUtils.js"; // Write file operation export async function writeFile( args: z.infer<typeof WriteFileSchema>, allowedDirectories: string[] ): Promise<string> { // Block write operations to root if (isWriteOperationToRoot("write", args.filePath)) { throw new Error("Write operations to root directory are not allowed"); } const validPath = await validatePath(args.filePath, allowedDirectories); await fs.writeFile(validPath, args.content, "utf-8"); // Return alias path in the response const aliasPath = pathAliases.length > 0 ? toAliasPath(validPath) : args.filePath; return `Successfully wrote to ${aliasPath}`; } // Read file operation export async function readFileContent( args: z.infer<typeof ReadFileContentSchema>, allowedDirectories: string[] ): Promise<string> { const validPath = await validatePath(args.filePath, allowedDirectories); return await fs.readFile(validPath, "utf-8"); } // Edit file operation export async function editFile( args: z.infer<typeof EditFileSchema>, allowedDirectories: string[] ): Promise<string> { // Block edit operations to root if (isWriteOperationToRoot("write", args.filePath)) { throw new Error("Edit operations to root directory are not allowed"); } const validPath = await validatePath(args.filePath, allowedDirectories); try { const diffResult = await applyFileEdits( validPath, args.edits, args.dryRun ); const actionMsg = args.dryRun ? "Dry run completed. Here's what would change:" : "File edited successfully. Here's what changed:"; return `${actionMsg}\n\n${diffResult}`; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to edit file: ${errorMessage}`); } } // Manage file operations (move, rename, copy, delete) export async function manageFile( args: z.infer<typeof ManageFileSchema>, allowedDirectories: string[] ): Promise<string> { // Block operations on root if (isWriteOperationToRoot(args.action, args.filePath)) { throw new Error(`${args.action} operations to root directory are not allowed`); } const validSourcePath = await validatePath(args.filePath, allowedDirectories); switch (args.action) { case "delete": { await fs.unlink(validSourcePath); // Return alias path in the response const aliasPath = pathAliases.length > 0 ? toAliasPath(validSourcePath) : args.filePath; return `Successfully deleted ${aliasPath}`; } case "move": case "rename": { if (!args.newFilePath) { throw new Error(`newFilePath is required for ${args.action} action`); } // Block operations on root if (isWriteOperationToRoot(args.action, args.newFilePath)) { throw new Error(`${args.action} operations to root directory are not allowed`); } const validDestPath = await validatePath(args.newFilePath, allowedDirectories); await fs.rename(validSourcePath, validDestPath); // Return alias paths in the response const sourceAliasPath = pathAliases.length > 0 ? toAliasPath(validSourcePath) : args.filePath; const destAliasPath = pathAliases.length > 0 ? toAliasPath(validDestPath) : args.newFilePath; return `Successfully ${args.action === "move" ? "moved" : "renamed"} ${sourceAliasPath} to ${destAliasPath}`; } case "copy": { if (!args.newFilePath) { throw new Error("newFilePath is required for copy action"); } // Block operations on root if (isWriteOperationToRoot(args.action, args.newFilePath)) { throw new Error(`${args.action} operations to root directory are not allowed`); } const validDestPath = await validatePath(args.newFilePath, allowedDirectories); await fs.copyFile(validSourcePath, validDestPath); // Return alias paths in the response const sourceAliasPath = pathAliases.length > 0 ? toAliasPath(validSourcePath) : args.filePath; const destAliasPath = pathAliases.length > 0 ? toAliasPath(validDestPath) : args.newFilePath; return `Successfully copied ${sourceAliasPath} to ${destAliasPath}`; } default: throw new Error(`Unknown file action: ${args.action}`); } }

Latest Blog Posts

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/MartinSchlott/BetterMCPFileServer'

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