配置 MCP 服务总会遇到的 3 个坑:入口文件、环境变量、数据库锁

2026-07-21

背景: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 启动子进程。如果指向了模块导出文件而非可执行入口,虽然能启动但不一定能正确注册工具。

通用检查方法

  1. 手动验证:先在命令行执行同样的命令,确认能正常启动并保持在前台
  2. 查 README:看项目文档里写的启动方式是什么(尤其是用 npx/uvx 还是直接执行)
  3. 查包元数据:对 npm 包看 package.jsonbin 字段,对 Python 包看 pyproject.tomlscripts

坑 2:环境变量不传递给 MCP 子进程

症状

CLI 下运行一切正常,但通过 MCP 调用时报错:连不上数据库、找不到模型、API 认证失败。

根因

AI Agent 框架出于安全考虑,不会把完整的 shell 环境变量传递给 MCP 子进程。只会传递 PATHHOMEUSER 等安全基线变量。所有 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 命令报 Aborteddatabase 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 服务的关键不是理解协议本身,而是确保进程启动环境的正确性

  1. 入口文件:指向可执行入口不是模块导出,先手动验证
  2. 环境变量:显式声明所有必要变量,不要依赖 shell 配置
  3. 数据库架构:嵌入式数据库在 MCP 场景下可能遇到锁冲突,考虑迁移到真正的数据库

这些坑都不是 MCP 协议本身的缺陷,而是从”本地跑一下”到”作为持续运行的服务”过程中,那些容易被忽略的边界条件。理解了它们背后的原理,下次配置新服务就能一次跑通。

标签: MCP AI 工具 教程