Skip to main content
Glama

Filesystem MCP Server

writeFileLogic.ts4.79 kB
import fs from 'fs/promises'; import path from 'path'; import { z } from 'zod'; import { BaseErrorCode, McpError } from '../../../types-global/errors.js'; import { logger } from '../../../utils/internal/logger.js'; import { RequestContext } from '../../../utils/internal/requestContext.js'; import { serverState } from '../../state.js'; // Import serverState for path resolution // Define the input schema using Zod for validation 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.'), }); // Define the TypeScript type for the input export type WriteFileInput = z.infer<typeof WriteFileInputSchema>; // Define the TypeScript type for the output (simple success message) export interface WriteFileOutput { message: string; writtenPath: string; bytesWritten: number; } /** * Writes content to a specified file, overwriting it if it exists, * and creating necessary directories. * * @param {WriteFileInput} input - The input object containing the file path and content. * @param {RequestContext} context - The request context for logging and error handling. * @returns {Promise<WriteFileOutput>} A promise that resolves with a success message, the path written to, and bytes written. * @throws {McpError} Throws McpError for path resolution errors, I/O errors, or if the path resolves to a directory. */ 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 }); } };

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/cyanheads/filesystem-mcp-server'

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