copy
Copy files while preserving metadata and performing safety checks to prevent data loss.
Instructions
Copy files with metadata preservation and safety checks
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| from | Yes | Source file path (required) | |
| to | Yes | Destination file path (required) | |
| overwrite | No | Allow overwriting existing files (default: false) |
Implementation Reference
- servers/file-mcp/tools/copy.ts:39-103 (handler)The main handler function that executes the copy tool logic, including input validation with Zod, security checks for paths and gitignore, existence checks, directory creation, and file copy with metadata preservation using node:fs/promises copyFile, utimes, and chmod.
async execute(args: any): Promise<any> { try { // Validate and parse input using Zod schema const validatedArgs = CopyToolInputSchema.parse(args); const { from: fromPath, to: toPath, overwrite } = validatedArgs; // Resolve absolute paths const fromResolved = resolve(fromPath); const toResolved = resolve(toPath); // Security checks this.validateCurrentDirectoryBounds(fromResolved, toResolved); if (PathSecurity.isDangerousFile(fromPath) || PathSecurity.isDangerousFile(toPath)) { throw new Error( `Security protection: Cannot operate on dangerous files (${fromPath} → ${toPath})` ); } if ( (await PathSecurity.isIgnoredByGit(fromResolved)) || (await PathSecurity.isIgnoredByGit(toResolved)) ) { throw new Error( `gitignore protection: Cannot operate on ignored files (${fromPath} → ${toPath})` ); } // Check if source exists try { await access(fromResolved); } catch { throw new Error(`Source file not found: ${fromPath}`); } // Check if destination exists const destinationExists = await this.checkDestinationExists(toResolved); // Smart dryRun control if (destinationExists && !overwrite) { const destStats = await stat(toResolved); const destSize = Math.round((destStats.size / 1024) * 100) / 100; throw new Error( `Destination already exists: ${toPath} (${destSize}KB, modified ${destStats.mtime.toISOString().split("T")[0]}). Copy operation would overwrite this file. Use overwrite=true to force overwrite or choose a different destination path.` ); } // Ensure destination directory exists await this.ensureDestinationDirectory(toResolved); // Perform copy operation await this.performCopy(fromResolved, toResolved); const message = destinationExists ? `✅ Successfully copied (overwrote existing): ${fromPath} → ${toPath}` : `✅ Successfully copied: ${fromPath} → ${toPath}`; return ResultFormatter.createResponse(message); } catch (error: any) { // Handle Zod validation errors if (error instanceof Error && error.name === "ZodError") { throw ToolError.createValidationError("input", args, `Invalid input: ${error.message}`); } throw ToolError.wrapError("Copy operation", error); } } - servers/file-mcp/tools/copy.ts:13-37 (schema)MCP tool definition including name, description, and JSON input schema for the copy tool.
getDefinition(): Tool { return { name: "copy", description: "Copy files with metadata preservation and safety checks", inputSchema: { type: "object", properties: { from: { type: "string", description: "Source file path (required)", }, to: { type: "string", description: "Destination file path (required)", }, overwrite: { type: "boolean", description: "Allow overwriting existing files (default: false)", default: false, }, }, required: ["from", "to"], }, }; } - servers/file-mcp/index.ts:122-123 (registration)Tool dispatch registration in the handleToolCall switch statement, routing 'copy' calls to CopyTool.execute.
case "copy": return await this.copyTool.execute(args); - servers/file-mcp/index.ts:87-87 (registration)Instantiation of CopyTool instance in FileMCPServer constructor.
this.copyTool = new CopyTool(); - Zod schema used internally for input validation in CopyTool.execute.
// Copy tool input schema export const CopyToolInputSchema = z.object({ from: FilePathSchema, to: FilePathSchema, overwrite: BooleanFlagSchema, });