Skip to content

feature: add optional content_base64 to write_file to eliminate JSON escaping failures from LLM agents #4394

@Ev3lynx727

Description

@Ev3lynx727

Summary

Add an optional content_base64 parameter to write_file so LLM agents can bypass JSON string escaping failures when content contains quotes, backticks, or special characters.

Problem

write_file accepts content as z.string(). When an LLM generates the tool call JSON, content with ", `, or ${} often results in malformed JSON → parse error → retry loop.

Token Cost (10KB doc)

Retries Calls Tokens vs base64
0 1 3,770 +52%
1 2 7,590 -24%
2 3 11,410 -50%
4 5 19,050 -70% (3.3×)

Breakeven is sub-1 retry. Content with quotes/backticks almost always triggers the problem.

Full analysis: https://github.com/Ev3lynx727/server-commands-rtk/blob/develop/docs/references/000_user_experiences.md

Proposed Fix

WriteFileArgsSchema = z.object({
  path: z.string(),
  content: z.string().optional(),
  content_base64: z.string().optional(),
}).refine(
  args => args.content !== undefined || args.content_base64 !== undefined,
  "Must provide either content or content_base64"
);

When content_base64 is provided, decode server-side:

const content = args.content_base64
  ? Buffer.from(args.content_base64, 'base64').toString('utf-8')
  : args.content;
await writeFileContent(validPath, content);

Base64 charset (A-Za-z0-9+/=) is fully JSON-safe. The server already uses base64 for read_media_file (readFileAsBase64Stream), so zero new dependencies.

Bonus: Binary writes

content: string makes binary writes impossible. content_base64 enables them:

const buffer = Buffer.from(args.content_base64, 'base64');
await fs.writeFile(validPath, buffer);

Scope

Tool Current Proposed
write_file content: string Add content_base64?: string
edit_file newText: string Add newText_base64?: string

Prior art

  • server-commands-rtk write_file tool (Node.js, MCP SDK): implements this exact pattern

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions