MCP 深度解读:AI 连接外部世界的通用协议
从零理解 Model Context Protocol 的架构、原理与实战。读完本文,你应该能回答:MCP 解决什么问题、由哪些部分组成、如何配置、如何自己开发一个 MCP Server。
第一部分 · 全景概览
1.1 为什么需要 MCP
没有 MCP 时,AI 与外部系统交互的困境:
| 痛点 | 表现 |
|---|---|
| 集成成本高 | 每接入一个数据源(数据库/文件/API),都要为每个 AI 客户端写一套专属对接代码 |
| 生态碎片化 | Claude Desktop、Cursor、VS Code Copilot 各自有不同的插件体系,无法复用 |
| 安全裸奔 | 数据库密码硬编码在代码里、API Token 随意传递,缺乏统一鉴权机制 |
| 能力受限 | AI 只能操作内置工具,无法访问企业内部数据库、本地文件或专有 API |
核心矛盾: AI 模型的能力很强,但它被困在对话框里——看不到你的数据库、读不到你的本地文件、调不动你的企业 API。每个 AI 工具都在重复造轮子:自己写数据库连接、自己写文件读取、自己写 API 调用。
MCP 的出现改变了一切:
一个 Server,所有 Client 共享——这就是 MCP 的本质价值。
1.2 什么是 MCP
MCP(Model Context Protocol) 是由 Anthropic 发起并开源的标准化协议,用于让 AI 应用与外部系统建立安全的双向连接。
官方比喻:MCP 就像 AI 世界的 USB-C 接口——正如 USB-C 让所有设备有了统一的物理连接标准,MCP 让所有 AI 应用有了统一的外部系统连接标准。
核心特性:
| 特性 | 说明 |
|---|---|
| 开放标准 | 不绑定任何厂商,任何 AI 应用都能实现 |
| 双向连接 | AI 既能读取外部数据,也能执行外部操作 |
| 安全优先 | 内置鉴权、权限控制、操作审计 |
| 动态发现 | AI 可以在运行时发现并调用可用的工具和资源 |
生态支持(截至 2025 年):
- AI 客户端:Claude Desktop、Cursor、VS Code Copilot、ChatGPT、MCPJam
- 官方 Server:文件系统、数据库(PostgreSQL/MySQL)、搜索引擎、GitHub、Slack 等
- 社区 Server:Oracle、MongoDB、Redis、Docker、Blender 等数百个
1.3 整体架构图
三大参与者:
| 角色 | 定义 | 示例 |
|---|---|---|
| Host | AI 应用,负责协调管理多个 Client | Claude Desktop、Cursor |
| Client | 维持与某个 Server 的连接,获取上下文 | Host 内部自动创建的客户端实例 |
| Server | 向 Client 提供上下文(工具/资源/提示词) | 数据库 Server、文件 Server |
关键理解:一个 Host 可以同时连接多个 Server——比如 Cursor 可以同时连接 MySQL Server、文件系统 Server 和 GitHub Server,AI 在一次对话中可以同时查数据库、读文件、查 PR。
第二部分 · 核心概念深度解读
2.1 三层协议架构
数据层(Data Layer):定义说什么——消息格式(JSON-RPC 2.0)、生命周期(初始化/能力协商/断开)、三大原语(Tools/Resources/Prompts)。
传输层(Transport Layer):定义怎么说——通过哪个通道传输、如何建立连接、如何做身份验证。
设计哲学:两层分离让同一套协议既能用于本地进程(stdio,零网络开销),也能用于远程服务(HTTP,支持 OAuth)。开发者只需关注数据层逻辑,传输层由 SDK 处理。
2.2 三大核心原语(Primitives)
MCP 最核心的概念是三大原语——它们定义了 Server 能向 AI 提供什么:
Tools(工具)—— AI 的"手"
定义:可被 AI 调用的可执行函数,用于执行操作(查数据库、写文件、调 API)。
典型示例:
{
"name": "query_database",
"description": "执行 SQL 查询并返回结果",
"inputSchema": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "要执行的 SQL 语句"
}
},
"required": ["sql"]
}
}
AI 看到 description 后,会自主判断何时调用这个工具,并填入参数。
调用方式:Client 先通过 tools/list 发现可用工具,AI 决定调用时通过 tools/call 执行。
Resources(资源)—— AI 的"眼睛"
定义:向 AI 提供的上下文数据,是只读的信息源。
典型示例:
- 数据库 Schema(表结构、字段说明)
- 文件内容(配置文件、代码文件)
- API 文档
{
"uri": "db://mydb/schema",
"name": "数据库表结构",
"description": "所有表的字段定义和说明",
"mimeType": "application/json"
}
与 Tools 的区别:Resources 是 AI 被动读取的上下文,Tools 是 AI 主动执行的操作。
Prompts(提示词)—— AI 的"剧本"
定义:可复用的交互模板,帮助 AI 结构化地与外部系统交互。
典型示例:
{
"name": "analyze_database_performance",
"description": "分析数据库性能问题的引导模板",
"arguments": [
{"name": "table_name", "description": "要分析的表名", "required": true}
]
}
调用后返回的 Prompt 内容会包含 Few-shot 示例、分析步骤引导等,让 AI 按规范流程执行。
三者关系小结:
| 原语 | AI 视角 | 操作方向 | 类比 |
|---|---|---|---|
| Tools | “我能做什么” | AI → Server(执行) | 函数/API |
| Resources | “我能看到什么” | Server → AI(读取) | 数据库/文件 |
| Prompts | “我该怎么交互” | Server → AI(引导) | 操作手册 |
2.3 两种传输方式
stdio(本地进程)
Host 进程
│ 标准输入(stdin)
▼
MCP Server 进程(本地)
▲ 标准输出(stdout)
│
- 适用场景:本地工具(数据库、文件系统、CLI 工具)
- 特点:零网络开销、最低延迟、Host 直接拉起 Server 进程
- 配置方式:在
mcp.json中填写command+args
Streamable HTTP(远程服务)
Host
│ HTTP POST(Client → Server)
▼
远程 MCP Server
▲ SSE(Server → Client,流式推送)
│
- 适用场景:云服务、企业 API、SaaS 集成
- 特点:支持 OAuth、Bearer Token、API Key 鉴权;支持流式响应
- 配置方式:在
mcp.json中填写url+ 鉴权头
选型指南:
| 场景 | 推荐传输 |
|---|---|
| 本地数据库(MySQL/Oracle/PostgreSQL) | stdio |
| 本地文件系统操作 | stdio |
| 企业内部 API | Streamable HTTP |
| 第三方云服务(GitHub/Sentry/Slack) | Streamable HTTP |
| 需要多用户共享的 Server | Streamable HTTP |
2.4 生命周期管理
MCP 是有状态协议,连接建立需要经历三个阶段:
能力协商(Capability Negotiation):初始化时双方交换"我支持什么功能",确保后续通信只用双方都支持的特性。
第三部分 · 实战配置指南
3.1 在 Cursor 中配置 MCP
配置文件位置:.cursor/mcp.json(项目级)或全局设置
示例:接入本地 MySQL 数据库
{
"mcpServers": {
"mysql-local": {
"command": "npx",
"args": [
"@f4ww4z/mcp-mysql-server",
"--host", "127.0.0.1",
"--port", "3306",
"--user", "root",
"--password", "your_password"
]
}
}
}
接入后 AI 可以做的事:
- “查一下 orders 表的结构”
- “统计上个月订单量前10的客户”
- “帮我优化这条慢查询”
示例:接入本地文件系统
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"@anthropic/mcp-filesystem",
"/path/to/allowed/directory1",
"/path/to/allowed/directory2"
]
}
}
}
安全注意:文件系统 Server 只允许访问 args 中明确列出的目录,这是白名单机制,防止 AI 读取敏感文件。
示例:接入远程服务(Streamable HTTP)
{
"mcpServers": {
"sentry": {
"url": "https://mcp.sentry.io/mcp",
"headers": {
"Authorization": "Bearer YOUR_SENTRY_TOKEN"
}
}
}
}
3.2 在 Claude Desktop 中配置 MCP
配置文件位置:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
配置格式与 Cursor 完全相同——这就是开放标准的力量。
{
"mcpServers": {
"sqlite-local": {
"command": "uvx",
"args": [
"mcp-server-sqlite",
"/path/to/database.db"
]
},
"github": {
"command": "npx",
"args": ["@anthropic/mcp-github"],
"env": {
"GITHUB_TOKEN": "your_github_token"
}
}
}
}
技巧:
env字段用于传递环境变量,适合存放 API Token,避免暴露在命令行参数里。
3.3 配置常见问题排查
| 问题 | 原因 | 解决方式 |
|---|---|---|
| Server 无法启动 | npx/node 未安装或版本过低 | 安装 Node.js 18+ |
| 连接超时 | 数据库连接参数错误 | 检查 host/port/user/password |
| 工具列表为空 | Server 包名错误 | 检查包名拼写,手动 npx <包名> 测试 |
| 权限拒绝 | 文件路径不在白名单中 | 在 args 中添加允许的路径 |
| SSE 连接失败 | 远程 Server URL 错误或 Token 失效 | 验证 URL 和鉴权信息 |
第四部分 · MCP Server 生态概览
4.1 官方 Server
| Server | 说明 | 安装方式 |
|---|---|---|
@anthropic/mcp-filesystem | 本地文件读写 | npx @anthropic/mcp-filesystem <paths> |
@anthropic/mcp-github | GitHub PR/Issue/仓库操作 | npx @anthropic/mcp-github |
@anthropic/mcp-postgres | PostgreSQL 查询 | npx @anthropic/mcp-postgres <conn_string> |
@anthropic/mcp-slack | Slack 消息/频道操作 | npx @anthropic/mcp-slack |
@anthropic/mcp-puppeteer | 浏览器自动化(截图/导航) | npx @anthropic/mcp-puppeteer |
mcp-server-sqlite | SQLite 数据库(Python) | uvx mcp-server-sqlite <db_path> |
4.2 数据库类 Server
| 数据库 | 推荐 Server | 语言 |
|---|---|---|
| MySQL | @f4ww4z/mcp-mysql-server | Node.js |
| PostgreSQL | @anthropic/mcp-postgres | Node.js |
| SQLite | mcp-server-sqlite | Python |
| Oracle | 自定义(参考第五部分) | Node.js / Python |
| MongoDB | @anthropic/mcp-mongo | Node.js |
| Redis | @anthropic/mcp-redis | Node.js |
4.3 工具类 Server
| 类别 | Server | 说明 |
|---|---|---|
| 搜索 | @anthropic/mcp-brave-search | Brave 搜索引擎 |
| 浏览器 | @anthropic/mcp-puppeteer | 自动化浏览器操作 |
| 代码执行 | @anthropic/mcp-code-interpreter | 安全沙盒执行代码 |
| 知识图谱 | graphify-mcp | 项目知识图谱查询 |
| 日历 | @anthropic/mcp-google-calendar | Google 日历读写 |
4.4 MCP Server 查找资源
- 官方 Server 仓库:github.com/modelcontextprotocol/servers
- 社区聚合站:mcp.so
- npm 搜索:搜索
mcp-server关键词 - Smithery 市场:smithery.ai
第五部分 · 自定义 MCP Server 开发
5.1 为什么需要自定义 Server
以下场景没有现成 Server 可用,需要自己开发:
- 企业内部 API(ERP、LIMS、CRM 等专有系统)
- 特定数据库(如 Oracle,官方 Server 不完善)
- 特定业务流程(审批流、报表生成)
- 私有知识库 / 文档系统
5.2 用 Node.js 开发一个最小 MCP Server
安装依赖:
npm init -y
npm install @modelcontextprotocol/sdk zod
完整代码(index.js):
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "my-custom-server",
version: "1.0.0",
});
// 注册一个 Tool:查询订单
server.tool(
"get_order",
"根据订单号查询订单详情",
{
orderNo: z.string().describe("订单编号"),
},
async ({ orderNo }) => {
// 这里替换为真实的数据库查询
const order = await fetchOrderFromDB(orderNo);
return {
content: [{ type: "text", text: JSON.stringify(order, null, 2) }],
};
}
);
// 注册一个 Resource:订单表结构
server.resource(
"order-schema",
"schema://orders",
async () => ({
contents: [{
uri: "schema://orders",
mimeType: "application/json",
text: JSON.stringify({
table: "orders",
columns: [
{ name: "order_no", type: "VARCHAR(50)", desc: "订单编号" },
{ name: "customer", type: "VARCHAR(100)", desc: "客户名称" },
{ name: "amount", type: "DECIMAL(10,2)", desc: "订单金额" },
{ name: "status", type: "INT", desc: "状态:0草稿 1已提交 2已完成" },
],
}),
}],
})
);
// 注册一个 Prompt:查询订单分析模板
server.prompt(
"analyze_order",
"订单分析引导模板",
{ orderNo: z.string() },
({ orderNo }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `请分析订单 ${orderNo}:
1. 先调用 get_order 获取订单详情
2. 检查状态是否异常(超过30天未完成)
3. 检查金额是否超出客户历史均值
4. 给出风险评级和建议`,
},
}],
})
);
// 启动 Server
const transport = new StdioServerTransport();
await server.connect(transport);
在 mcp.json 中配置使用:
{
"mcpServers": {
"my-custom-server": {
"command": "node",
"args": ["/path/to/index.js"]
}
}
}
5.3 用 Python 开发 MCP Server
安装依赖:
pip install mcp
完整代码(server.py):
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-python-server")
@mcp.tool()
def query_table(table_name: str, limit: int = 10) -> str:
"""查询指定表的前 N 条记录"""
# 替换为真实数据库查询
rows = execute_query(f"SELECT * FROM {table_name} LIMIT {limit}")
return str(rows)
@mcp.resource("config://app-settings")
def get_app_settings() -> str:
"""返回应用配置信息"""
return '{"env": "production", "db_host": "10.0.0.1"}'
@mcp.prompt()
def debug_slow_query(sql: str) -> str:
"""慢查询分析引导"""
return f"""请分析以下 SQL 的性能问题:
```sql
{sql}
步骤:
- 检查是否有全表扫描
- 检查索引使用情况
- 给出优化建议"“”
if name == “main”:
mcp.run(transport=“stdio”)
---
### 5.4 MCP Inspector:开发调试利器
官方提供的调试工具,可以在浏览器中测试你的 Server:
```bash
npx @modelcontextprotocol/inspector node /path/to/index.js
打开浏览器后可以看到:
- 所有注册的 Tools / Resources / Prompts
- 手动触发工具调用,查看返回值
- 查看 JSON-RPC 通信报文
强烈推荐:开发阶段先用 Inspector 验证 Server 工作正常,再接入 Cursor / Claude Desktop。
第六部分 · 安全与最佳实践
6.1 安全原则
核心安全清单:
✓ Token/密码 通过 env 传递,不写入 args 或代码
✓ 数据库账号使用只读权限(SELECT only),禁止 DROP/DELETE
✓ 文件系统 Server 只开放白名单目录
✓ 写操作类工具(INSERT/UPDATE)要求用户确认后再执行
✓ 日志记录所有 tools/call 调用,便于审计
✗ 禁止将生产环境 root 账号直接暴露给 MCP
✗ 禁止在 Tool description 中写出真实密码或内网 IP
6.2 工具设计最佳实践
好的 Tool 设计:
{
"name": "search_orders",
"description": "根据客户名或日期范围搜索订单,返回最多50条结果",
"inputSchema": {
"properties": {
"customer": { "description": "客户名称(支持模糊匹配)" },
"from_date": { "description": "起始日期,格式 YYYY-MM-DD" },
"to_date": { "description": "截止日期,格式 YYYY-MM-DD" }
}
}
}
设计原则:
| 原则 | 说明 |
|---|---|
| 清晰的 description | AI 靠描述判断何时调用,描述要说明"做什么"和"何时用" |
| 参数有边界 | 限制返回条数(LIMIT)、限制日期范围,防止 AI 发出 SELECT * |
| 返回值结构化 | 用 JSON 而非纯文本,AI 更容易解析 |
| 错误信息有帮助 | 返回错误时说明原因和建议,而非只抛异常 |
| 操作分类 | 读操作(SELECT)和写操作(INSERT)分开,写操作更谨慎 |
6.3 常见反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
| 一个 Tool 做所有事 | AI 难以判断何时调用 | 拆分为多个职责单一的 Tool |
| description 含糊 | AI 不知道何时该用 | 明确写出"用途 + 何时使用 + 参数含义" |
| 无限制查询 | AI 可能 SELECT * 拉全表数据 | 强制加 LIMIT,参数设最大值限制 |
| Token 硬编码 | 安全风险 | 使用 env 环境变量 |
| 没有错误处理 | 连接失败时 AI 无法理解 | 返回结构化错误信息 |
第七部分 · MCP 与 Function Calling 的区别
很多人会问:MCP 和 OpenAI 的 Function Calling 不是一回事吗?
| 维度 | Function Calling | MCP |
|---|---|---|
| 范围 | 单个 AI 提供商的内置能力 | 跨厂商的开放标准 |
| 生态 | 只在 OpenAI API 中有效 | Claude、Cursor、VS Code、ChatGPT 通用 |
| 数据提供 | 开发者手动注入函数描述 | Server 动态暴露 Tools/Resources/Prompts |
| 状态管理 | 无状态(每次请求独立) | 有状态(连接生命周期管理) |
| 资源支持 | 无 Resources/Prompts 概念 | 三大原语完整 |
| 安全性 | 开发者自行处理 | 内置鉴权、权限控制 |
一句话区别:Function Calling 是 AI 模型的"内置能力",MCP 是"AI 世界的 USB-C 接口"——前者绑定厂商,后者跨平台通用。
第八部分 · 常见问题 FAQ
Q1: MCP Server 会消耗很多系统资源吗?
A: stdio 类型的本地 Server 通常很轻量,只是一个 Node.js/Python 进程。只有当 AI 调用工具时才会执行代码,空闲时几乎不消耗 CPU。
Q2: 多个 AI 客户端能同时连接同一个 MCP Server 吗?
A: 本地 stdio Server 通常是一对一(一个 Host 拉起一个 Server 进程)。远程 Streamable HTTP Server 支持多客户端并发。
Q3: MCP Server 能访问互联网吗?
A: 可以。MCP Server 是普通程序,它可以调用任何 API、访问任何网络资源。但建议限制 Server 的网络权限,只允许访问必要的地址。
Q4: 如何保护数据库密码不被 AI 看到?
A: 密码通过 env 字段注入到 Server 进程的环境变量中,AI 只能调用工具,无法读取 Server 的环境变量。
Q5: Cursor 里配置的 MCP Server,Claude Desktop 能用吗?
A: 配置文件格式完全相同,但需要在两个地方分别配置(项目级 .cursor/mcp.json vs Claude Desktop 全局配置)。同一 Server 包两边都能用。
Q6: 如何调试 MCP Server 是否正常工作?
A: 使用官方 @modelcontextprotocol/inspector 工具,在浏览器中可视化测试所有工具和资源。
Q7: MCP 支持流式响应吗?
A: Streamable HTTP 传输支持 SSE(Server-Sent Events),可以实现流式响应。stdio 传输也支持异步返回,适合长时间运行的查询。
Q8: 企业内网没有外网访问,能用 MCP 吗?
A: 可以。stdio 类型的 Server 完全本地运行,不依赖外网。企业内部也可以部署 Streamable HTTP Server 在内网使用。
第九部分 · 学习路径与资源
9.1 推荐学习顺序
1. 阅读本文,理解架构和三大原语
2. 在 Cursor 中配置一个 MySQL/SQLite Server,体验 AI 查数据库
3. 用 Inspector 调试官方 filesystem Server,观察 JSON-RPC 报文
4. 用 Node.js/Python 开发一个自定义 Server(参考第五部分)
5. 为企业内部 API 开发生产级 Server,加入鉴权和错误处理
9.2 核心资源
| 资源 | 链接 |
|---|---|
| 官方文档 | modelcontextprotocol.io |
| 官方 Server 仓库 | github.com/modelcontextprotocol/servers |
| MCP 规范 | spec.modelcontextprotocol.io |
| Node.js SDK | @modelcontextprotocol/sdk |
| Python SDK | mcp (PyPI) |
| MCP Inspector | @modelcontextprotocol/inspector |
| 社区 Server 聚合 | mcp.so |
| Smithery 市场 | smithery.ai |
结语
MCP 的本质,是给 AI 装上了手和眼睛——让它从"只能在对话框里说话"升级为"能够读取真实数据、执行真实操作"。
作为开发者,理解 MCP 的价值不仅在于使用现有的 Server,更在于创造新的 Server——把企业内部的数据和能力,通过 MCP 暴露给 AI,让 AI 真正成为你工作流的一部分。
最后的话:下一个十年,AI 与外部系统的集成不再是"高级功能",而是基础能力。MCP 就是这个时代的基础设施。现在开始学习和使用,就是在为未来积累复利。

1034

被折叠的 条评论
为什么被折叠?



