write_file
Write content to a specified file on the Filesystem MCP Server. Creates or overwrites the file and necessary directories based on provided relative or absolute paths.
Instructions
Writes content to a specified file. Creates the file (and necessary directories) if it doesn't exist, or overwrites it if it does. Accepts relative or absolute paths (resolved like readFile).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The content to write to the file. If the file exists, it will be overwritten. | |
| path | Yes | The path to the file to write. Can be relative or absolute. If relative, it resolves against the path set by `set_filesystem_default`. If absolute, it is used directly. Missing directories will be created. |
Implementation Reference
- Core handler function that executes the write_file tool logic: resolves the input path using serverState.resolvePath, checks if it's not a directory, creates parent directories if needed, writes the content using fs.promises.writeFile, logs progress, handles errors with McpError, and returns success details including bytes written.export const writeFileLogic = async (input: WriteFileInput, context: RequestContext): Promise<WriteFileOutput> => { const { path: requestedPath, content } = input; logger.debug(`writeFileLogic: Received request for path "${requestedPath}"`, context); // Resolve the path using serverState (handles relative/absolute logic and sanitization) const absolutePath = serverState.resolvePath(requestedPath, context); logger.debug(`writeFileLogic: Resolved path to "${absolutePath}"`, { ...context, requestedPath }); try { // Ensure the target path is not a directory before attempting to write try { const stats = await fs.stat(absolutePath); if (stats.isDirectory()) { logger.warning(`writeFileLogic: Attempted to write to a directory path "${absolutePath}"`, { ...context, requestedPath }); throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Cannot write file. Path exists and is a directory: ${absolutePath}`, { ...context, requestedPath, resolvedPath: absolutePath }); } } catch (statError: any) { // ENOENT (file/dir doesn't exist) is expected and okay, we'll create it. // Other errors during stat (like permission issues) should be thrown. if (statError.code !== 'ENOENT') { throw statError; // Re-throw other stat errors } // If ENOENT, proceed to create directory and file logger.debug(`writeFileLogic: Path "${absolutePath}" does not exist, will create.`, { ...context, requestedPath }); } // Ensure the directory exists before writing the file const dirName = path.dirname(absolutePath); logger.debug(`writeFileLogic: Ensuring directory "${dirName}" exists`, { ...context, requestedPath, resolvedPath: absolutePath }); await fs.mkdir(dirName, { recursive: true }); logger.debug(`writeFileLogic: Directory "${dirName}" confirmed/created`, { ...context, requestedPath, resolvedPath: absolutePath }); // Write the file content logger.debug(`writeFileLogic: Writing content to "${absolutePath}"`, { ...context, requestedPath }); await fs.writeFile(absolutePath, content, 'utf8'); const bytesWritten = Buffer.byteLength(content, 'utf8'); logger.info(`writeFileLogic: Successfully wrote ${bytesWritten} bytes to "${absolutePath}"`, { ...context, requestedPath }); return { message: `Successfully wrote content to ${absolutePath}`, writtenPath: absolutePath, bytesWritten: bytesWritten, }; } catch (error: any) { logger.error(`writeFileLogic: Error writing file to "${absolutePath}"`, { ...context, requestedPath, error: error.message, code: error.code }); // Handle specific file system errors if (error instanceof McpError) { throw error; // Re-throw McpErrors (like the directory check) } // Handle potential I/O errors during mkdir or writeFile throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to write file: ${error.message || 'Unknown I/O error'}`, { ...context, requestedPath, resolvedPath: absolutePath, originalError: error }); } };
- Zod schema defining the input parameters for the write_file tool: 'path' (string, required) and 'content' (string).export const WriteFileInputSchema = z.object({ path: z.string().min(1, 'Path cannot be empty') .describe('The path to the file to write. Can be relative or absolute. If relative, it resolves against the path set by `set_filesystem_default`. If absolute, it is used directly. Missing directories will be created.'), content: z.string() // Allow empty content .describe('The content to write to the file. If the file exists, it will be overwritten.'), });
- src/mcp-server/tools/writeFile/registration.ts:19-62 (registration)Function that registers the 'write_file' tool with the MCP server using server.tool(), providing tool name, description, input schema, and an inline handler that calls the core writeFileLogic function, handles logging and error wrapping.export const registerWriteFileTool = async (server: McpServer): Promise<void> => { const registrationContext = requestContextService.createRequestContext({ operation: 'RegisterWriteFileTool' }); logger.info("Attempting to register 'write_file' tool", registrationContext); await ErrorHandler.tryCatch( async () => { server.tool( 'write_file', // Tool name 'Writes content to a specified file. Creates the file (and necessary directories) if it doesn\'t exist, or overwrites it if it does. Accepts relative or absolute paths (resolved like readFile).', // Description WriteFileInputSchema.shape, // Pass the schema shape async (params, extra) => { const typedParams = params as WriteFileInput; const callContext = requestContextService.createRequestContext({ operation: 'WriteFileToolExecution', parentId: registrationContext.requestId }); logger.info(`Executing 'write_file' tool for path: ${typedParams.path}`, callContext); // ErrorHandler will catch McpErrors thrown by the logic const result = await ErrorHandler.tryCatch( () => writeFileLogic(typedParams, callContext), { operation: 'writeFileLogic', context: callContext, input: { path: typedParams.path, content: '[CONTENT REDACTED]' }, // Redact content for logging errorCode: BaseErrorCode.INTERNAL_ERROR } ); logger.info(`Successfully executed 'write_file' for path: ${result.writtenPath}`, callContext); // Format the successful response return { content: [{ type: 'text', text: result.message }], }; } ); logger.info("'write_file' tool registered successfully", registrationContext); }, { operation: 'registerWriteFileTool', context: registrationContext, errorCode: BaseErrorCode.CONFIGURATION_ERROR, critical: true } ); };
- src/mcp-server/server.ts:81-95 (registration)Top-level call to registerWriteFileTool(server) as part of the array of all filesystem tool registrations during server initialization in createMcpServerInstance.const registrationPromises = [ registerReadFileTool(server), registerSetFilesystemDefaultTool(server), registerWriteFileTool(server), registerUpdateFileTool(server), registerListFilesTool(server), registerDeleteFileTool(server), registerDeleteDirectoryTool(server), registerCreateDirectoryTool(server), registerMovePathTool(server), registerCopyPathTool(server) ]; await Promise.all(registrationPromises); logger.info("Filesystem tools registered successfully", context);