MCP 调试完全指南:快速定位和解决常见问题
MCP Server 开发中常见问题的诊断和解决方法,包括连接失败、工具调用错误、性能问题的排查流程。
MCP 开发中遇到问题时,很多开发者不知道从何下手。这篇文章整理了最常见的问题场景和系统化的调试方法。
MCP Inspector:你的调试利器
MCP Inspector 是官方提供的交互式调试工具,可以连接到任何 MCP Server 进行测试。
安装和使用
npx @modelcontextprotocol/inspector node dist/server.js
启动后会打开一个 Web 界面,你可以在其中:
- 查看 Server 声明的所有工具、资源和提示
- 手动调用工具并查看返回结果
- 查看 JSON-RPC 消息的完整内容
- 测试错误场景
Inspector 的核心功能
工具列表——显示所有注册的工具,包括名称、描述和参数 Schema。
工具调用——填写参数并执行调用,实时查看返回结果。
消息日志——查看 Client 和 Server 之间的所有 JSON-RPC 消息。
常见问题诊断
问题一:Server 启动失败
症状:Claude Desktop 显示 MCP Server 连接失败。
排查步骤:
- 检查配置文件路径是否正确
- 检查命令和参数是否正确
- 手动运行 Server 命令查看错误输出
# 手动测试 Server
node dist/server.js
# 检查 Node.js 版本
node --version # 需要 18+
# 检查依赖是否安装
npm ls @modelcontextprotocol/sdk
常见原因:
- 编译错误——TypeScript 代码未正确编译
- 依赖缺失——
node_modules未安装 - 路径错误——配置文件中的路径不正确
问题二:工具未被 LLM 调用
症状:Server 正常运行,但 LLM 不使用你的工具。
排查步骤:
- 使用 Inspector 检查工具是否正确注册
- 检查工具描述是否清晰
- 检查参数 Schema 是否正确
// 差:描述模糊
server.tool('process', '处理数据', {}, handler);
// 好:描述具体
server.tool(
'search_documents',
'在指定目录中搜索文档。返回匹配的文件列表,包含文件名和摘要。当用户需要查找文件时使用此工具。',
{
directory: z.string().describe('搜索目录的绝对路径'),
query: z.string().describe('搜索关键词'),
},
handler
);
常见原因:
- 描述不清晰——LLM 无法理解工具的用途
- 参数类型错误——Schema 定义与实际不符
- 工具名称冲突——多个 Server 注册了同名工具
问题三:工具调用返回错误
症状:LLM 调用了工具,但返回了错误。
排查步骤:
- 查看 Server 的 stderr 日志
- 使用 Inspector 手动调用工具
- 检查参数是否符合预期
// 添加详细日志
server.tool('my_tool', schema, async (args) => {
console.error('[my_tool] 收到参数:', JSON.stringify(args));
try {
const result = await doWork(args);
console.error('[my_tool] 执行成功');
return result;
} catch (error) {
console.error('[my_tool] 执行失败:', error.message);
return {
content: [{ type: 'text', text: `错误:${error.message}` }],
isError: true,
};
}
});
问题四:性能问题
症状:工具调用延迟过高。
排查步骤:
- 在工具函数中添加计时
- 检查是否有阻塞操作
- 分析网络延迟(对于远程 Server)
server.tool('slow_tool', schema, async (args) => {
const start = performance.now();
const result = await doWork(args);
const duration = performance.now() - start;
console.error(`[slow_tool] 耗时: ${duration.toFixed(2)}ms`);
return result;
});
优化建议:
- 使用异步操作避免阻塞
- 实施缓存减少重复调用
- 限制返回数据量
日志最佳实践
分级日志
enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
class Logger {
private level: LogLevel;
constructor(level: LogLevel = LogLevel.INFO) {
this.level = level;
}
debug(message: string, data?: any) {
if (this.level <= LogLevel.DEBUG) {
console.error(`[DEBUG] ${message}`, data || '');
}
}
info(message: string, data?: any) {
if (this.level <= LogLevel.INFO) {
console.error(`[INFO] ${message}`, data || '');
}
}
error(message: string, error?: Error) {
console.error(`[ERROR] ${message}`, error?.stack || '');
}
}
请求追踪
为每个请求生成唯一 ID,便于追踪完整的调用链:
import { randomUUID } from 'crypto';
server.tool('my_tool', schema, async (args) => {
const requestId = randomUUID();
console.error(`[${requestId}] 开始执行 my_tool`);
const result = await doWork(args);
console.error(`[${requestId}] 执行完成`);
return result;
});
传输层调试
stdio 调试
stdio 传输的调试比较特殊——stdout 用于协议通信,所有日志必须输出到 stderr。
// 正确:日志输出到 stderr
console.error('Debug message');
// 错误:不要使用 console.log,它会干扰协议通信
console.log('This will break the protocol!');
SSE/HTTP 调试
使用 curl 手动测试 HTTP 端点:
# 测试 SSE 连接
curl -N http://localhost:3000/sse
# 测试工具调用
curl -X POST http://localhost:3000/messages \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"my_tool","arguments":{}}}'
常见问题(FAQ)
MCP Server 可以输出到 stdout 吗?
不可以。stdout 用于 MCP 协议通信。所有日志、调试信息必须输出到 stderr。
如何在 Claude Desktop 中查看 MCP 日志?
macOS:~/Library/Logs/Claude/ 目录下有详细的 MCP 日志。
工具调用超时怎么办?
检查 Server 端是否有长时间运行的操作。可以在工具函数中添加超时控制:
async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, timeout]);
}
总结
MCP 调试的核心工具是 MCP Inspector,它能解决 80% 的问题。剩余 20% 需要通过日志、手动测试和系统化的排查流程来解决。关键原则:先确认 Server 独立运行正常,再检查 Client 连接,最后排查 LLM 调用逻辑。