Skip to main content
Glama
ConnorBoetig-dev

Unrestricted Development MCP Server

filesystem.ts17.1 kB
import { z } from 'zod'; import fs from 'fs/promises'; import fsSync from 'fs'; import path from 'path'; /** * Filesystem Tools * Provides unrestricted access to read, write, delete, and manipulate files and directories */ // ========== TOOL SCHEMAS ========== export const readFileSchema = z.object({ path: z.string().describe('Absolute or relative path to the file to read'), encoding: z.enum(['utf8', 'binary', 'base64']).default('utf8').describe('File encoding') }); export const writeFileSchema = z.object({ path: z.string().describe('Absolute or relative path to the file to write'), content: z.string().describe('Content to write to the file'), encoding: z.enum(['utf8', 'binary', 'base64']).default('utf8').describe('File encoding'), createDirs: z.boolean().default(true).describe('Create parent directories if they don\'t exist') }); export const appendFileSchema = z.object({ path: z.string().describe('Absolute or relative path to the file'), content: z.string().describe('Content to append to the file'), encoding: z.enum(['utf8', 'binary', 'base64']).default('utf8').describe('File encoding') }); export const deleteFileSchema = z.object({ path: z.string().describe('Absolute or relative path to the file to delete') }); export const listDirectorySchema = z.object({ path: z.string().describe('Absolute or relative path to the directory'), recursive: z.boolean().default(false).describe('List subdirectories recursively'), showHidden: z.boolean().default(false).describe('Show hidden files (starting with .)') }); export const createDirectorySchema = z.object({ path: z.string().describe('Absolute or relative path to the directory to create'), recursive: z.boolean().default(true).describe('Create parent directories if they don\'t exist') }); export const deleteDirectorySchema = z.object({ path: z.string().describe('Absolute or relative path to the directory to delete'), recursive: z.boolean().default(false).describe('Delete directory and all contents recursively') }); export const getFileInfoSchema = z.object({ path: z.string().describe('Absolute or relative path to the file or directory') }); export const moveFileSchema = z.object({ source: z.string().describe('Source path'), destination: z.string().describe('Destination path') }); export const copyFileSchema = z.object({ source: z.string().describe('Source path'), destination: z.string().describe('Destination path') }); // ========== TOOL IMPLEMENTATIONS ========== type ToolResponse = { content: Array<{ type: "text"; text: string }>; isError?: boolean; }; export async function readFile(args: z.infer<typeof readFileSchema>): Promise<ToolResponse> { try { const content = await fs.readFile(args.path, args.encoding as BufferEncoding); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, content: content, size: content.length }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function writeFile(args: z.infer<typeof writeFileSchema>): Promise<ToolResponse> { try { // Create parent directories if needed if (args.createDirs) { const dir = path.dirname(args.path); await fs.mkdir(dir, { recursive: true }); } await fs.writeFile(args.path, args.content, args.encoding as BufferEncoding); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, bytesWritten: args.content.length }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function appendFile(args: z.infer<typeof appendFileSchema>): Promise<ToolResponse> { try { await fs.appendFile(args.path, args.content, args.encoding as BufferEncoding); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, bytesAppended: args.content.length }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function deleteFile(args: z.infer<typeof deleteFileSchema>): Promise<ToolResponse> { try { await fs.unlink(args.path); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, message: 'File deleted successfully' }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function listDirectory(args: z.infer<typeof listDirectorySchema>): Promise<ToolResponse> { try { const entries = await fs.readdir(args.path, { withFileTypes: true }); let files: any[] = []; for (const entry of entries) { // Skip hidden files if not requested if (!args.showHidden && entry.name.startsWith('.')) { continue; } const fullPath = path.join(args.path, entry.name); const stats = await fs.stat(fullPath); const fileInfo = { name: entry.name, path: fullPath, type: entry.isDirectory() ? 'directory' : entry.isSymbolicLink() ? 'symlink' : 'file', size: stats.size, modified: stats.mtime, permissions: stats.mode }; files.push(fileInfo); // Recurse into subdirectories if requested if (args.recursive && entry.isDirectory()) { const subResult = await listDirectory({ path: fullPath, recursive: true, showHidden: args.showHidden }); // Parse the sub-result and add to files const subData = JSON.parse(subResult.content[0].text); if (subData.success) { files = files.concat(subData.entries); } } } return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, count: files.length, entries: files }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function createDirectory(args: z.infer<typeof createDirectorySchema>): Promise<ToolResponse> { try { await fs.mkdir(args.path, { recursive: args.recursive }); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, message: 'Directory created successfully' }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function deleteDirectory(args: z.infer<typeof deleteDirectorySchema>): Promise<ToolResponse> { try { if (args.recursive) { await fs.rm(args.path, { recursive: true, force: true }); } else { await fs.rmdir(args.path); } return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, message: 'Directory deleted successfully' }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function getFileInfo(args: z.infer<typeof getFileInfoSchema>): Promise<ToolResponse> { try { const stats = await fs.stat(args.path); const realPath = await fs.realpath(args.path); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, path: args.path, realPath: realPath, type: stats.isDirectory() ? 'directory' : stats.isSymbolicLink() ? 'symlink' : 'file', size: stats.size, created: stats.birthtime, modified: stats.mtime, accessed: stats.atime, permissions: stats.mode.toString(8), uid: stats.uid, gid: stats.gid }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function moveFile(args: z.infer<typeof moveFileSchema>): Promise<ToolResponse> { try { await fs.rename(args.source, args.destination); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, source: args.source, destination: args.destination, message: 'File/directory moved successfully' }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } export async function copyFile(args: z.infer<typeof copyFileSchema>): Promise<ToolResponse> { try { await fs.copyFile(args.source, args.destination); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, source: args.source, destination: args.destination, message: 'File copied successfully' }, null, 2) } ] }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } // ========== TOOL DEFINITIONS FOR MCP ========== export const filesystemTools = [ { name: 'fs_read_file', description: 'Read the contents of a file from the filesystem. Supports text and binary files.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the file to read' }, encoding: { type: 'string', enum: ['utf8', 'binary', 'base64'], default: 'utf8', description: 'File encoding' } }, required: ['path'] } }, { name: 'fs_write_file', description: 'Write content to a file. Creates the file if it doesn\'t exist, overwrites if it does. Can create parent directories.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the file to write' }, content: { type: 'string', description: 'Content to write to the file' }, encoding: { type: 'string', enum: ['utf8', 'binary', 'base64'], default: 'utf8', description: 'File encoding' }, createDirs: { type: 'boolean', default: true, description: 'Create parent directories if they don\'t exist' } }, required: ['path', 'content'] } }, { name: 'fs_append_file', description: 'Append content to an existing file. Creates the file if it doesn\'t exist.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the file' }, content: { type: 'string', description: 'Content to append to the file' }, encoding: { type: 'string', enum: ['utf8', 'binary', 'base64'], default: 'utf8', description: 'File encoding' } }, required: ['path', 'content'] } }, { name: 'fs_delete_file', description: 'Delete a file from the filesystem. This operation is irreversible.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the file to delete' } }, required: ['path'] } }, { name: 'fs_list_directory', description: 'List contents of a directory with detailed information about each entry (name, type, size, permissions, etc.)', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the directory' }, recursive: { type: 'boolean', default: false, description: 'List subdirectories recursively' }, showHidden: { type: 'boolean', default: false, description: 'Show hidden files (starting with .)' } }, required: ['path'] } }, { name: 'fs_create_directory', description: 'Create a new directory. Can create parent directories if they don\'t exist.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the directory to create' }, recursive: { type: 'boolean', default: true, description: 'Create parent directories if they don\'t exist' } }, required: ['path'] } }, { name: 'fs_delete_directory', description: 'Delete a directory. Can recursively delete all contents. WARNING: Use with caution as this is irreversible.', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the directory to delete' }, recursive: { type: 'boolean', default: false, description: 'Delete directory and all contents recursively' } }, required: ['path'] } }, { name: 'fs_get_file_info', description: 'Get detailed information about a file or directory (size, permissions, timestamps, etc.)', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute or relative path to the file or directory' } }, required: ['path'] } }, { name: 'fs_move_file', description: 'Move or rename a file or directory', inputSchema: { type: 'object', properties: { source: { type: 'string', description: 'Source path' }, destination: { type: 'string', description: 'Destination path' } }, required: ['source', 'destination'] } }, { name: 'fs_copy_file', description: 'Copy a file to a new location', inputSchema: { type: 'object', properties: { source: { type: 'string', description: 'Source path' }, destination: { type: 'string', description: 'Destination path' } }, required: ['source', 'destination'] } } ];

Implementation Reference

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/ConnorBoetig-dev/mcp2'

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