【AI智能体】打造高内聚的 MCP-Filesystem Server

本文假设你已经看过上一篇 Claude Code 工具架构核心解析 ,理解了"权限边界"和"大道至简"的设计哲学。现在我们要把这些最佳实践落地到实际项目中------设计一个高内聚、低耦合的 MCP-Filesystem Server。

前言

基于 Claude Code 的设计理念,本文设计一个 6 个核心工具的 MCP-Filesystem Server,适用于 FastGPT、Dify、Coze 等 AI Agent 平台。

期望实现类似 Google AI Studio、天工(Skywork)、Minimax Agent等工作空间能力。


一、设计目标

基于 Claude Code 的启示,我们的设计目标是:

复制代码
✅ 高内聚:6 个工具,职责清晰
✅ 权限清晰:每个工具是一个权限边界
✅ 语义明确:工具名称直接反映能力
✅ 安全可控:支持权限过滤和审计
✅ 自动格式识别:支持 txt、md、xlsx、json、csv 等

功能覆盖

  • 📁 文件系统:读取、写入、编辑、搜索
  • ⚙️ 代码执行:Python 代码执行
  • 🌐 前端部署:自动构建并部署到预览服务器

二、工具设计方案

基于 Claude Code 的设计理念,我们设计了 6 个核心工具

工具名称 对应 CC 工具 核心职责 权限级别 一句话总结
fs_read Read 读取文件 只读(✅ 安全) 只读,零副作用
fs_write Write 创建/覆盖文件 写入(⚠️ 中等) 语义明确:我就是要覆盖!
fs_edit Edit 精确编辑文件 修改(⚠️ 中等) 局部修改,不动其他内容
fs_search Grep + Glob 搜索文件/内容 只读(✅ 安全) 合并搜索,减少工具数
exec - 执行 Python 代码 执行(⚠️ 中等) 仅支持 Python,安全可控
preview_frontend - 前端项目部署 部署(⚠️ 中等) 自动构建并部署到预览服务器

优势

  • 权限边界清晰:每个工具职责单一
  • 工具数量合理:6 个刚好,不多不少
  • AI 容易选择:语义明确,不会选错
  • 易于管理和使用:配置简洁
  • 功能完整:覆盖文件操作、代码执行、前端部署

这就是我们向 Claude Code 学来的高内聚设计


三、详细设计:6 个工具的完整实现

3.1 工具 1:fs_read(文件读取)

核心原则:只读,零副作用,自动识别格式

工具定义
typescript 复制代码
{
  name: 'fs_read',
  description: '读取文件内容,自动识别格式(txt/xlsx/json/csv/pdf/图片等)',
  inputSchema: {
    type: 'object',
    properties: {
      path: {
        type: 'string',
        description: '文件路径(相对于工作目录)',
        required: true
      },
      format: {
        type: 'string',
        enum: ['auto', 'text', 'xlsx', 'json', 'csv', 'binary'],
        description: '读取格式,默认为 auto(自动识别)',
        default: 'auto'
      },
      sheet: {
        type: 'string',
        description: 'xlsx 文件的 sheet 名称(可选)'
      },
      encoding: {
        type: 'string',
        enum: ['utf-8', 'gbk', 'utf-16'],
        description: '文本编码,默认 utf-8',
        default: 'utf-8'
      }
    }
  }
}
实现要点
  • 路径安全检查(防止路径穿越)
  • 根据文件扩展名自动识别格式
  • 支持 text、json、csv、xlsx 等格式
返回格式示例
json 复制代码
// 文本文件
{
  "content": "Hello World!",
  "format": "text"
}

// JSON 文件
{
  "content": { "name": "Alice", "age": 30 },
  "format": "json"
}

// XLSX 文件
{
  "content": {
    "sheets": ["Sheet1", "Sheet2"],
    "data": [
      ["姓名", "年龄", "城市"],
      ["张三", 30, "北京"],
      ["李四", 25, "上海"]
    ],
    "currentSheet": "Sheet1"
  },
  "format": "xlsx"
}

3.2 工具 2:fs_write(文件创建/覆盖)

核心原则:创建新文件或完全覆盖现有文件,语义明确

工具定义
typescript 复制代码
{
  name: 'fs_write',
  description: '创建新文件或完全覆盖现有文件(支持 txt/xlsx/json/csv 等格式)',
  inputSchema: {
    type: 'object',
    properties: {
      path: {
        type: 'string',
        description: '文件路径(相对于工作目录)',
        required: true
      },
      content: {
        description: '文件内容(根据格式可以是字符串、对象或数组)',
        required: true
      },
      format: {
        type: 'string',
        enum: ['auto', 'text', 'xlsx', 'json', 'csv'],
        description: '写入格式,默认为 auto(根据扩展名自动识别)',
        default: 'auto'
      },
      encoding: {
        type: 'string',
        enum: ['utf-8', 'gbk', 'utf-16'],
        description: '文本编码,默认 utf-8',
        default: 'utf-8'
      }
    }
  }
}
实现要点
  • 自动创建目录
  • 根据扩展名自动识别格式并写入
  • 支持 text、json、csv、xlsx 等格式

3.3 工具 3:fs_edit(精确编辑)

核心原则:精确修改文件的特定部分,避免全文覆盖

支持模式

  • replace:字符串替换
  • line_range:按行编辑
  • xlsx_cell:xlsx 单元格编辑
工具定义
typescript 复制代码
{
  name: 'fs_edit',
  description: '精确编辑文件的特定部分(支持按行编辑、字符串替换、xlsx 单元格编辑)',
  inputSchema: {
    type: 'object',
    properties: {
      path: {
        type: 'string',
        description: '文件路径(相对于工作目录)',
        required: true
      },
      editType: {
        type: 'string',
        enum: ['replace', 'line_range', 'xlsx_cell'],
        description: '编辑类型',
        required: true
      },
      // replace 模式参数
      oldContent: {
        type: 'string',
        description: '要替换的内容(editType=replace 时必需)'
      },
      newContent: {
        type: 'string',
        description: '新内容(editType=replace 时必需)'
      },
      replaceAll: {
        type: 'boolean',
        description: '是否替换所有匹配(默认 false,只替换第一个)',
        default: false
      },
      // line_range 模式参数
      startLine: {
        type: 'number',
        description: '起始行号(从 1 开始,editType=line_range 时必需)'
      },
      endLine: {
        type: 'number',
        description: '结束行号(editType=line_range 时必需)'
      },
      lineContent: {
        type: 'string',
        description: '新的行内容(editType=line_range 时必需)'
      },
      // xlsx_cell 模式参数
      sheet: {
        type: 'string',
        description: 'sheet 名称(editType=xlsx_cell 时可选)'
      },
      cell: {
        type: 'string',
        description: '单元格地址(如 "A1",editType=xlsx_cell 时必需)'
      },
      value: {
        description: '单元格的新值(editType=xlsx_cell 时必需)'
      }
    }
  }
}
实现示例(Python - 核心部分)

注:以下为 Python 实现示例,MCP Server 可以使用任何语言实现

python 复制代码
async function fs_edit(params: {
  path: string;
  editType: 'replace' | 'line_range' | 'xlsx_cell';
  // ...其他参数
}): Promise<{ success: boolean; message: string }> {
  const { path: filePath, editType } = params;

  // 【安全检查】
  const safePath = path.resolve(process.env.WORKSPACE_DIR || '.', filePath);
  if (!safePath.startsWith(process.env.WORKSPACE_DIR || '.')) {
    throw new Error('Access denied: path traversal detected');
  }

  if (!fs.existsSync(safePath)) {
    throw new Error(`File not found: ${filePath}`);
  }

  switch (editType) {
    case 'replace': {
      // 【字符串替换模式】学 Claude Code 的 Edit 工具
      const { oldContent, newContent, replaceAll = false } = params;
      if (!oldContent || newContent === undefined) {
        throw new Error('oldContent and newContent are required for replace mode');
      }

      const content = fs.readFileSync(safePath, 'utf-8');

      // 检查 oldContent 是否唯一(防止误操作)
      const matches = content.split(oldContent).length - 1;
      if (!replaceAll && matches > 1) {
        throw new Error(
          `Found ${matches} matches for oldContent. Use replaceAll=true or provide more context.`
        );
      }

      const newFileContent = replaceAll
        ? content.split(oldContent).join(newContent)
        : content.replace(oldContent, newContent);

      fs.writeFileSync(safePath, newFileContent, 'utf-8');
      return { success: true, message: `Replaced ${replaceAll ? 'all' : '1'} occurrence(s)` };
    }

    case 'line_range': {
      // 【按行编辑模式】适合代码修改
      const { startLine, endLine, lineContent } = params;
      if (!startLine || !endLine || lineContent === undefined) {
        throw new Error('startLine, endLine, and lineContent are required for line_range mode');
      }

      const content = fs.readFileSync(safePath, 'utf-8');
      const lines = content.split('\n');

      // 检查行号范围
      if (startLine < 1 || startLine > lines.length || endLine < 1 || endLine > lines.length) {
        throw new Error(`Invalid line range: ${startLine}-${endLine} (file has ${lines.length} lines)`);
      }

      // 替换行
      lines.splice(startLine - 1, endLine - startLine + 1, lineContent);

      fs.writeFileSync(safePath, lines.join('\n'), 'utf-8');
      return { success: true, message: `Updated lines ${startLine}-${endLine}` };
    }

    case 'xlsx_cell': {
      // 【xlsx 单元格编辑模式】这是我们的特色能力
      const { sheet, cell, value } = params;
      if (!cell || value === undefined) {
        throw new Error('cell and value are required for xlsx_cell mode');
      }

      const workbook = xlsx.readFile(safePath);
      const sheetName = sheet || workbook.SheetNames[0];

      if (!workbook.Sheets[sheetName]) {
        throw new Error(`Sheet not found: ${sheetName}`);
      }

      const worksheet = workbook.Sheets[sheetName];
      worksheet[cell] = { v: value, t: typeof value === 'number' ? 'n' : 's' };

      xlsx.writeFile(workbook, safePath);
      return { success: true, message: `Updated cell ${cell} in sheet ${sheetName}` };
    }

    default:
      throw new Error(`Unsupported editType: ${editType}`);
  }
}

3.4 工具 4:fs_search(文件/内容搜索)

核心原则:合并文件名搜索和内容搜索,减少工具数量

搜索类型

  • filename:使用 glob 模式搜索文件名
  • content:使用正则表达式搜索文件内容
工具定义
typescript 复制代码
{
  name: 'fs_search',
  description: '搜索文件名或文件内容(支持 glob 模式和正则表达式)',
  inputSchema: {
    type: 'object',
    properties: {
      searchType: {
        type: 'string',
        enum: ['filename', 'content'],
        description: '搜索类型:文件名或内容',
        required: true
      },
      pattern: {
        type: 'string',
        description: '搜索模式(filename: glob 模式如 "*.js"; content: 正则表达式)',
        required: true
      },
      path: {
        type: 'string',
        description: '搜索路径(相对于工作目录),默认为整个工作区',
        default: '.'
      },
      caseSensitive: {
        type: 'boolean',
        description: '是否区分大小写(仅 content 搜索有效)',
        default: false
      },
      maxResults: {
        type: 'number',
        description: '最大结果数量,默认 100',
        default: 100
      }
    }
  }
}

3.5 工具 5:exec(Python 代码执行)

核心原则:仅支持 Python,安全可控

使用方式

  • exec(code="print(1 + 1)") - 执行代码字符串
  • exec(file="/greet.py", args=["Alice"]) - 执行 Python 文件
工具定义
python 复制代码
{
  name: 'exec',
  description: '执行 Python 代码或文件',
  inputSchema: {
    type: 'object',
    properties: {
      code: {
        type: 'string',
        description: '要执行的 Python 代码字符串(与 file 二选一)'
      },
      file: {
        type: 'string',
        description: '要执行的 Python 文件路径(相对于工作目录,与 code 二选一)'
      },
      args: {
        type: 'array',
        items: { type: 'string' },
        description: '传递给 Python 文件的命令行参数(仅 file 模式有效)',
        default: []
      },
      cwd: {
        type: 'string',
        description: '工作目录(相对于工作区)',
        default: '.'
      },
      timeout: {
        type: 'number',
        description: '超时时间(毫秒),默认 120000(2分钟)',
        default: 120000
      },
      env: {
        type: 'object',
        description: '环境变量(可选)'
      }
    },
    required: ['code']  # code 和 file 至少需要一个
  }
}
使用示例
python 复制代码
exec(code="print(1 + 1)")
exec(file="/greet.py", args=["Alice"])

3.6 工具 6:preview_frontend(前端项目部署)

核心原则:自动构建并部署前端项目到预览服务器

使用示例

  • preview_frontend("index.html") - 部署简单 HTML
  • preview_frontend("dist/index.html") - 部署构建后的项目
  • preview_frontend("index.html", build_command="npm run build", output_dir="dist") - 自动构建并部署
工具定义
python 复制代码
{
  name: 'preview_frontend',
  description: '部署前端项目到预览服务器',
  inputSchema: {
    type: 'object',
    properties: {
      entry_file: {
        type: 'string',
        description: '入口 HTML 文件路径(相对于工作目录)',
        default: 'index.html'
      },
      build_command: {
        type: 'string',
        description: '构建命令(如 "npm run build"),如果项目已构建可省略',
        default: None
      },
      output_dir: {
        type: 'string',
        description: '构建输出目录(如 "dist"),如果已构建可省略',
        default: None
      }
    },
    required: ['entry_file']
  }
}
使用示例
python 复制代码
preview_frontend(entry_file="index.html")
preview_frontend(entry_file="dist/index.html")
preview_frontend(entry_file="index.html", build_command="npm run build", output_dir="dist")

四、MCP Server 完整实现

由于篇幅原因,完整的 MCP Server 代码(包含目录结构、package.json、入口文件)请移步 GitHub 查阅

GitHub 仓库 (待发布):mcp-filesystem

五、与 Dify / FastGPT / Coze 集成简便

直接在可视化界面引入外部sse格式的mcp-sever即可。


六、最佳实践

工具设计原则

  1. 每个工具是一个权限边界:Read 只读,Write 只写,Edit 只编辑
  2. 语义清晰:工具名称直接反映能力,AI 容易理解
  3. 自动格式识别:减少 AI 选择困难
  4. 安全第一:路径穿越检查、权限验证、超时控制

参考资源

相关推荐
丝斯201134 分钟前
AI学习笔记整理(26)—— 计算机视觉之目标追踪‌
人工智能·笔记·学习
Deepoch36 分钟前
Deepoc-M 破局:半导体研发告别试错内耗
大数据·人工智能·数学建模·半导体·具身模型·deepoc
Debroon1 小时前
Function Call 函数调用高阶方法:从零开始,深入理解 AI 函数调用的核心原理与实战技巧
人工智能
超龄超能程序猿1 小时前
提升文本转SQL(Text-to-SQL)精准度的实践指南
数据库·人工智能·sql
柒柒钏1 小时前
PyTorch学习总结(一)
人工智能·pytorch·学习
金融小师妹1 小时前
基于NLP政策信号解析的联邦基金利率预测:美银动态调整12月降息概率至88%,2026年双降路径的强化学习模拟
大数据·人工智能·深度学习·1024程序员节
MadPrinter1 小时前
FindQC 实战 (三):基于 DrissionPage 的底层攻防与 Decodo 混合架构终局
架构
_山止川行2 小时前
生活
人工智能
是Dream呀2 小时前
昇腾实战 | 昇腾 NPU 异构编程与 GEMM 调优核心方法
人工智能·华为·cann