1. MCP 协议概述

Claude Code 本身的能力边界是明确的:读写文件、执行命令、搜索代码。但实际开发中,你经常需要跟外部系统打交道——查 GitHub 上的 PR 状态、给 Slack 频道发消息、从 Notion 拉文档、查数据库。这些事情 Claude Code 原生做不了,或者做起来很绕(比如用 curl 调 API 再解析 JSON)。

MCP(Model Context Protocol)就是为了解决这个问题而设计的协议。它定义了一套标准化的接口规范,让 AI 模型能够以统一的方式连接外部工具和数据源。你可以把它理解为"AI 世界的 USB 接口"——不管你要接什么设备,只要它实现了 MCP 协议,Claude 就能直接用。

MCP 的设计目标

核心就一句话:标准化 AI 与外部世界的连接方式

在 MCP 出现之前,每个 AI 工具都有自己的一套插件/扩展机制。Cursor 有 Cursor Rules,Copilot 有 Extensions,各家互不兼容。开发者想让自己的服务被 AI 调用,得给每个平台分别写适配层,跟早年移动端碎片化一个德行。

MCP 的做法是:定义一套通用协议,任何工具提供方只需实现一次 MCP Server,就能被所有支持 MCP 的 AI 客户端调用。Anthropic 主导设计了这个协议,但它是开放标准,不绑定 Claude。

MCP 在 Claude 生态中的位置

这里要区分两个概念:

  • API 层的 MCP Connector:在 Claude API(Messages API / Managed Agents)中使用,通过 mcp_servers 参数在 API 请求中声明 MCP 服务器。这是给后端开发者用的,服务器端直接调用。

  • CLI 层的 MCP Server:在 Claude Code 中使用,通过 claude mcp add 命令或配置文件声明。这是本篇的重点。

两者底层协议相同,但配置方式和使用场景不同。CLI 层更偏向开发者日常使用,API 层更偏向生产环境集成。

MCP 的开放性

MCP 不是 Claude 的私有协议。OpenAI、Google、微软等公司也在接入或考虑接入 MCP。一个 MCP Server 写好之后,理论上可以被任何支持 MCP 的 AI 客户端使用——不管底层 LLM 是 Claude、GPT 还是 Gemini。

这意味着你在 MCP 生态上的投入不会被锁定在某一家。今天给 Claude Code 配的 GitHub MCP Server,明天换到其他支持 MCP 的工具里,配置基本不用改。


2. 传输类型详解

MCP 协议支持多种传输方式,决定了 Claude Code 跟 MCP Server 之间怎么通信。目前有三种:HTTP、stdio 和 SSE(已弃用)。

HTTP — 远程服务器

HTTP 是当前推荐的远程传输方式。MCP Server 作为一个 HTTP 服务运行在远程(通常是 SaaS 服务商提供的),Claude Code 通过 HTTP 请求与之通信。

适用场景

  • SaaS 服务提供的官方 MCP Server(Notion、Slack、Linear 等)

  • 团队共享的内部 MCP 服务

  • 需要认证和权限控制的场景

认证方式

  • Header 认证:通过 --header 参数传递 Authorization 头

  • OAuth:部分 SaaS 服务支持 OAuth 流程,Claude Code 会引导你完成授权

  • Token 认证:最常见的方式,通过环境变量引用 API Token

配置示例:

# 最简单的 HTTP 远程服务器
claude mcp add --transport http notion https://mcp.notion.com/mcp

# 带 Token 认证
claude mcp add --transport http my-api https://api.example.com/mcp \
  --header "Authorization: Bearer ${MY_API_TOKEN}"

# 带多个自定义 Header
claude mcp add --transport http internal-service https://mcp.internal.com \
  --header "Authorization: Bearer ${TOKEN}" \
  --header "X-Team-ID: engineering"

HTTP 传输的优势在于简单可靠。不需要在本地装任何东西,不需要管理进程生命周期,服务端升级对客户端透明。

stdio — 本地进程

stdio 传输方式下,Claude Code 会在本地启动一个子进程(通常是 Node.js 或 Python 程序),通过标准输入/输出(stdin/stdout)进行通信。

适用场景

  • 本地开发工具

  • 需要访问本地文件系统或数据库的场景

  • 私有/内部工具,不想暴露到公网

  • 需要离线使用的场景

工作原理

  1. Claude Code 根据配置启动子进程(比如 npx @modelcontextprotocol/server-github

  2. 子进程启动后,通过 stdout 发送工具定义

  3. Claude Code 需要调用工具时,通过 stdin 发送请求

  4. 子进程处理请求后,通过 stdout 返回结果

配置示例:

# GitHub MCP Server(最经典的 stdio 示例)
claude mcp add --transport stdio github -- \
  npx @modelcontextprotocol/server-github

# 带环境变量的本地服务器
claude mcp add --transport stdio my-db -- \
  node /path/to/my-db-server.js

# Python 实现的 MCP Server
claude mcp add --transport stdio analyzer -- \
  python3 /path/to/analyzer_server.py

stdio 方式的 -- 后面跟的是启动命令。Claude Code 会用这个命令启动子进程,并接管其 stdin/stdout。

注意:stdio 方式下,MCP Server 进程的生命周期与 Claude Code 会话绑定。会话结束时进程会被终止,下次会话重新启动。如果进程启动较慢(比如需要编译或下载依赖),第一次调用会有明显延迟。

SSE — 已弃用

SSE(Server-Sent Events)是早期 MCP 使用的远程传输方式。它通过 HTTP 长连接实现服务器向客户端推送消息。

为何弃用:HTTP 传输更简单、更可靠、更容易调试。SSE 在网络不稳定时容易断连,而且很多代理和 CDN 对长连接支持不好。

迁移指南:如果你有旧的 SSE 配置,改动很小:

# 旧方式(SSE)
claude mcp add --transport sse my-server https://mcp.example.com/sse

# 新方式(HTTP)
claude mcp add --transport http my-server https://mcp.example.com/mcp

大多数 MCP Server 提供方已经同时支持 HTTP 和 SSE,通常只是 URL 路径不同。检查你的 MCP Server 文档,找到 HTTP endpoint 替换即可。


3. 核心命令完全参考

Claude Code 提供了一组 claude mcp 子命令来管理 MCP Server。

添加服务器

# === HTTP 远程服务器 ===

# 基础添加
claude mcp add --transport http <name> <url>

# 带认证头
claude mcp add --transport http notion https://mcp.notion.com/mcp \
  --header "Authorization: Bearer ${NOTION_TOKEN}"

# 指定作用域为用户级(所有项目可用)
claude mcp add --transport http --scope user slack https://mcp.slack.com/mcp \
  --header "Authorization: Bearer ${SLACK_TOKEN}"

# 指定作用域为项目级(仅当前项目)
claude mcp add --transport http --scope project my-service https://mcp.internal.com


# === stdio 本地服务器 ===

# Node.js 包(npx 自动安装)
claude mcp add --transport stdio github -- \
  npx @modelcontextprotocol/server-github

# 带环境变量传递
claude mcp add --transport stdio github -- \
  env GITHUB_TOKEN=${GITHUB_TOKEN} npx @modelcontextprotocol/server-github

# 本地脚本
claude mcp add --transport stdio my-tool -- node ./tools/my-mcp-server.js

# Python Server
claude mcp add --transport stdio py-tool -- python3 -m my_mcp_server


# === 从 Claude Desktop 导入 ===

# 如果你已经在 Claude Desktop 中配置了 MCP Server,可以一键导入
claude mcp add-from-claude-desktop

add-from-claude-desktop 会读取 Claude Desktop 的配置文件(通常在 ~/Library/Application Support/Claude/claude_desktop_config.json 或 Windows 下的对应路径),把里面的 MCP Server 配置导入到 Claude Code 中。

管理服务器

# 列出所有已配置的 MCP Server
claude mcp list

# 查看指定服务器的详细配置
claude mcp get github

# 删除指定服务器
claude mcp remove github

# 会话内查看活跃的 MCP 连接状态
/mcp

/mcp 是会话内的斜杠命令,会显示当前会话中所有已连接的 MCP Server 及其提供的工具列表。如果某个 Server 连接异常,这里也会显示错误信息。

常用参数说明

参数 说明 示例
--scope user 用户级配置,所有项目可用 claude mcp add --scope user ...
--scope project 项目级配置,仅当前项目 claude mcp add --scope project ...
--transport http HTTP 远程传输 连接 SaaS 服务
--transport stdio 本地进程传输 连接本地工具
--header 设置 HTTP 头(可多次使用) --header "Authorization: Bearer xxx"

不指定 --scope 时,默认是 project


4. 配置文件与作用域

MCP Server 的配置最终都会写入配置文件。理解配置文件的层级和作用域对于团队协作很重要。

用户级配置:~/.claude.json

用户级配置存储在 ~/.claude.json 中。这里配置的 MCP Server 在所有项目中都可用。

适合放在这里的:

  • 个人常用的 SaaS 服务(你自己的 Notion、Slack 等)

  • 包含个人认证信息的服务器

  • 跨项目通用的开发工具

{
  "mcpServers": {
    "slack": {
      "transport": "http",
      "url": "https://mcp.slack.com/mcp",
      "headers": {
        "Authorization": "Bearer ${SLACK_TOKEN}"
      }
    },
    "notion": {
      "transport": "http",
      "url": "https://mcp.notion.com/mcp",
      "headers": {
        "Authorization": "Bearer ${NOTION_API_KEY}"
      }
    }
  }
}

项目级配置:.mcp.json

项目级配置存储在项目根目录的 .mcp.json 文件中。这个文件应该提交到 Git,让团队成员共享。

适合放在这里的:

  • 项目特定的 MCP Server(项目相关的数据库、内部 API)

  • 不包含敏感认证信息的配置(Token 通过环境变量引用)

  • 团队统一使用的工具

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "project-db": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${PROJECT_DB_URL:-postgresql://localhost:5432/mydb}"
      }
    }
  }
}

注意 .mcp.json 使用的是 stdio 传输的简写格式:command + args + env,不需要显式写 transport: "stdio"

环境变量引用

配置文件中可以通过 ${VAR} 语法引用环境变量,支持默认值语法 ${VAR:-default}

{
  "mcpServers": {
    "my-service": {
      "command": "node",
      "args": ["./mcp-server.js"],
      "env": {
        "API_KEY": "${MY_API_KEY}",
        "API_HOST": "${API_HOST:-https://api.example.com}",
        "LOG_LEVEL": "${LOG_LEVEL:-info}"
      }
    }
  }
}

${MY_API_KEY} 直接引用环境变量,如果变量不存在会是空字符串。${API_HOST:-https://api.example.com} 在变量不存在时使用默认值 https://api.example.com

这个机制很实用——团队共享的 .mcp.json 中用环境变量占位,每个人在自己的 .env 或 shell profile 中设置实际值。

团队协作最佳实践

.mcp.json(提交到 Git)

  • 项目需要的 MCP Server 声明

  • 不含敏感信息的配置

  • Token 用 ${ENV_VAR} 引用

**放用户级 ~/.claude.json**:

  • 个人的 SaaS 账号连接

  • 个人开发工具

  • 实际的 Token 值(或者更好的做法是放环境变量)

不要做的事

  • 不要把明文 Token 写进 .mcp.json 然后提交到 Git

  • 不要在用户级配置里放项目特定的服务器

  • 不要给 .mcp.json 里的每个服务器都硬编码认证信息

一个合理的团队工作流是这样的:

  1. Tech Lead 在 .mcp.json 中声明项目需要的 MCP Server

  2. README 或 CLAUDE.md 中说明需要设置哪些环境变量

  3. 每个开发者在自己的 shell profile 中设置对应的 Token

  4. claude mcp list 验证配置是否生效


5. 工具发现与延迟加载

MCP Server 通常会暴露多个工具。一个 GitHub MCP Server 可能提供 20+ 个工具(创建 PR、列出 Issue、搜索代码……),一个 Notion MCP Server 也有十几个工具。如果你配了 5 个 MCP Server,加起来可能有上百个工具定义。

把这些工具定义全部塞进上下文窗口是不现实的——它们会吃掉大量 token,而且绝大多数时候你只用到其中几个。

默认行为:延迟加载

Claude Code 默认对 MCP 工具采用延迟加载策略:

  1. 启动时:Claude Code 连接所有配置的 MCP Server,获取工具列表(只有名称和简短描述)

  2. 对话时:这些工具名称和描述被注册到 Tool Search 系统中,但完整的工具定义(参数 schema 等)不进入上下文

  3. 需要时:当 Claude 判断需要使用某个 MCP 工具时,通过 Tool Search 找到它,此时才加载完整定义并调用

这个机制的好处很明显:

  • 节省 token:100 个工具的完整定义可能有几万 token,延迟加载后只在实际使用时才消耗

  • 避免上下文污染:太多工具定义会分散 Claude 的注意力,影响它对核心任务的判断

  • 启动速度:不需要等所有 MCP Server 的完整 schema 都加载完

alwaysLoad: true

某些 MCP Server 提供的工具你几乎每次都会用到。比如你的项目重度依赖 GitHub MCP,每次会话都要查 PR、看 Issue。这种情况下延迟加载反而增加了一次额外的 Tool Search 开销。

可以在配置中设置 alwaysLoad: true,让指定 MCP Server 的工具定义在会话启动时就加载进上下文:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      },
      "alwaysLoad": true
    },
    "notion": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-notion"],
      "env": {
        "NOTION_API_KEY": "${NOTION_API_KEY}"
      }
    }
  }
}

上面的配置中,GitHub MCP 的工具会立即加载,Notion MCP 的工具延迟加载。根据你的使用频率来决定。

一般原则:每次会话必用的设 alwaysLoad: true,偶尔用的保持默认延迟加载。不要给所有 Server 都设 alwaysLoad,那等于关闭了延迟加载的优化。

Tool Search 与 MCP 工具的联动

Claude Code 内置了 Tool Search 机制(你在会话中可能见过 ToolSearch 工具被调用)。当 Claude 判断需要使用某个它当前上下文中没有的工具时,会通过 Tool Search 搜索所有已注册的工具——包括 MCP Server 提供的工具。

流程是这样的:

  1. 你说"帮我看一下 GitHub 上 #123 这个 Issue"

  2. Claude 发现当前上下文没有 GitHub 相关的工具

  3. Claude 调用 Tool Search,搜索关键词 “github issue”

  4. Tool Search 返回 GitHub MCP Server 的 get_issue 工具定义

  5. Claude 使用这个工具获取 Issue 信息

整个过程对你是透明的,你不需要手动"激活"某个 MCP 工具。


6. 常用 MCP 服务器实战

理论讲完了,看看实际怎么用。下面是几个最常用的 MCP Server 的安装配置和使用示例。

GitHub MCP

GitHub MCP Server 可能是使用最广泛的 MCP Server 之一。它让 Claude Code 能直接操作 GitHub——查看 PR、创建 Issue、搜索代码、管理仓库。

安装配置

# 方式一:命令行添加
claude mcp add --transport stdio github -- \
  npx @modelcontextprotocol/server-github

# 方式二:写入 .mcp.json

.mcp.json 配置:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

确保环境变量 GITHUB_TOKEN 已设置。Token 需要的权限取决于你要做什么操作:

  • 只读操作(查看 PR、Issue):repo:read 权限就够

  • 写操作(创建 PR、评论):需要 repo 完整权限

  • 组织级操作:需要 admin:org 权限

常用操作示例

在 Claude Code 会话中直接用自然语言即可:

"列出当前仓库所有 open 的 PR"
"查看 Issue #42 的详细信息和评论"
"给 PR #15 添加评论:LGTM,代码看起来没问题"
"搜索仓库中所有包含 TODO 的 Issue"
"创建一个新 Issue,标题是'重构用户认证模块',描述写清楚需求"

Claude 会自动选择合适的 GitHub MCP 工具来完成这些操作。

实际使用中的一个技巧:Claude Code 本身已经内置了 gh 命令行工具的支持。对于简单操作(比如查看 PR 状态),Claude 可能会直接用 gh pr list 命令而不是 MCP 工具。MCP 的优势在于更复杂的操作和更结构化的数据返回。两者可以共存,Claude 会自己判断用哪个更合适。

数据库 MCP

数据库 MCP Server 让你能用自然语言查询数据库,不用手写 SQL。

以 PostgreSQL 为例

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL:-postgresql://localhost:5432/mydb}"
      }
    }
  }
}

使用示例

"查询 users 表中最近注册的 10 个用户"
"统计每个月的新用户数量,按月份分组"
"找出 orders 表中金额大于 1000 的订单及对应的用户信息"

安全考量

这里必须强调安全问题。给 AI 直连数据库,风险不小:

  1. 只用只读权限。创建一个专门的数据库用户,只授予 SELECT 权限。绝对不要用有写权限的账号连接 MCP:
CREATE USER mcp_readonly WITH PASSWORD 'xxx';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_readonly;
  1. 别连生产库。用只读副本或者开发环境的数据库。MCP Server 本身没有防止误操作的机制。

  2. 敏感数据过滤。如果表里有密码哈希、身份证号等敏感字段,考虑只授予特定列的 SELECT 权限,或者用视图隔离。

  3. 查询审计。开启数据库的查询日志,记录 MCP 执行的每条 SQL。

Slack MCP

Slack MCP Server 让 Claude Code 能发消息、管理频道。

claude mcp add --transport http slack https://mcp.slack.com/mcp \
  --header "Authorization: Bearer ${SLACK_BOT_TOKEN}"

常用操作

"给 #engineering 频道发消息:部署完成,v2.3.1 已上线"
"查看 #bug-reports 频道最近的 10 条消息"
"列出我参与的所有频道"

Slack MCP 配合 Hooks 特别好用。比如在 PostToolUse Hook 中,当 Claude 完成一次部署后自动发 Slack 通知。这个在第 8 节会详细讲。

Filesystem MCP

你可能会问:Claude Code 不是已经能读写文件了吗?为什么还需要 Filesystem MCP?

区别在于 Claude Code 内置的文件操作有权限限制和沙箱约束。Filesystem MCP 可以提供更灵活的文件操作能力,比如:

  • 访问 Claude Code 沙箱外的目录

  • 批量文件操作(比如递归复制目录结构)

  • 文件监控(Watch 模式)

  • 跨设备文件访问(通过远程 Filesystem MCP)

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "@modelcontextprotocol/server-filesystem",
        "/path/to/allowed/directory"
      ]
    }
  }
}

Filesystem MCP 的参数中需要指定允许访问的目录路径,这是一个安全边界。MCP Server 只能操作这个目录及其子目录下的文件。


7. 自建 MCP 服务器

现有的 MCP Server 满足不了你的需求?自己写一个。MCP Server 的开发并不复杂,Anthropic 提供了 TypeScript 和 Python 两套 SDK。

基本开发步骤

一个 MCP Server 的核心就是:声明你提供哪些工具,然后实现这些工具的逻辑

流程:

  1. 创建项目,安装 MCP SDK

  2. 定义工具(name、description、输入参数 schema)

  3. 实现工具的处理逻辑

  4. 启动 Server 监听 stdio 或 HTTP

工具定义规范

每个工具需要三个要素:

  • name:工具标识符,英文小写加下划线,如 get_usercreate_order

  • description:工具描述,告诉 Claude 这个工具干什么、什么时候该用。写清楚很重要,直接影响 Claude 能否正确选择工具

  • inputSchema:输入参数的 JSON Schema 定义,包括参数类型、是否必填、描述等

TypeScript SDK 快速开始

mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk

创建 server.js

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  // 模拟调用天气 API
  return {
      city,
      temperature: "25°C",
      condition: "Sunny",
  };
}

async function convertCurrency(amount, from, to) {
  // 模拟调用汇率转换 API
  const rates = {
      USD: 1,
      CNY: 6.5,
      EUR: 0.85,
  };
  const result = (amount / rates[from]) * rates[to];
  return result.toFixed(2);
}

const server = new McpServer({
  name: "my-tool-server",
  version: "1.0.0",
});

// 定义一个工具:查询天气
server.tool(
  "get_weather",
  "获取指定城市的当前天气信息。当用户询问天气相关问题时使用此工具。",
  {
    city: {
      type: "string",
      description: "城市名称,如 'Beijing', 'Shanghai'",
    },
  },
  async ({ city }) => {
    // 这里实现实际的天气查询逻辑
    // 比如调用天气 API
    const weather = await fetchWeather(city);
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(weather, null, 2),
        },
      ],
    };
  }
);

// 定义另一个工具:汇率转换
server.tool(
  "convert_currency",
  "将金额从一种货币转换为另一种货币。",
  {
    amount: {
      type: "number",
      description: "要转换的金额",
    },
    from: {
      type: "string",
      description: "源货币代码,如 'USD', 'CNY'",
    },
    to: {
      type: "string",
      description: "目标货币代码",
    },
  },
  async ({ amount, from, to }) => {
    const result = await convertCurrency(amount, from, to);
    return {
      content: [
        {
          type: "text",
          text: `${amount} ${from} = ${result} ${to}`,
        },
      ],
    };
  }
);

// 启动 stdio 传输
const transport = new StdioServerTransport();
await server.connect(transport);

编译并注册到 Claude Code:

npx tsc server.ts
claude mcp add --transport stdio my-tools -- node ./server.js

Python SDK 快速开始

pip install mcp

创建 server.py

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import json

server = Server("my-python-tools")

@server.list_tools()
async def list_tools():
    return [
        Tool(
            name="analyze_log",
            description="分析日志文件,提取错误和警告信息。传入日志文件路径即可。",
            inputSchema={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "日志文件的绝对路径"
                    },
                    "level": {
                        "type": "string",
                        "enum": ["error", "warning", "all"],
                        "description": "要提取的日志级别",
                        "default": "error"
                    }
                },
                "required": ["file_path"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "analyze_log":
        file_path = arguments["file_path"]
        level = arguments.get("level", "error")
        
        # 实际的日志分析逻辑
        results = analyze_log_file(file_path, level)
        
        return [TextContent(
            type="text",
            text=json.dumps(results, ensure_ascii=False, indent=2)
        )]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

注册到 Claude Code:

claude mcp add --transport stdio log-analyzer -- python3 ./server.py

测试与调试

开发 MCP Server 时,调试是个痛点。因为 stdio 模式下所有通信都走 stdin/stdout,你没法直接用 print 打日志(会干扰 MCP 协议通信)。

几个调试技巧:

1. 使用 stderr 输出日志

import sys
print("debug info here", file=sys.stderr)
console.error("debug info here");

stderr 不会被 MCP 协议解析,可以安全输出调试信息。

2. 使用 MCP Inspector

Anthropic 提供了 MCP Inspector 工具,可以独立测试你的 MCP Server:

npx @modelcontextprotocol/inspector node ./server.js

它会启动一个 Web UI,你可以手动调用每个工具,查看输入输出,非常方便。
在这里插入图片描述

3. 先用 HTTP 模式开发

如果你的 Server 比较复杂,可以先用 HTTP 模式开发和测试。HTTP 模式下你可以用 Postman、curl 等工具直接发请求测试,调试体验好得多。功能验证通过后再切换到 stdio 模式。

4. 单元测试

把工具的业务逻辑独立出来,用普通的单元测试框架测试。MCP Server 本身只是一层薄薄的协议封装。

// 业务逻辑独立
export async function getWeather(city: string) {
  // ...
}

// 单元测试
test("getWeather returns data for Beijing", async () => {
  const result = await getWeather("Beijing");
  expect(result).toHaveProperty("temperature");
});

8. MCP 与 Skills / Hooks 的联动

MCP Server 单独用已经很有用了,但它真正的威力在于跟 Claude Code 的其他扩展机制组合使用。

Skill 中通过 MCP 获取外部数据

一个 Skill 可以在 allowed-tools 中声明它需要使用的 MCP 工具。这样当 Skill 被触发时,Claude 可以调用 MCP 工具获取外部数据。

例如,创建一个"PR 全面审查"Skill,它需要从 GitHub 拉取 PR 信息,从 Notion 拉取相关设计文档:

---
name: full-pr-review
description: 全面审查 PR,结合设计文档和代码变更进行深度评审
allowed-tools:
  - mcp__github__*
  - mcp__notion__search
  - mcp__notion__get_page
  - Read
  - Grep
  - Glob
---

## 审查流程

1. 使用 GitHub MCP 获取 PR 的完整 diff 和描述
2. 从 PR 描述中提取关联的设计文档链接
3. 使用 Notion MCP 获取设计文档内容
4. 对照设计文档审查代码实现
5. 输出结构化的审查意见

MCP 工具在 allowed-tools 中的命名格式是 mcp__<server-name>__<tool-name>。用 * 通配符可以匹配某个 Server 的所有工具。

Hook 中通过 mcp_tool 类型调用 MCP 工具

Hooks 系统支持 mcp_tool 类型,可以直接在 Hook 中调用 MCP 工具。这比用 command 类型手动 curl API 要简洁得多。

settings.json 中配置:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "if": "Bash(git push*)",
        "type": "mcp_tool",
        "server": "slack",
        "tool": "send_message",
        "input": {
          "channel": "#deployments",
          "text": "代码已推送到远程仓库"
        }
      }
    ]
  }
}

这个 Hook 的意思是:当 Claude 执行了 git push 命令后,自动通过 Slack MCP 发送一条消息到 #deployments 频道。

组合案例:PR 创建时自动通知 + 更新文档

下面是一个完整的组合案例。场景:团队约定每次创建 PR 时,需要在 Slack 频道通知,并在 Notion 的迭代文档中更新进度。

Step 1:确保 MCP Server 已配置

.mcp.json

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    }
  }
}

~/.claude.json(用户级,包含个人 Token):

{
  "mcpServers": {
    "slack": {
      "transport": "http",
      "url": "https://mcp.slack.com/mcp",
      "headers": {
        "Authorization": "Bearer ${SLACK_BOT_TOKEN}"
      }
    },
    "notion": {
      "transport": "http",
      "url": "https://mcp.notion.com/mcp",
      "headers": {
        "Authorization": "Bearer ${NOTION_API_KEY}"
      }
    }
  }
}

Step 2:创建 Skill 统一编排

.claude/skills/pr-workflow/SKILL.md

---
name: pr-workflow
description: 创建 PR 并自动通知 Slack 和更新 Notion 文档。当用户说"创建 PR 并通知""提交 PR 到 xxx"时触发。
allowed-tools:
  - mcp__github__create_pull_request
  - mcp__slack__send_message
  - mcp__notion__update_page
  - Bash
  - Read
---

## 工作流程

1. 分析当前分支的变更(git diff main...HEAD)
2. 生成 PR 标题和描述
3. 通过 GitHub MCP 创建 PR
4. 通过 Slack MCP 发送通知到 #pull-requests 频道,包含 PR 链接和简要描述
5. 通过 Notion MCP 更新当前迭代文档,添加 PR 记录

## 通知格式

Slack 消息格式:
-```
🔀 新 PR: {PR标题}
链接: {PR URL}
分支: {source}{target}
简述: {一句话描述变更}
-```

Step 3:使用

在 Claude Code 会话中:

"创建一个 PR,标题是'重构用户认证模块',目标分支 main,然后通知团队"

Claude 会按 Skill 定义的流程执行:创建 PR → 发 Slack 通知 → 更新 Notion。整个过程自动完成。

这就是 MCP + Skills + Hooks 三者组合的威力。MCP 提供外部连接能力,Skills 提供编排逻辑,Hooks 提供自动化触发。三者各司其职,组合起来可以覆盖非常复杂的工作流。


9. 故障排查

MCP 涉及网络连接、进程管理、认证等多个环节,出问题的概率不低。下面是常见问题和排查思路。

连接失败的常见原因

HTTP 传输连接失败

  1. URL 错误:检查 URL 是否正确,特别注意路径部分。有些 MCP Server 的 endpoint 是 /mcp,有些是 /v1/mcp,有些带端口号。

  2. 网络不通:先用 curl 测试 URL 是否可达:

    curl -I https://mcp.example.com/mcp
    
  3. 代理问题:如果你在公司网络或国内环境,可能需要配置代理。检查 HTTP_PROXY / HTTPS_PROXY 环境变量。

  4. DNS 解析:某些内部服务的域名可能需要 VPN 或特定 DNS 才能解析。

stdio 传输连接失败

  1. 命令不存在:确保 npxnodepython3 等命令在 PATH 中可用。在 Claude Code 的 shell 环境中运行一下看看:

    which npx
    npx @modelcontextprotocol/server-github --version
    
  2. 包未安装npx 第一次运行时需要下载包,可能因为网络问题失败。手动安装试试:

    npm install -g @modelcontextprotocol/server-github
    
  3. Node.js 版本过低:部分 MCP Server 要求 Node.js 18+。检查版本:

    node --version
    
  4. 权限问题:本地脚本需要执行权限:

    chmod +x ./my-mcp-server.js
    

认证过期的处理

Token 过期是最常见的"昨天还好好的,今天突然不行了"问题。

排查步骤

  1. 在 Claude Code 会话中输入 /mcp 查看连接状态。认证失败的 Server 通常会显示 401 或 403 错误。

  2. 检查环境变量是否正确设置:

    echo $GITHUB_TOKEN
    echo $NOTION_API_KEY
    
  3. 用 Token 直接调 API 测试:

    curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user
    
  4. 如果 Token 确实过期了,去对应平台重新生成,更新环境变量,然后重启 Claude Code 会话。

预防措施

  • 使用长期有效的 Token(GitHub Personal Access Token 可以设置为永不过期,但注意安全风险)

  • 对于支持 OAuth 的服务,使用 OAuth 流程,Token 会自动刷新

  • 在 CLAUDE.md 中记录各个 Token 的过期时间,作为提醒

stdio 进程挂起的排查

stdio 模式下,MCP Server 作为子进程运行。有时候这个进程会挂起——不响应请求,但也不退出。

症状:Claude 调用 MCP 工具后长时间没有响应,或者超时报错。

排查步骤

  1. 查看进程状态

    # Linux / macOS
    ps aux | grep mcp
    
    # Windows
    tasklist | findstr mcp
    
  2. 手动测试 MCP Server:直接运行 MCP Server 的启动命令,看看能否正常启动:

    npx @modelcontextprotocol/server-github
    

    如果启动时就卡住了,问题出在 Server 本身。

  3. 检查资源占用:MCP Server 可能因为内存泄漏或死循环导致资源耗尽:

    top -p $(pgrep -f "server-github")
    
  4. 超时设置:有些 MCP Server 支持超时配置,设置合理的超时可以避免永久挂起。

  5. 重启大法:最简单粗暴的方式——退出 Claude Code 会话(会自动终止子进程),重新开始新会话。

常见的挂起原因

  • MCP Server 在等待用户输入(比如某些 Server 首次运行时会要求交互式配置)

  • 网络请求超时但没有设置超时时间

  • 依赖的外部服务不可用

  • Server 内部错误导致事件循环阻塞

最佳实践

  • 给 stdio 类型的 MCP Server 配置 timeout 参数

  • 自建的 MCP Server 一定要做好错误处理和超时控制

  • 定期更新 MCP Server 到最新版本,bug 修复和性能改进都在更新中

  • .mcp.json 配置后,先用 claude mcp get <name> 验证配置是否正确,再开始使用


小结

MCP 协议解决的是一个根本性问题:让 AI 能够标准化地连接外部世界。没有 MCP,Claude Code 是一个强大但封闭的编码助手;有了 MCP,它变成了一个可以与整个开发工具链集成的中枢。

回顾一下关键要点:

  • 传输选择:远程服务用 HTTP,本地工具用 stdio,SSE 已弃用

  • 配置分层:团队共享的放 .mcp.json(提交 Git),个人的放 ~/.claude.json

  • 延迟加载:默认开启,高频工具设 alwaysLoad: true

  • 安全第一:数据库用只读权限,Token 用环境变量引用,不要明文提交

  • 组合使用:MCP + Skills + Hooks 组合能实现复杂的自动化工作流

MCP 生态正在快速发展,新的 MCP Server 每天都在涌现。官方维护的 MCP Server 列表可以在 GitHub modelcontextprotocol 仓库找到。社区贡献的 Server 数量更多,覆盖了从 AWS 到 Figma 到 Jira 的各种服务。


参考资料

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐