云计算百科
云计算领域专业知识百科平台

Python MCP实战:从零搭建本地文件系统服务器,让Cursor/Claude自由读取本地项目文件(附完整安全代码)

本文仅用于本地开发学习,MCP服务拥有本地文件读写权限,存在敏感文件泄露、路径穿越风险,请严格遵守以下安全规范:

  • 仅授权AI访问非隐私、无密钥、无配置文件的项目目录,禁止直接扫描系统根目录、用户桌面、数据库密钥文件夹;
  • 代码内置目录白名单校验,生产环境必须开启路径限制,防止../路径穿越攻击;
  • stdio模式仅本地客户端使用,streamable-http HTTP模式禁止公网暴露,仅本地localhost访问;
  • 本教程技术仅供个人开发调试,请勿用于第三方远程文件读取、批量扫描他人设备。
  • 一、前言

    日常使用Cursor、Claude Desktop、VS Code MCP客户端时,AI只能处理对话内粘贴的代码片段,无法直接读取本地项目目录、批量检索源码、统计文件结构、预览日志文件。
    核心原因:AI客户端默认无本地文件系统操作权限,而 MCP(Model Context Protocol 模型上下文协议) 是Anthropic推出的标准化AI本地工具通信协议,相当于AI的通用USB接口,一次开发MCP服务,所有支持MCP的AI客户端均可无缝调用本地文件能力。

    本文基于Python FastMCP SDK,从零实现文件搜索、目录统计、文件预览三大工具,完整兼容Cursor、Claude Desktop,附带安全权限校验、客户端全平台配置教程。

    适用场景

    • 本地项目批量检索py/json配置文件
    • 代码目录结构统计、文件大小汇总
    • 日志、源码快速预览,无需手动打开文件
    • AI自动分析本地项目工程结构

    二、MCP协议通俗原理

    把MCP理解为AI客户端的标准化外设接口:

    类比事物MCP对应概念
    电脑主机 Claude/Cursor/VS Code AI客户端
    U盘/外设 自定义Python本地工具服务
    USB通信标准 MCP(JSON-RPC/Streamable HTTP/stdio)
    即插即用配置 客户端mcpServers配置项

    传统方案:不同AI工具需要单独开发插件、适配各自私有API;
    MCP标准化后:一套MCP服务,全平台AI客户端通用,大幅降低本地工具开发成本。

    三、环境部署

    1. Python版本要求

    Python ≥ 3.10

    # 查看版本
    python3 –version

    2. 安装依赖库

    # MCP官方SDK + HTTP服务框架
    pip install mcp fastapi uvicorn

    依赖说明:

    • mcp:FastMCP官方Python开发库,快速注册AI可调用工具
    • fastapi+uvicorn:提供Streamable HTTP服务传输通道

    3. 项目初始化

    # 创建项目文件夹
    mkdir -p ~/my-file-mcp && cd ~/my-file-mcp

    四、完整MCP服务代码(带安全白名单+详细注释)

    新建 file_scanner.py,增加目录白名单防护,规避路径穿越漏洞:

    """
    本地文件扫描MCP Server(安全加固版)
    功能:文件检索、目录统计、文件内容预览
    安全限制:仅允许访问预设白名单目录,防止路径穿越攻击
    """

    import os
    from pathlib import Path
    from mcp.server.fastmcp import FastMCP

    # ====================== 安全配置:允许访问的目录白名单(自行修改) ======================
    ALLOW_DIRS = [
    Path("~/projects").expanduser(),
    Path("~/code").expanduser()
    ]
    # 转换为绝对路径,用于校验
    ALLOW_ABS = [p.resolve() for p in ALLOW_DIRS]

    # 初始化MCP服务
    mcp = FastMCP(
    "File Scanner",
    description="本地文件系统安全扫描工具,仅读取白名单内目录,支持文件检索、目录统计、源码预览",
    port=8765
    )

    def is_path_safe(target_path: str) > bool:
    """路径安全校验:仅允许访问白名单目录,拦截../路径穿越"""
    target = Path(target_path).resolve()
    # 判断目标路径是否在任一允许目录下
    for safe_dir in ALLOW_ABS:
    if str(target).startswith(str(safe_dir)):
    return True
    return False

    @mcp.tool()
    def search_files(directory: str, pattern: str = "*.py", max_depth: int = 3) > str:
    """
    递归搜索指定目录下匹配后缀的文件
    Args:
    directory: 目标检索目录(必须在白名单内)
    pattern: 文件匹配规则,如 *.py、*.json
    max_depth: 最大递归深度,避免遍历过多文件
    Returns:
    匹配到的文件路径列表
    """

    # 安全校验
    if not is_path_safe(directory):
    return f"权限拒绝:{directory} 不在允许访问目录列表中,请修改ALLOW_DIRS配置"

    base = Path(directory)
    if not base.exists():
    return f"错误:目录不存在 —— {directory}"

    results = []
    try:
    for depth in range(max_depth + 1):
    glob_rule = "**/*" + pattern if depth > 0 else pattern
    for file_path in base.glob(glob_rule):
    if file_path.is_file() and len(results) < 50:
    results.append(str(file_path))
    except Exception as e:
    return f"文件搜索异常:{str(e)}"

    if not results:
    return f"在 {directory} 未匹配到 {pattern} 文件(最大深度{max_depth})"
    return f"共找到 {len(results)} 个文件:\\n" + "\\n".join(results)

    @mcp.tool()
    def dir_stats(path: str) > str:
    """
    统计目录:文件总数、总大小、文件类型分布
    Args:
    path: 目标统计目录
    Returns:
    结构化目录统计报告
    """

    if not is_path_safe(path):
    return f"权限拒绝:{path} 不在允许访问目录列表中"

    p = Path(path)
    if not p.exists():
    return f"错误:路径不存在 —— {path}"

    total_files = 0
    total_size = 0
    ext_count = {}

    for item in p.rglob("*"):
    if item.is_file():
    total_files += 1
    size = item.stat().st_size
    total_size += size
    suffix = item.suffix if item.suffix else "(无后缀)"
    ext_count[suffix] = ext_count.get(suffix, 0) + 1

    # 按文件数量降序排序
    sorted_ext = sorted(ext_count.items(), key=lambda x: x[1])
    lines = [
    f"📁 统计目录:{path}",
    f"📄 文件总数量:{total_files}",
    f"💾 目录总大小:{total_size / 1024:.1f} KB",
    "",
    "前10类文件分布:"
    ]
    for ext, num in sorted_ext[:10]:
    lines.append(f" {ext}{num} 个")
    return "\\n".join(lines)

    @mcp.tool()
    def preview_file(path: str, max_lines: int = 30) > str:
    """
    预览文件前N行内容,避免一次性读取超大文件占满上下文
    Args:
    path: 文件完整路径
    max_lines: 最多预览行数,默认30行
    Returns:
    文件元信息 + 头部内容预览
    """

    if not is_path_safe(path):
    return f"权限拒绝:{path} 不在允许访问目录列表中"

    p = Path(path)
    if not p.exists() or not p.is_file():
    return f"错误:文件不存在或非文件 —— {path}"

    try:
    with open(p, "r", encoding="utf-8", errors="replace") as f:
    all_lines = f.readlines()
    preview = all_lines[:max_lines]
    except Exception as e:
    return f"文件读取失败:{str(e)}"

    file_size = p.stat().st_size
    total_line_num = len(all_lines)
    header = (
    f"📄 文件路径:{path}\\n"
    f"文件大小:{file_size/1024:.1f} KB | 总行数:{total_line_num}\\n"
    f"预览前 {min(max_lines, total_line_num)} 行内容:\\n\\n"
    )
    return header + "".join(preview)

    if __name__ == "__main__":
    # Streamable HTTP 本地服务(仅localhost访问)
    mcp.run(transport="streamable-http")

    启动服务命令

    python file_scanner.py

    正常输出示例:

    INFO: Uvicorn running on http://0.0.0.0:8765
    INFO: Application startup complete.

    五、AI客户端接入配置(区分Mac/Windows)

    5.1 Claude Desktop 配置

  • Mac配置文件路径:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows配置文件路径:%APPDATA%\\Claude\\claude_desktop_config.json
  • 配置JSON(stdio传输模式,推荐本地使用):

    {
    "mcpServers": {
    "file-scanner": {
    "command": "python",
    "args": ["~/my-file-mcp/file_scanner.py"],
    "transport": "stdio"
    }
    }
    }

    修改完成后重启Claude Desktop,自动加载MCP服务。

    5.2 Cursor 编辑器配置

  • 打开Cursor → Settings → MCP → Add new MCP Server
  • 配置参数:
    | 配置项 | 填写内容 |
    | Name | file-scanner |
    | Command | python |
    | Arguments | ~/my-file-mcp/file_scanner.py |
    | Transport | stdio |
  • 保存后刷新MCP列表,显示服务在线即连接成功。

    六、实操调用示例

    客户端连接成功后,直接对话发送指令即可自动调用文件工具:

  • 检索项目所有Python文件
  • 调用file-scanner,扫描~/projects目录,找出所有*.py文件,最大深度3

  • 统计目录文件结构
  • 统计~/projects目录总文件数量、总大小,展示各类文件占比

  • 预览源码文件
  • 读取~/projects/utils.py前20行代码并展示文件信息

    七、进阶扩展工具模板

    基于@mcp.tool()装饰器可快速扩展更多本地自动化能力,推荐开发:

    工具函数实现功能
    git_log 读取Git仓库最近提交记录
    log_tail 实时读取日志末尾内容
    dir_diff 对比两个目录文件差异
    docker_list 列出本地运行容器
    cron_check 读取系统定时任务配置

    新增工具仅需定义函数、增加参数注解,MCP会自动生成工具描述供AI识别。

    八、安全加固&生产优化方案

  • 严格目录白名单:代码内置ALLOW_DIRS拦截路径穿越,禁止开放系统根目录;
  • 限制文件读取行数:preview_file限制最大预览行数,防止超大文件填满LLM上下文;
  • HTTP模式禁止公网暴露:streamable-http仅本地localhost访问,不开放0.0.0.0给局域网;
  • 增加文件大小校验:可新增代码判断文件体积,拒绝读取超过1MB大文件;
  • 日志记录所有文件操作:添加本地日志,审计AI全部文件访问行为。
  • 九、常见踩坑FAQ

    Q1:客户端识别不到MCP服务?
    A:检查Python路径是否正确、配置文件路径区分Mac/Windows,修改配置后重启客户端;确认mcp库版本≥1.0。

    Q2:调用文件工具提示权限拒绝?
    A:将目标目录添加到代码顶部ALLOW_DIRS白名单,重启MCP服务生效。

    Q3:启动服务报端口占用?
    A:修改FastMCP初始化时port=xxxx更换端口,同步修改客户端配置。

    Q4:读取中文文件乱码?
    A:代码已使用encoding="utf-8", errors="replace",特殊编码文件可自行调整编码参数。

    十、全文总结

  • MCP协议统一AI本地工具标准,一份服务兼容Cursor、Claude、VS Code多客户端;
  • 本文实现安全版文件扫描MCP服务,内置路径白名单规避文件读取安全漏洞;
  • 通过@mcp.tool()装饰器极简开发自定义本地工具,轻松扩展Git、容器、日志自动化能力;
  • 核心价值:打破AI只能操作对话文本的限制,让AI直接接管本地项目分析、批量文件处理工作。
  • 本教程基于Python MCP SDK v1.x编写,代码可直接本地运行,仅用于个人开发学习。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Python MCP实战:从零搭建本地文件系统服务器,让Cursor/Claude自由读取本地项目文件(附完整安全代码)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!