fileSystem_tool
Manage file systems across platforms using read, write, copy, move, delete, list, chmod, chown, and size operations with recursive and overwrite options.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| fileMode | No | File mode (permissions) in octal format (e.g., 755) | |
| gid | No | Group ID for chown operation | |
| operation | Yes | File system operation (read, write, copy, etc.) | |
| overwrite | No | Overwrite existing files during copy/move | |
| platformOverride | No | Override platform for OS behavior simulation | auto |
| recursive | No | Recursively apply operation to directories | |
| showHidden | No | Include hidden files/directories in list/listDetails | |
| sourcePath | Yes | Absolute path to source | |
| targetPath | No | Absolute path to target (required for copy/move) | |
| uid | No | User ID for chown operation |
Implementation Reference
- src/tools/fileSystem_tool.ts:60-187 (handler)The default exported async function implementing the core logic of fileSystem_tool, handling operations like read, write, copy, move, delete, list, chmod, chown, and getSize with path safety checks.export default async function(request: any) { try { const { operation, sourcePath, targetPath, content, recursive, overwrite, showHidden, fileMode, uid, gid } = request.params.arguments; const basePath = process.cwd(); const isSafePath = (userPath: string | undefined) => { if (!userPath) return true; // Allow targetPath to be optional const resolvedPath = path.resolve(basePath, userPath); return resolvedPath.startsWith(basePath); }; if (!isSafePath(sourcePath)) { throw new Error(`源路径 "${sourcePath}" 超出了允许的操作目录。`); } if (!isSafePath(targetPath)) { throw new Error(`目标路径 "${targetPath}" 超出了允许的操作目录。`); } switch (operation) { case "read": { const data = await fs.readFile(sourcePath, 'utf-8'); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; } case "write": { if (content === undefined) { throw new Error('执行 "write" 操作必须提供 "content" 参数。'); } await fs.writeFile(sourcePath, content, 'utf-8'); return { content: [{ type: "text", text: `文件已成功写入到 ${sourcePath}` }] }; } case "copy": { if (!targetPath) { throw new Error("执行 'copy' 操作必须提供 'targetPath' 参数。"); } await fs.copy(sourcePath, targetPath, { overwrite }); return { content: [{ type: "text", text: `文件已成功从 ${sourcePath} 复制到 ${targetPath}` }] }; } case "move": { if (!targetPath) { throw new Error("执行 'move' 操作必须提供 'targetPath' 参数。"); } await fs.move(sourcePath, targetPath, { overwrite }); return { content: [{ type: "text", text: `文件已成功从 ${sourcePath} 移动到 ${targetPath}` }] }; } case "delete": { await fs.remove(sourcePath); return { content: [{ type: "text", text: `文件 ${sourcePath} 已被成功删除。` }] }; } case "list": { const files = await fs.readdir(sourcePath); // TODO: Implement showHidden filter return { content: [{ type: "text", text: JSON.stringify(files, null, 2) }] }; } case "listDetails": { const files = await fs.readdir(sourcePath); const fileDetails = await Promise.all( files.map(async (file) => { const filePath = path.join(sourcePath, file); const stat = await fs.stat(filePath); return { name: file, type: stat.isFile() ? "file" : stat.isDirectory() ? "directory" : "unknown", size: stat.size, modified: stat.mtime, permissions: stat.mode.toString(8), }; }) ); // TODO: Implement showHidden filter return { content: [{ type: "text", text: JSON.stringify(fileDetails, null, 2) }] }; } case "chmod": { if (!fileMode) { throw new Error("执行 'chmod' 操作必须提供 'fileMode' 参数。"); } await fs.chmod(sourcePath, fileMode); return { content: [{ type: "text", text: `文件权限已成功修改为 ${fileMode}` }] }; } case "chown": { if (uid === undefined || gid === undefined) { throw new Error("执行 'chown' 操作必须同时提供 'uid' 和 'gid' 参数。"); } await fs.chown(sourcePath, uid, gid); return { content: [{ type: "text", text: `文件所有者已成功变更为 UID: ${uid}, GID: ${gid}` }] }; } case "getSize": { const stat = await fs.stat(sourcePath); let totalSize = stat.size; if (stat.isDirectory() && recursive) { // Note: This is a simplified size calculation for the top-level directory. const files = await fs.readdir(sourcePath); totalSize = (await Promise.all(files.map(async file => { const childPath = path.join(sourcePath, file); const childStat = await fs.stat(childPath); return childStat.size; // Simplified: doesn't recurse into subdirectories }))).reduce((a, b) => a + b, stat.size); } return { content: [{ type: "text", text: `路径 ${sourcePath} 的总大小为: ${totalSize} 字节` }] }; } default: throw new Error(`不支持的操作: ${operation}`); } } catch (error) { return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } }
- src/tools/fileSystem_tool.ts:5-57 (schema)The schema defining the input parameters, types, and requirements for the fileSystem_tool.export const schema = { name: "fileSystem_tool", description: "一个强大的文件系统工具,用于执行读、写、复制、移动、删除、列表等操作。", type: "object", properties: { operation: { type: "string", enum: ["read", "write", "copy", "move", "delete", "list", "listDetails", "chmod", "chown", "getSize"], description: "要执行的文件系统操作 (例如: read, write, copy)" }, sourcePath: { type: "string", description: "源文件的绝对路径" }, targetPath: { type: "string", description: "目标文件的绝对路径 (用于 copy/move 操作)" }, content: { type: "string", description: "要写入文件的内容 (用于 'write' 操作)" }, recursive: { type: "boolean", default: false, description: "递归地对目录应用操作" }, overwrite: { type: "boolean", default: false, description: "在 copy/move 操作中覆盖已存在的文件" }, showHidden: { type: "boolean", default: false, description: "在 list/listDetails 中包含隐藏文件/目录" }, fileMode: { type: "string", pattern: "^[0-7]{3,4}$", description: "文件模式(权限),使用八进制格式 (例如, 755)" }, uid: { type: "number", description: "用于 chown 操作的用户 ID" }, gid: { type: "number", description: "用于 chown 操作的组 ID" } }, required: ["operation", "sourcePath"] };
- src/handler/ToolHandler.ts:91-139 (registration)Dynamic loading and registration of fileSystem_tool (and other tools) from src/tools directory using filename as tool name, importing default handler, schema, and destroy function.export async function loadTools(reload: boolean = false): Promise<{ [key: string]: (request: ToolRequest) => Promise<ToolResponse> }> { // 如果是初始加载且已加载,则直接返回 if (!reload && isLoaded) return; // 如果是重新加载,则重置状态 if (reload) { for (const tool of tools) { await tool?.destroy?.(); delete handlers[tool.name]; } tools.length = 0; isLoaded = false; } // 获取所有工具文件 const toolFiles = fs.readdirSync(toolsDir).filter(file => file.endsWith('.js') || file.endsWith('.ts')); // 加载每个工具 for (const file of toolFiles) { const toolPath = path.join(toolsDir, file); try { // 如果是重新加载,清除模块缓存 if (reload) clearModuleCache(toolPath); // 导入模块,重新加载时添加时间戳防止缓存 const importPath = 'file://' + toolPath + (reload ? `?update=${Date.now()}` : ''); const { default: tool, schema, destroy } = await import(importPath); const toolName = path.parse(toolPath).name; // 注册工具 tools.push({ name: toolName, description: tool.description, inputSchema: schema, destroy: destroy }); // 注册处理函数 handlers[toolName] = async (request: ToolRequest) => { return await tool(request); }; } catch (error) { console.error(`Failed to ${reload ? 'reload' : 'load'} tool ${file}:`, error); } } isLoaded = true; if (reload) console.log(`Successfully reloaded ${tools.length} tools`); return handlers; }
- src/tools/fileSystem_tool.ts:190-192 (helper)Cleanup function called during tool reload or unload.export async function destroy() { console.log("Destroy fileSystem_tool"); }