MCP

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 连接失败。

排查步骤

  1. 检查配置文件路径是否正确
  2. 检查命令和参数是否正确
  3. 手动运行 Server 命令查看错误输出
# 手动测试 Server
node dist/server.js

# 检查 Node.js 版本
node --version  # 需要 18+

# 检查依赖是否安装
npm ls @modelcontextprotocol/sdk

常见原因

  • 编译错误——TypeScript 代码未正确编译
  • 依赖缺失——node_modules 未安装
  • 路径错误——配置文件中的路径不正确

问题二:工具未被 LLM 调用

症状:Server 正常运行,但 LLM 不使用你的工具。

排查步骤

  1. 使用 Inspector 检查工具是否正确注册
  2. 检查工具描述是否清晰
  3. 检查参数 Schema 是否正确
// 差:描述模糊
server.tool('process', '处理数据', {}, handler);

// 好:描述具体
server.tool(
  'search_documents',
  '在指定目录中搜索文档。返回匹配的文件列表,包含文件名和摘要。当用户需要查找文件时使用此工具。',
  {
    directory: z.string().describe('搜索目录的绝对路径'),
    query: z.string().describe('搜索关键词'),
  },
  handler
);

常见原因

  • 描述不清晰——LLM 无法理解工具的用途
  • 参数类型错误——Schema 定义与实际不符
  • 工具名称冲突——多个 Server 注册了同名工具

问题三:工具调用返回错误

症状:LLM 调用了工具,但返回了错误。

排查步骤

  1. 查看 Server 的 stderr 日志
  2. 使用 Inspector 手动调用工具
  3. 检查参数是否符合预期
// 添加详细日志
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,
    };
  }
});

问题四:性能问题

症状:工具调用延迟过高。

排查步骤

  1. 在工具函数中添加计时
  2. 检查是否有阻塞操作
  3. 分析网络延迟(对于远程 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 调用逻辑。