Write file
write_fileWrite a file atomically within a configured scope. Ensures data integrity by writing to a temporary file then renaming. Supports custom encoding and automatic directory creation.
Instructions
Write a file atomically inside the configured scope (writes to a temp file then renames).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| content | Yes | ||
| encoding | No | utf-8 | |
| createDirs | No |
Implementation Reference
- src/tools/filesystem/write-file.ts:42-69 (handler)The main handler function for the write_file tool. It performs an atomic file write by writing to a temp file then renaming. Validates the path is within scope, ensures parent directory exists (optionally creating it), refuses to overwrite directories, encodes the payload, and returns path/bytesWritten/created status.
export async function writeFileHandler( input: WriteFileInput, config: McpDevtoolsConfig, ): Promise<ToolResult<WriteFileOutput>> { const target = assertWithinScope(config.scope, input.path); const parent = path.dirname(target); await ensureParent(parent, input.createDirs); await ensureTargetIsNotDirectory(target); const created = !(await pathExists(target)); const payload = encodePayload(input.content, input.encoding); const tmpPath = `${target}.tmp.${process.pid}.${randomBytes(8).toString("hex")}`; try { await writeFile(tmpPath, payload); await rename(tmpPath, target); } catch (error) { await unlinkSafe(tmpPath); throw mapFsError(error, target); } return ok({ path: input.path, bytesWritten: payload.length, created, }); } - Zod input schema (WriteFileInput) and output interface (WriteFileOutput). Input accepts: path (string), content (string), encoding (utf8/ascii/base64/hex, default utf-8), createDirs (boolean, default false). Output returns: path, bytesWritten, created flag.
export const WriteFileInput = z.object({ path: z.string().min(1), content: z.string(), encoding: z.enum(["utf8", "utf-8", "ascii", "base64", "hex"]).default("utf-8"), createDirs: z.boolean().default(false), }); export type WriteFileInput = z.infer<typeof WriteFileInput>; export interface WriteFileOutput { path: string; bytesWritten: number; created: boolean; } - src/tools/index.ts:60-67 (registration)Registration of the write_file tool in the allTools array using defineTool(). Maps the name 'write_file' to WriteFileInput schema and writeFileHandler handler.
defineTool({ name: "write_file", title: "Write file", description: "Write a file atomically inside the configured scope (writes to a temp file then renames).", inputSchema: WriteFileInput, handler: writeFileHandler, }), - src/tools/filesystem/_utils.ts:36-47 (helper)Helper function assertWithinScope used by write_file to perform a synchronous, no-IO scope check on the target path (the path may not exist yet, so no symlink following).
export function assertWithinScope(scopeRoot: string, candidate: string): string { validateInputPath(candidate); const absoluteScope = path.resolve(scopeRoot); const resolved = path.resolve(absoluteScope, candidate); if (!isWithinPath(absoluteScope, resolved)) { throw new ScopeViolationError(`Path is outside the configured scope: ${candidate}`, { scope: absoluteScope, requested: resolved, }); } return resolved; } - Helper function encodePayload that converts the string content to a Buffer based on the requested encoding (utf8, ascii, base64, hex), with validation for base64 and hex.
function encodePayload(content: string, encoding: WriteFileInput["encoding"]): Buffer { switch (encoding) { case "utf8": case "utf-8": return Buffer.from(content, "utf-8"); case "ascii": return Buffer.from(content, "ascii"); case "base64": try { return Buffer.from(content, "base64"); } catch { throw new ValidationError("Invalid base64 content"); } case "hex": try { return Buffer.from(content, "hex"); } catch { throw new ValidationError("Invalid hex content"); } default: { const exhaustive: never = encoding; throw new ValidationError(`Unsupported encoding: ${String(exhaustive)}`); } } }