Skip to main content
Glama

Write file

write_file

Write 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

TableJSON Schema
NameRequiredDescriptionDefault
pathYes
contentYes
encodingNoutf-8
createDirsNo

Implementation Reference

  • 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;
    }
  • 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,
    }),
  • 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)}`);
        }
      }
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It discloses atomic write behavior and the temp file rename mechanism, which are critical for safe use. However, it omits details like overwrite behavior, permissions, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence. It front-loads the core purpose ('Write a file atomically') and adds a parenthetical detail. Every part is informative with no waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 4 parameters, no output schema, and no annotations, the description is incomplete. It does not explain parameters, return value, or error conditions. The atomicity info is valuable but insufficient for a complete understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description does not explain any parameters. It does not clarify that path is required, content is data to write, or the meaning of encoding and createDirs. This is a significant gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool writes a file atomically within a configured scope, using a temp file then rename. It distinguishes from siblings like read_file by specifying write and atomicity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use for writing files atomically, but does not explicitly provide when-to-use vs alternatives or exclusions. The atomicity note offers some guidance for concurrent safe writes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/marin1321/mcp-devtools'

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