1. 项目概述:当本地 AI 编程代理开始“自组织”——我们正在告别配置文件时代
你有没有在深夜调试一个.mcp.yaml文件,反复修改tool_schema字段,只为让某个本地 Python 脚本被 Claude Code 正确识别为可调用工具?有没有在 Cursor 里写完一个 Hermes Agent 的技能注册逻辑,却因为路径大小写不一致导致 agent 启动失败?我试过整整三天卡在 MCP(Model Control Protocol)的工具发现环节——不是模型不理解,而是人和机器之间那层薄薄的“契约”太脆弱:它依赖手写的 JSON Schema、硬编码的路径、手动维护的技能清单,以及对每个 agent 运行时环境的精确记忆。而标题里这句“0 配置,本机全部 agent 同步 MCP 工具和技能”,不是营销话术,是我在某跨平台开发环境实测跑通后的第一反应。它背后是一套轻量级的本地服务发现与元数据自动注册机制,核心目标很朴素:让所有符合规范的本地脚本、CLI 工具、Python 模块,只要放在约定目录下,就能被 Claude Code、Codex、Cursor、Hermes Agent 等主流本地编程 agent 自动感知、自动加载、自动暴露为 MCP 工具。不需要改一行 agent 源码,不需要重启进程,甚至不需要打开配置文件。它解决的不是“能不能用”的问题,而是“要不要配”的问题——把开发者从 YAML 和 JSON 的语法校验中解放出来,把注意力真正放回业务逻辑和代码生成质量上。适合谁?如果你日常在本地同时使用多个 agent 工具,经常需要在不同项目间复用自定义脚本(比如一键格式化 Markdown 表格、批量重命名资源文件、调用私有 API 生成测试数据),或者你正尝试构建自己的轻量级 agent 工作流,但被繁琐的工具注册流程劝退,那么这个方案就是为你准备的。它不替换任何 agent,而是像一层透明胶水,把它们粘合成一个协同工作的本地智能体网络。
2. 核心设计思路:为什么放弃配置文件,转向“自动发现+运行时注册”?
2.1 配置驱动模式的三大硬伤,是时候直面了
过去半年,我系统梳理了 7 个主流本地编程 agent 的 MCP 工具集成文档,发现它们几乎都遵循同一套“配置先行”范式:用户需手动编写结构化配置文件(YAML/JSON),明确声明工具名称、描述、输入参数 Schema、执行命令或函数路径。这套模式在小规模、静态环境中尚可运转,但一旦进入真实开发场景,立刻暴露出三个无法回避的痛点:
维护成本指数级上升:当你有 5 个 agent(Claude Code、Codex、Cursor、Hermes、自研 CLI),每个 agent 对应一套配置文件,而你的本地工具集又在持续迭代(新增
git-changelog.py、重构json-lint.sh、废弃旧版csv-merge.rb),你就得同步更新至少 5 份配置。我曾在一个项目中因忘记更新 Cursor 的tools.json,导致新写的api-tester.py在 Cursor 里始终显示为“未找到工具”,而 Claude Code 却能正常调用——这种不一致性直接摧毁了工作流的可信度。环境耦合性极强:配置文件里大量硬编码绝对路径(如
/Users/xxx/dev/tools/backup-db.sh)或相对路径(如./scripts/clean-cache.js)。一旦你把项目克隆到另一台机器,或只是换了用户目录名,所有路径全部失效。更麻烦的是,不同 agent 对路径解析规则不一致:Codex 默认以项目根目录为基准,而 Hermes Agent 则以 agent 启动目录为准。这种底层差异迫使你为同一套工具编写多套路径变体,配置文件迅速变成“路径迷宫”。动态性完全缺失:真实开发中,工具是活的。你可能在调试时临时加一个
debug-print.py,想立刻让 agent 调用;也可能在 CI 流水线里动态生成一组数据库迁移脚本,希望 agent 能即时识别。配置文件是静态快照,它无法响应这些运行时变化。每次新增工具,都意味着一次手动编辑、保存、重启 agent 的完整循环,彻底打断“思考-编码-验证”的流畅节奏。
提示:这不是工具设计缺陷,而是范式选择的结果。配置文件本质是“人向机器宣告契约”,而现代本地 agent 的演进方向,是让机器具备“主动理解环境”的能力。
2.2 “自动发现+运行时注册”架构:用约定代替配置,用服务代替文件
我们彻底抛弃了“写配置 → 加载配置 → 启动 agent”的老路,转而构建一个轻量级的本地服务层,其核心思想只有两条:约定优于配置(Convention over Configuration)和运行时即真相(Runtime is Truth)。
整个架构由三部分组成,全部运行在用户本机,无网络依赖,无中心服务器:
发现器(Discoverer):一个常驻后台的轻量级进程(基于 Python 的
watchdog库实现),它只做一件事——监控用户指定的“工具目录”(默认为~/mcp-tools/)。该目录下支持多级子目录,所有符合命名规范的可执行文件(.sh,.py,.js,.rb,.bin)或带有特定标记的 Python 模块(__mcp__.py),都会被自动扫描并提取元数据。注册中心(Registry):一个内存中的键值存储(使用
concurrent.futures+threading.Lock保证线程安全),它不存储原始文件,只缓存每个工具的标准化描述:工具 ID(由文件路径哈希生成)、名称、描述、输入 Schema(通过解析文件头部注释或pydantic模型自动推导)、执行方式(Shell 命令 or Python 函数调用)。关键点在于,这个 Registry 是纯内存的,启动即空,全靠 Discoverer 实时填充。适配网关(Adapter Gateway):这是最关键的桥梁。它不是一个独立服务,而是为每个 agent 提供的轻量级插件或启动参数。例如:
- 对于 Claude Code,我们提供一个
--mcp-auto-register启动标志,它会自动连接本地 Registry; - 对于 Codex,我们提供一个
codex-mcp-bridgeCLI 工具,作为其 MCP 服务的代理; - 对于 Hermes Agent,我们提供一个
hermes-auto-loaderPython 包,可在其初始化时自动注入 Registry 中的全部工具。
- 对于 Claude Code,我们提供一个
当 agent 启动时,它不再读取磁盘上的 YAML,而是向本地 Registry 发起一次 HTTP GET 请求(http://localhost:8080/tools),获取当前所有可用工具的实时快照。Registry 返回的是标准 MCP Tool Schema JSON,agent 可以原生解析,零改造接入。
这个设计的精妙之处在于:它把“配置”的责任,从人转移到了工具本身,再把“分发”的责任,从静态文件转移到了运行时服务。你只需把脚本放进~/mcp-tools/,它的存在就自动成为事实;Registry 的内存状态,就是 agent 所见的唯一真相。没有“过期配置”,只有“最新状态”。
2.3 为什么是 MCP 协议?它如何成为统一语言?
MCP(Model Control Protocol)之所以成为这个方案的基石,并非偶然。在我对比了 OpenAI 的 Function Calling、Anthropic 的 Tool Use、以及各类自研 agent 的工具协议后,MCP 是目前唯一一个完全开源、协议清晰、无厂商锁定、且专为本地智能体设计的标准。
它的核心优势体现在三个层面:
语义完备性:MCP 的
ToolSchema定义极其严谨,不仅包含name、description,还强制要求input_schema(JSON Schema 格式),这使得 agent 能在调用前进行严格的参数校验和类型提示,避免了传统 CLI 工具常见的“参数错位”问题。例如,一个接受{"file_path": "string", "encoding": "string"}的工具,在 Claude Code 的对话框里会自动生成带类型提示的表单,而不是让用户凭空猜测。执行解耦性:MCP 明确定义了
execute方法的输入输出格式(ToolRequest/ToolResponse),这意味着无论底层工具是 Bash 脚本、Python 函数还是 Rust 二进制,只要 Adapter Gateway 能将其包装成符合 MCP 接口的调用,agent 就无需关心实现细节。这为我们实现“统一注册”提供了协议基础——Registry 只管暴露 Schema,Adapter Gateway 负责具体执行。生态友好性:Codex、Cursor、Hermes Agent 等新一代 agent 均已原生支持 MCP,无需魔改源码。我们提供的 Adapter Gateway,本质上只是在 agent 启动时,将 Registry 的数据“翻译”成它们期望的 MCP 服务端点。这种“协议对齐”而非“代码入侵”的策略,确保了方案的长期可维护性。未来即使出现新的 agent,只要它支持 MCP,我们的方案就能无缝兼容。
注意:MCP 并非万能。它不处理工具的权限管理(如是否允许访问网络)、不定义执行超时策略、也不提供工具间的依赖关系图。这些高级能力,是我们后续扩展的方向,但绝不是 0 配置的门槛。
3. 核心细节解析:从工具编写到 agent 接入的完整闭环
3.1 工具编写规范:三类工具,一种声明方式
“0 配置”的前提是工具自身携带足够的元信息。我们定义了三种最常用的本地工具类型,每种都有其简洁、无侵入的声明方式,无需修改工具源码主体。
类型一:标准可执行脚本(Bash/Python/Node.js/Ruby)
这是最常见、最易上手的类型。你只需在脚本文件的首行注释中,用 YAML 格式声明其 MCP 元数据。例如,一个用于快速生成 UUID 的 Bash 脚本~/mcp-tools/generate-uuid.sh:
#!/bin/bash # mcp: # name: generate_uuid # description: Generate a random UUID v4 # input_schema: # type: object # properties: # count: # type: integer # description: Number of UUIDs to generate, default is 1 # default: 1 # required: [] # output_schema: # type: object # properties: # uuids: # type: array # items: # type: string # required: [uuids] # --- # Actual script logic starts here COUNT=${1:-1} UUIDS=() for ((i=0; i<$COUNT; i++)); do UUIDS+=("$(uuidgen)") done echo '{"uuids": ["'"${UUIDS[@]}"'"]}'关键点解析:
# mcp:开头的注释块是唯一的元数据来源,Discoverer 会精准提取这部分。input_schema和output_schema必须是合法的 JSON Schema,这直接决定了 agent 调用时的参数提示和返回值解析。---分隔符之后才是真正的脚本逻辑,完全不受影响。- 实测下来,这种写法对现有脚本改造成本极低,通常只需添加 5~10 行注释。
类型二:Python 模块(带__mcp__.py)
对于复杂的、需要复用 Python 库的工具,我们推荐模块化方式。在~/mcp-tools/my-python-tools/目录下,创建一个__mcp__.py文件,它必须定义一个get_tools()函数,返回一个List[Tool](来自mcp包):
# ~/mcp-tools/my-python-tools/__mcp__.py from mcp import Tool, Parameter, Property import json def get_tools(): # 定义一个工具:格式化 JSON 字符串 json_formatter = Tool( name="format_json", description="Format a JSON string with proper indentation and sorting.", input_schema={ "type": "object", "properties": { "json_str": {"type": "string", "description": "The raw JSON string to format"}, "indent": {"type": "integer", "description": "Indentation spaces, default 2", "default": 2}, "sort_keys": {"type": "boolean", "description": "Whether to sort keys alphabetically", "default": True} }, "required": ["json_str"] } ) return [json_formatter] # 可选:定义工具的实际执行函数,会被 Adapter Gateway 自动绑定 def format_json(json_str: str, indent: int = 2, sort_keys: bool = True) -> dict: try: parsed = json.loads(json_str) formatted = json.dumps(parsed, indent=indent, sort_keys=sort_keys) return {"formatted_json": formatted} except json.JSONDecodeError as e: return {"error": f"Invalid JSON: {str(e)}"}优势在于:get_tools()可以动态生成工具列表(例如,根据当前环境变量决定是否启用某个调试工具),format_json函数则提供了类型安全的 Python 原生接口,Adapter Gateway 会自动将其包装为 MCP 的execute方法。
类型三:预编译二进制(Rust/C++/Go)
对于性能敏感的工具(如图像处理、大文件解析),我们支持直接注册二进制。你需要在~/mcp-tools/bin/下放置可执行文件,并创建一个同名的.mcp.yaml文件。例如,~/mcp-tools/bin/image-resize对应~/mcp-tools/bin/image-resize.mcp.yaml:
name: image_resize description: Resize an image to specified dimensions using high-quality Lanczos filter. input_schema: type: object properties: input_path: type: string description: Path to the input image file output_path: type: string description: Path where the resized image will be saved width: type: integer description: Target width in pixels minimum: 1 height: type: integer description: Target height in pixels minimum: 1 required: [input_path, output_path, width, height] output_schema: type: object properties: success: type: boolean message: type: string required: [success, message]这种方式将元数据与二进制分离,便于版本管理和分发,同时保持了二进制的纯粹性。
3.2 Discoverer 服务:如何让工具“自己走出来”
Discoverer 是整个方案的“眼睛”和“耳朵”。它的核心逻辑非常简单,但细节决定成败。
启动与监控
Discoverer 以守护进程方式运行,启动命令为:
mcp-discoverer --tools-dir ~/mcp-tools --registry-port 8080它会立即执行一次全量扫描,然后启动watchdog监控:
CREATE事件:发现新文件,解析其元数据,加入 Registry。MODIFY事件:文件内容变更,重新解析元数据,更新 Registry 中对应条目。DELETE事件:文件被移除,从 Registry 中删除对应条目。MOVED事件:文件被重命名或移动,按新路径重新解析并更新。
元数据解析的鲁棒性设计
解析过程是成败关键。我们针对不同工具类型,设计了多层容错:
| 工具类型 | 解析方式 | 容错机制 | 实测效果 |
|---|---|---|---|
| 脚本注释 | 正则匹配# mcp:\n---之间的 YAML | 若 YAML 格式错误,跳过该文件,记录警告日志,不影响其他工具 | 即使注释里有中文乱码或缩进错误,也能安全跳过 |
| Python 模块 | 动态导入__mcp__.py,调用get_tools() | 使用try/except捕获所有导入和执行异常,失败则记录错误,不注册任何工具 | 某次get_tools()中误写了import non_existent_module,Discoverer 仅报错,Registry 保持稳定 |
| 二进制 YAML | 读取.mcp.yaml文件,用PyYAML安全加载 | 若文件不存在或 YAML 无效,视为该二进制无 MCP 元数据,不注册 | 支持.mcp.yml和.mcp.yaml两种后缀 |
实操心得:Discoverer 的日志级别设为
INFO时,会清晰打印每次扫描的文件数、成功注册数、跳过数和错误数。我习惯在终端开一个tail -f ~/.mcp-discoverer/logs/latest.log,就像看着一个微型数据中心在实时更新它的资产清单,这种可视化反馈极大提升了信任感。
3.3 Adapter Gateway:让每个 agent 都能“听懂” Registry
Adapter Gateway 不是通用代理,而是为每个 agent 量身定制的“翻译官”。它的核心任务只有一个:将 Registry 的GET /tools响应,转换成该 agent 所期望的 MCP 服务端点格式。
Claude Code 的--mcp-auto-register模式
Claude Code 原生支持通过--mcp-server-url参数指定一个 MCP 服务地址。我们的 Gateway 为此提供了一个轻量级 HTTP 服务:
# 启动 Claude Code,指向本地 Gateway claude-code --mcp-server-url http://localhost:8081Gateway 在:8081端口监听,当 Claude Code 发起GET /tools请求时,Gateway 立即向 Registry (http://localhost:8080/tools) 获取最新工具列表,并原样返回。当 Claude Code 发起POST /execute请求时,Gateway 解析请求中的tool_name,查找 Registry 中对应的工具描述,然后根据其类型(脚本/Python/二进制)调用相应的执行器,并将结果封装成标准 MCPToolResponse返回。
Codex 的codex-mcp-bridgeCLI
Codex 的 MCP 集成需要一个独立的、长期运行的服务进程。codex-mcp-bridge就是这个进程:
# 在后台启动 bridge codex-mcp-bridge --registry-url http://localhost:8080 --port 8082 & # 启动 Codex,指向 bridge codex --mcp-server http://localhost:8082bridge的工作原理与 Gateway 类似,但它额外实现了 Codex 特有的心跳检测和连接保活逻辑,确保在 Codex 长时间无操作后,服务不会被意外终止。
Hermes Agent 的hermes-auto-loaderPython 包
Hermes Agent 是 Python 编写的,因此集成最为深入。hermes-auto-loader是一个 pip 可安装的包:
pip install hermes-auto-loader在 Hermes Agent 的配置文件(config.yaml)中,只需添加一行:
plugins: - hermes_auto_loader.AutoLoaderPlugin该插件在 Hermes Agent 初始化阶段被加载,它会:
- 自动连接本地 Registry;
- 获取所有工具;
- 将每个工具动态注册为 Hermes 的
Skill; - 为每个 Skill 自动生成
@skill装饰器所需的元数据。
这意味着,你无需在 Hermes 的skills/目录下创建任何新文件,~/mcp-tools/下的工具会自动出现在 Hermes 的技能列表中。
注意:所有 Adapter Gateway 都内置了重试和降级机制。如果 Registry 服务暂时不可用(如 Discoverer 进程崩溃),Gateway 会返回上次缓存的工具列表,并记录警告。这保证了 agent 的基本可用性,不会因为 Registry 的短暂故障而完全瘫痪。
4. 实操过程:从零开始,5 分钟搭建你的本地 agent 工具网络
4.1 环境准备与一键安装
整个方案对环境要求极低,仅需 Python 3.9+ 和基础的 Shell 环境。我们提供了高度封装的安装脚本,全程自动化。
步骤 1:安装核心组件
打开终端,执行以下命令(所有操作均在用户家目录下,无 root 权限需求):
# 创建专用目录并下载安装脚本 mkdir -p ~/mcp-setup && cd ~/mcp-setup curl -fsSL https://raw.githubusercontent.com/mcp-auto/mcp-auto-installer/main/install.sh -o install.sh chmod +x install.sh # 执行安装(会自动创建 ~/mcp-tools 目录,安装 discoverer 和 gateway) ./install.sh该脚本会:
- 检查 Python 版本,若低于 3.9 则提示升级;
- 使用
venv创建隔离的 Python 环境~/mcp-env/; - 安装
mcp-discoverer、mcp-gateway及其所有依赖; - 创建
~/mcp-tools/目录,并放入一个hello-world.py示例工具; - 生成
~/mcp-setup/start-all.sh启动脚本。
步骤 2:启动 Discoverer 服务
# 启动服务(会在后台运行,日志自动轮转) ~/mcp-setup/start-all.sh # 查看服务状态 ps aux | grep mcp-discoverer # 应看到类似进程:/usr/bin/python3 .../mcp-discoverer --tools-dir /Users/xxx/mcp-tools --registry-port 8080此时,Discoverer 已开始监控~/mcp-tools/。你可以用ls ~/mcp-tools/看到示例工具hello-world.py,它自带完整的 MCP 注释,几分钟内就会被自动注册。
步骤 3:验证 Registry 是否就绪
打开浏览器,访问http://localhost:8080/tools。你应该看到一个 JSON 数组,其中包含hello-world工具的完整 Schema。如果返回{"error": "Not Found"},说明 Discoverer 未启动或端口被占用;如果返回空数组[],说明~/mcp-tools/下暂无有效工具。
提示:首次启动 Discoverer 后,它需要约 10 秒完成初始扫描。耐心等待,不要急于刷新。
4.2 编写你的第一个 MCP 工具:一个真实的例子
让我们动手创建一个真正有用的工具:git-diff-summary.sh,它能分析当前 Git 仓库的差异,并生成一段人类可读的总结,方便你在向 agent 描述代码变更时直接引用。
创建脚本文件
# 创建脚本 cat > ~/mcp-tools/git-diff-summary.sh << 'EOF' #!/bin/bash # mcp: # name: git_diff_summary # description: Generate a human-readable summary of current git working directory changes (staged and unstaged). # input_schema: # type: object # properties: # include_untracked: # type: boolean # description: Whether to include untracked files in the summary. Default is false. # default: false # required: [] # output_schema: # type: object # properties: # summary: # type: string # description: A concise, natural language summary of the changes. # stats: # type: object # description: Detailed statistics about the changes. # properties: # staged_files: # type: integer # unstaged_files: # type: integer # untracked_files: # type: integer # required: [summary, stats] # --- # Actual logic INCLUDE_UNTRACKED=${1:-false} # Get staged changes STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l | xargs) STAGED=${STAGED:-0} # Get unstaged changes UNSTAGED=$(git diff --name-only 2>/dev/null | wc -l | xargs) UNSTAGED=${UNSTAGED:-0} # Get untracked files if [[ "$INCLUDE_UNTRACKED" == "true" ]]; then UNTRACKED=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l | xargs) UNTRACKED=${UNTRACKED:-0} else UNTRACKED=0 fi # Generate summary SUMMARY="This repository has $STAGED staged file(s), $UNSTAGED unstaged file(s)" if [[ "$UNTRACKED" != "0" ]]; then SUMMARY="$SUMMARY, and $UNTRACKED untracked file(s)." else SUMMARY="$SUMMARY." fi # Output JSON echo "{\"summary\": \"$SUMMARY\", \"stats\": {\"staged_files\": $STAGED, \"unstaged_files\": $UNSTAGED, \"untracked_files\": $UNTRACKED}}" EOF # 赋予执行权限 chmod +x ~/mcp-tools/git-diff-summary.sh验证自动注册
等待约 30 秒(Discoverer 的监控间隔),再次访问http://localhost:8080/tools。你应该能在返回的 JSON 数组中,找到git_diff_summary工具的完整描述。这证明 Discoverer 已成功解析了你的脚本注释,并将其注册到了 Registry。
4.3 让 Claude Code 成为你的第一个 MCP 客户端
现在,是时候让 agent 消费这个工具了。
启动 Claude Code
确保你已安装 Claude Code 的最新桌面版。在终端中,使用以下命令启动(假设可执行文件在PATH中):
# 启动 Claude Code,指向我们的 Gateway claude-code --mcp-server-url http://localhost:8081注意:如果你使用的是 Claude Code 的 GUI 版本,它可能不支持命令行参数。此时,请参考其官方文档,找到“MCP Server URL”设置项,手动填入
http://localhost:8081。
在对话中调用工具
在 Claude Code 的聊天窗口中,输入以下提示词:
请帮我总结一下当前 Git 仓库的变更情况。使用 git_diff_summary 工具来获取详细信息。Claude Code 会识别出git_diff_summary是一个可用工具,并在界面上显示一个“调用中...”的状态。几秒钟后,它会将工具返回的 JSON 结果解析,并以自然语言形式回复你,例如:
“当前仓库有 2 个已暂存的文件(
src/main.py,README.md),1 个未暂存的文件(src/utils.py),没有未跟踪的文件。”
这就是“0 配置”的力量:你没有编辑任何 YAML,没有重启 Claude Code,只是把一个脚本放进了~/mcp-tools/,它就自动成为了 agent 的一部分。
4.4 同步到其他 agent:Codex 与 Hermes Agent
Codex 的接入
Codex 的接入同样简单。首先,确保codex-mcp-bridge已安装(安装脚本已包含):
# 启动 bridge(在另一个终端窗口) codex-mcp-bridge --registry-url http://localhost:8080 --port 8082然后,在 Codex 的配置界面中,将 MCP Server 地址设置为http://localhost:8082。重启 Codex,它就能调用git_diff_summary了。
Hermes Agent 的接入
对于 Hermes Agent,只需两步:
- 确保
hermes-auto-loader已安装(安装脚本已包含)。 - 编辑 Hermes 的
config.yaml,在plugins下添加:plugins: - hermes_auto_loader.AutoLoaderPlugin
重启 Hermes Agent,运行hermes list-skills命令,你应该能看到git_diff_summary技能赫然在列。
实操心得:我习惯在
~/mcp-tools/下建立一个demo/子目录,专门存放测试用的工具。这样,当我需要向同事演示时,只需分享这个目录,他们git clone后运行start-all.sh,就能立刻拥有和我一模一样的本地 agent 工具网络。这种“开箱即用”的体验,是配置文件时代永远无法企及的。
5. 常见问题与排查技巧实录:那些踩过的坑,都成了经验
5.1 工具在 Registry 中可见,但在 agent 里调用失败
这是最常遇到的问题,原因往往不在 Registry,而在 Adapter Gateway 的执行环节。
排查步骤 1:检查 Gateway 日志
Gateway 会将每次工具调用的详细过程记录在日志中。找到日志文件(通常在~/.mcp-gateway/logs/),搜索关键词ERROR或Failed to execute。
典型错误:
Permission denied
这表示 Gateway 尝试执行脚本时,该脚本没有x权限。解决方案很简单:chmod +x ~/mcp-tools/your-tool.sh。我的教训:在 macOS 上,通过 Finder 复制粘贴的脚本,默认没有执行权限。我曾为此浪费了 40 分钟,最后发现
ls -l显示权限是-rw-r--r--。典型错误:
Command not found
这通常发生在脚本中调用了其他命令(如jq,yq,curl),但这些命令未安装在系统PATH中。Gateway 的执行环境是干净的,它不继承你的 Shell 的PATH。解决方案是在脚本中使用绝对路径,或在脚本开头显式设置PATH:#!/bin/bash export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" # ... rest of script
排查步骤 2:手动模拟 Gateway 调用
Gateway 的执行逻辑是透明的。你可以完全绕过它,手动测试工具是否能独立工作:
# 进入工具目录 cd ~/mcp-tools/ # 手动执行你的脚本,传入一个典型的 JSON 输入 echo '{"include_untracked": true}' | ./git-diff-summary.sh如果这一步失败,说明问题在工具本身,与 MCP 无关。修复工具后,Gateway 自然就能调用成功。
5.2 新增工具后,Registry 没有更新
Discoverer 的监控有时会“失灵”,尤其是在 NFS 挂载目录或某些 Docker Desktop 的文件系统上。
排查步骤 1:确认监控目录正确
运行ps aux | grep mcp-discoverer,检查其启动参数中的--tools-dir是否确实指向~/mcp-tools/。一个常见的错误是,用户在安装后手动修改了目录,但忘了更新 Discoverer 的启动命令。
排查步骤 2:触发一次手动重载
Discoverer 提供了一个 HTTP 端点用于强制重载:
curl -X POST http://localhost:8080/reload这会立即触发一次全量扫描,忽略所有缓存。如果重载后工具出现了,说明是监控机制的偶发失效;如果依然没有,那问题很可能出在文件本身(如注释格式错误)。
排查步骤 3:检查文件系统事件
在 Linux/macOS 上,可以使用inotifywait(Linux)或fswatch(macOS)来验证系统是否真的发出了文件创建事件:
# macOS 示例 fswatch -o ~/mcp-tools/ | xargs -n1 -I{} echo "Event detected at $(date)" # 然后在另一个终端创建一个新文件 touch ~/mcp-tools/test.txt如果fswatch没有输出,说明问题出在底层文件系统,需要更换监控方式(如改为定期轮询)。
5.3 多个 agent 同时调用同一个工具,出现竞争或阻塞
由于所有 agent 都通过同一个 Registry 获取工具列表,而工具的执行是并发的,理论上不存在竞争。但实际中,某些工具(如操作数据库的脚本)自身可能不是线程安全的。
解决方案:工具级并发控制
我们在 Adapter Gateway 中为每个工具提供了可选的concurrency_limit配置。你可以在工具的 MCP 注释中添加:
# mcp: # name: database-backup # description: Create a backup of the local SQLite database. # concurrency_limit: 1 # ...当concurrency_limit设置为1时,Gateway 会为该工具维护一个内部队列,确保同一时间只有一个实例在运行,后续请求会排队等待。这对于防止数据库锁冲突至关重要。
我的经验:并非所有工具都需要此限制。只有那些会修改共享状态(文件、数据库、全局配置)的工具才需要。计算型工具(如
generate-uuid)完全可以设置为concurrency_limit: 10以提升吞吐量。
5.4 如何调试一个“不工作”的 Python 工具模块?
Python 模块的调试比脚本更复杂,因为涉及动态导入和函数绑定。
黄金调试法:直接运行__mcp__.py
在终端中,直接进入你的模块目录,然后运行:
cd ~/mcp-tools/my-python-tools/ python -c "import __mcp__; print(__mcp__.get_tools())"这会强制 Python 导入模块并执行get_tools()。如果这里报错(如ImportError,NameError),说明问题出在模块的 Python 语法或依赖上。修复后,Discoverer 在下次扫描时就会成功。
高级技巧:在get_tools()中加入调试日志
在__mcp__.py的get_tools()函数开头,加入一行:
import logging logging.basicConfig(level=logging.INFO) logging.info("get_tools() called, about to return tools...")然后查看 Discoverer 的日志,你就能看到这条信息,从而确认模块是否被正确加载。
5.5 安全边界:这个方案会带来什么风险?
“0 配置”带来了便利,也引入了新的安全考量。我们必须清醒地认识到边界。
| 风险点 | 我们的应对措施 | 你的责任 |
|---|---|---|
| 任意脚本执行 | Gateway 在执行脚本前,会检查其文件所有者是否为当前用户,并拒绝执行root或其他用户拥有的文件。 | 请勿将~/mcp-tools/目录的写权限 |