MCP 踩坑手记:给 AI 接数据库时我犯的 5 个错误
2024 年底 Anthropic 开源了 Model Context Protocol(MCP),到现在一年半,月下载量已经破了 1.1 亿次。增速比当年 React 还猛。
但下载量不等于用好了。我在自己的项目里前后接了 6 个 MCP Server,过程中踩坑花的时间比写业务代码还多。把这些问题和解法记下来,你应该能少走几天弯路。
MCP 是什么,两句话说完
MCP 是个标准化的接口协议。AI 模型通过它调用外部工具——数据库、文件系统、API,什么都行。
之前每个工具都要单独写 function calling 的 schema,换个模型就得改一遍。MCP 统一了格式:Server 写一次,Claude、GPT、Gemini 都能用。架构就三层:
AI 模型 ←→ MCP Client ←→ MCP Server ←→ 外部工具
Client 集成在 AI 应用里(Claude Desktop、Cursor 自带),Server 你自己写或者用社区现成的。
下面说坑。
坑 1:配置路径写错,报错信息完全没用
Claude Desktop 的 MCP 配置文件位置:
# macOS
~/Library/Application Support/Claude/claude_desktop_config.json
# Windows
%APPDATA%\Claude\claude_desktop_config.json
# Linux
~/.config/Claude/claude_desktop_config.json
一个典型的 PostgreSQL 配置:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://user:pass@localhost:5432/mydb"
]
}
}
}
我第一次配的时候,连接串少写了端口号。Claude Desktop 给的报错就俩字:"Server disconnected"。没有堆栈,没有具体原因,什么都没有。
排查了半小时才发现问题。后来养成习惯:改完配置,先在终端手动跑一遍 Server 命令。
npx -y @modelcontextprotocol/server-postgres "postgresql://user:pass@localhost:5432/mydb"
终端会直接打印错误信息,比如 "password authentication failed" 或者 "connection refused"。比 Claude Desktop 的报错有用得多。
这一步大概 10 秒钟,但能省你半小时。
坑 2:Server 启动了,工具列表却是空的
这个坑更隐蔽。Server 正常启动,Claude 也识别到了连接,但实际调用时它说"没有可用工具"。
我遇到过两个原因。
第一个:npx 缓存了旧版本的 Server。社区的 MCP Server 更新很频繁,npx 不一定每次都拉最新的。
# 方法 1:清缓存
npx clear-npx-cache
# 方法 2:指定 latest
npx -y @modelcontextprotocol/server-postgres@latest "postgresql://..."
第二个原因更坑:数据库连接本身没问题,但用户没有表的读权限。Server 不报错,只是返回空工具列表。
-- 给用户加上 SELECT 权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_user;
-- 别忘了未来新建的表也要有权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO your_user;
这个排查花了我将近一个下午。因为连接没报错,我一直在翻 MCP Client 的代码找问题,方向完全搞反了。
坑 3:符号链接会绕过文件系统的安全边界
文件系统 MCP Server 有个安全设计:你指定一个根目录,AI 只能访问这个目录和它的子目录。
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/yourname/projects"
]
}
}
}
试图读 /etc/passwd 会被拒绝。看起来很安全。
问题是:如果你的 projects 目录里有指向系统目录的符号链接,AI 能通过 symlink 读到外面的文件。比如 projects/configs -> /etc,AI 就能读 /etc 下的所有内容。
这不是 bug,是 POSIX 文件系统的工作方式。但对安全性来说是个隐患。
解决办法:
- 检查允许目录里有没有 symlink:
find /Users/yourname/projects -type l - 如果 Server 支持
--no-follow-symlinks参数,开启它 - 给 MCP Server 的操作系统用户设置最小权限
坑 4:两个请求同时发,Server 直接卡死
MCP 用的是 JSON-RPC over stdio 传输。这意味着一个 Server 进程同一时刻只能处理一个请求。
我的 Agent 有时候会同时发两个查询(比如"对比 A 表和 B 表的数据"),第一个请求正常返回,第二个卡住了,等到超时才报错。
两个解决方案。
方案 1,多实例:
{
"mcpServers": {
"pg-read": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://...?application_name=read"]
},
"pg-write": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://...?application_name=write"]
}
}
}
方案 2,换传输方式。MCP 2025 年初加了 Streamable HTTP 传输,不走 stdio,天然支持并发。但需要 Server 端也支持这个传输方式,社区里大部分 Server 还在用 stdio。
我目前用方案 1,两个实例分别处理读和写,没再卡死过。
坑 5:AI 传参格式不对,docstring 写法决定成败
用 Python SDK 写自定义 MCP Server:
from mcp.server import Server
from mcp.types import TextContent
app = Server("sales-query")
@app.tool()
async def query_sales(
region: str, start_date: str, end_date: str
) -> list[TextContent]:
"""查询指定区域和时间段的销售数据"""
results = db.execute(
"SELECT * FROM sales WHERE region = %s AND date BETWEEN %s AND %s",
(region, start_date, end_date)
)
return [TextContent(type="text", text=format_results(results))]
代码本身没问题。问题出在 AI 传过来的参数。
start_date 这个参数,AI 有时候传 2026-05-15,有时候传 May 15, 2026,偶尔还会传 20260515。我的 SQL 只认第一种格式,后两种直接报错。
修复方法很简单,把 docstring 写具体:
@app.tool()
async def query_sales(
region: str, start_date: str, end_date: str
) -> list[TextContent]:
"""查询指定区域和时间段的销售数据
Args:
region: 区域代码,只接受以下值:east, west, north, south
start_date: 开始日期,格式 YYYY-MM-DD,例如 2026-01-01
end_date: 结束日期,格式 YYYY-MM-DD,例如 2026-12-31
"""
AI 会读 docstring 来决定传参格式。写得越具体,格式错误越少。
加了详细 docstring 之后,参数格式错误从占总失败的 62% 降到了不到 10%。这是我做过的最简单也最有效的优化。
跑了两周的数据
我在一个内部数据分析项目里接了 PostgreSQL + 文件系统两个 MCP Server,让 Agent 自己查数据、生成周报。连续跑了两周,记了一些数字:
| 指标 | 第一周 | 第二周(优化后) |
|---|---|---|
| 日均调用次数 | 34 次 | 51 次 |
| 工具调用成功率 | 78.4% | 94.3% |
| 平均响应时间 | 1.8 秒 | 1.2 秒 |
| 最慢一次 | 12.3 秒 | 4.1 秒 |
第一周到第二周的提升主要来自三件事:docstring 写详细、数据库加连接池(pgbouncer)、给大表加了合适的索引。
什么时候该用 MCP
用了这段时间,我的判断标准挺简单的:
用 MCP:你的工具要给两个以上的 AI 应用用,或者你想直接用社区已有的 Server。MCP 的价值在"写一次到处用"。
不用 MCP:只在一个应用里用、对延迟很敏感(MCP 每次调用多 200-500ms 序列化开销)、或者需要复杂的会话状态管理。这些场景直接写 function calling 更合适。
MCP 的官方 Server 仓库在 GitHub 搜 modelcontextprotocol/servers,目前有 30 多个官方维护的 Server,社区贡献的更多。挑一个你需要的试试,比自己从零写快得多。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)