背景:MCP 配好了,但服务不工作
MCP(Model Context Protocol)正在快速成为 AI Agent 连接外部工具的标准协议。Hermes Agent、Claude Code、Cursor、Windsurf、Cline 等都支持它。配一个 MCP 服务看起来很简单——在 YAML 文件里写几行配置就行。
但真正开始配的时候,问题就来了:
- 服务进程能启动,但工具列表是空的
- CLI 下运行正常,通过 MCP 调用就报错
- MCP 跑着的时候,另一个命令报 “database is locked”
这些不是协议层面的问题,是进程环境正确性和架构设计限制的体现。官方文档通常不会写这些,只有亲手踩过一遍才能讲清楚。

坑 1:入口文件指向错误——最常见的致命错误
症状
服务进程能启动,不报错,但工具列表为空或工具不可用。
真实案例
某个知识库系统第一次配置 MCP 时,配置文件长这样:
mcp_servers:
my-service:
command: bun
args:
- run
- src/mcp/server.ts
cwd: /path/to/project
能启动,但 MCP 客户端连不上任何工具。排查了半天才发现问题:src/mcp/server.ts 虽然导出了工具定义和 serve() 函数,但它不是可执行入口点——这是”被调用方”,而正确的入口是打包后的 CLI 命令。
mcp_servers:
my-service:
command: /path/to/.local/bin/my-service
args:
- serve
cwd: /path/to/project
根因
许多 TypeScript 项目会把工具定义和 CLI 入口分离在两个文件里:
server.ts— 导出工具定义和serve(),供框架调用cli.ts serve— CLI 入口,包装了服务启动逻辑
前端 MCP 客户端(Hermes Agent 等)通过 command + args 启动子进程。如果指向了模块导出文件而非可执行入口,虽然能启动但不一定能正确注册工具。
通用检查方法
- 手动验证:先在命令行执行同样的命令,确认能正常启动并保持在前台
- 查 README:看项目文档里写的启动方式是什么(尤其是用 npx/uvx 还是直接执行)
- 查包元数据:对 npm 包看
package.json的bin字段,对 Python 包看pyproject.toml的scripts段

坑 2:环境变量不传递给 MCP 子进程
症状
CLI 下运行一切正常,但通过 MCP 调用时报错:连不上数据库、找不到模型、API 认证失败。
根因
AI Agent 框架出于安全考虑,不会把完整的 shell 环境变量传递给 MCP 子进程。只会传递 PATH、HOME、USER 等安全基线变量。所有 API Key、数据库连接串都需要在配置的 env 字段里显式声明。
修复
mcp_servers:
my-service:
command: /path/to/bin
args:
- serve
env:
DATABASE_URL: "postgresql://user:pass@host:5432/db"
API_KEY: "sk-your-key"
MODEL_BASE_URL: "http://localhost:11434/v1"
环境变量优先级
| 来源 | 优先级 | 说明 |
|---|---|---|
MCP config 的 env |
最高 | 框架显式传入 |
| wrapper 脚本的 export | 中等 | 走脚本启动时有效,但 npx/uvx 不经过脚本 |
.bashrc/.zshrc |
不加载 | MCP 子进程不经过 shell 启动 |
| 服务自身的配置文件 | 最低 | 服务自己读文件时生效 |
通用检查方法
- 所有依赖 API Key、DB URL、Token 的 MCP 服务,都要在
env字段里显式声明 - 变量名要和服务文档中声明的一致(不一定是常用的 CLI 变量名)
- 如果服务有配置文件兜底(如
~/.my-service/config.json),确认 MCP 子进程能读到它

坑 3:嵌入式数据库的锁冲突
症状
MCP 服务运行时,其他 CLI 命令报 Aborted 或 database is locked。
真实案例
某个使用 PGLite(WASM 嵌入式 PostgreSQL)的知识库系统,MCP serve 启动后:
- CLI 导入命令
my-service import→ 报错 “database is locked” - CLI 更新命令
my-service sync→ 同样失败 - 只有先停掉 MCP serve,才能执行这些操作
这不是 bug,是嵌入式数据库的单连接架构限制。MCP 子进程持有了数据库文件锁,其他进程无法写入。
解决路径
短期方案:停服操作。先在配置中禁用 MCP 服务,执行完 CLI 命令后再启用。
长期方案:迁移到真正的客户端-服务器数据库。以 PostgreSQL 为例:
- 支持并发连接
- 可通过网络远程访问
- 自带连接池管理
- 配合 pgvector 还能做向量搜索
适用范围
使用 SQLite、PGLite、DuckDB 等嵌入式数据库作为 MCP 服务后端的场景都可能遇到这个问题。
补充踩坑:几个值得注意的小问题
相对路径导致 “command not found”
某些运行时(如 bun/node)在 args 中使用相对路径时会解析失败,即使设置了 cwd。始终使用绝对路径:
# 可能失败
mcp_servers:
my-service:
command: bun
args: ["run", "src/cli.ts"]
cwd: /home/user/project
# 稳定的写法
mcp_servers:
my-service:
command: /home/user/.local/bin/my-service
args: ["serve"]
cwd: /home/user/project
npx 缺少 -y 参数
首次运行时 npx 会提示 “Need to install the following packages”,MCP 子进程无法响应交互式提示,导致服务卡住。添加 -y 跳过确认:
mcp_servers:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
超时配置不匹配
不同场景需要的超时时间不同:
| 场景 | 建议 connect_timeout |
建议 timeout |
|---|---|---|
| SSH 远程 MCP | 30s+ | 120s+ |
| 编译型入口(bun/tsx) | 30s | 60s+ |
| HTTP 远程服务 | 15s | 120s |
| 本地轻量脚本 | 10s | 30s |
排障流程:按顺序排查
MCP 服务配置后不工作时,按以下顺序排查:
第 1 步:检查日志
确认 MCP 子进程的错误输出位置
→ 看 stderr 日志,通常能直接定位问题
第 2 步:命令行验证
手动执行 <command> <args>
→ 确认命令本身能正常启动
第 3 步:检查 entry point
配置的是可执行入口还是模块导出?
→ 对比 README / package.json 的 bin 字段
第 4 步:检查环境变量
服务需要哪些环境变量?
→ config 的 env 字段都声明了吗?MCP 进程不加载 .bashrc
第 5 步:检查文件路径
command 和 args 是否用绝对路径?
→ cwd 目录是否存在?
第 6 步:检查超时
服务启动需要多长时间?
→ connect_timeout 是否足够?
总结
配置 MCP 服务的关键不是理解协议本身,而是确保进程启动环境的正确性:
- 入口文件:指向可执行入口不是模块导出,先手动验证
- 环境变量:显式声明所有必要变量,不要依赖 shell 配置
- 数据库架构:嵌入式数据库在 MCP 场景下可能遇到锁冲突,考虑迁移到真正的数据库
这些坑都不是 MCP 协议本身的缺陷,而是从”本地跑一下”到”作为持续运行的服务”过程中,那些容易被忽略的边界条件。理解了它们背后的原理,下次配置新服务就能一次跑通。