MCP:用标准协议连接工具、资源与提示模板
# MCP:用标准协议连接工具、资源与提示模板
建立 MCP 的 Host、Client、Server 心智模型,理解 Tools、Resources、Prompts 的职责,以及传输、授权和安全边界。
# 先记住一句话
MCP 是宿主应用(AI Host)连接外部工具和上下文能力的标准协议:Server 以统一方式暴露 Tools、Resources 和 Prompts,Host 中的 Client 负责连接和调用;它解决 “怎样接入”,不负责 Agent 的目标、规划和任务闭环。
用户
↓
Host(宿主应用:管理会话、模型、权限与用户体验)
├─ MCP Client A ── MCP Server:笔记库
├─ MCP Client B ── MCP Server:GitHub
└─ MCP Client C ── MCP Server:数据库
2
3
4
5
6
# 三个角色
- Host:承载 Agent 的宿主应用,决定连接哪些 Server、给模型暴露哪些能力,并承担会话、权限、审批和用户交互;
- Client:Host 内与某个 Server 保持协议连接的组件,负责能力发现、消息交换和生命周期;
- Server:把某个外部系统的能力按 MCP 规范暴露出来。
不要把 MCP Client 理解成用户界面,也不要把 Server 理解成 Agent。Server 可以只是一个提供 “搜索笔记” 工具和 “读取文档” 资源的适配器。
# Tools、Resources 和 Prompts
| 能力 | 适合表达什么 | 谁通常决定使用 |
|---|---|---|
| Tools | 查询或执行动作,有结构化输入输出 | 模型在 Host 允许范围内选择 |
| Resources | 可读取的文件、文档或数据 | 宿主应用或用户选择并加入上下文 |
| Prompts | 可复用的提示模板和参数 | 用户或宿主应用显式选择 |
把所有东西都做成 Tool 会丢失语义。只读知识适合 Resource;可复用工作入口适合 Prompt;需要计算、查询或产生副作用的能力才适合 Tool。
# Tool Calling 与 MCP 的关系
模型通过 Tool Calling 表达 “我要使用哪个工具和参数”;MCP 规定外部能力怎样被发现、描述和调用。Host 把 MCP Server 的工具转换成模型可理解的工具定义后,模型仍然进行 Tool Calling。
Tool Calling 是模型侧调用机制,MCP 是宿主应用与能力提供者之间的协议。
# 一个完整的 MCP 接入包含什么
MCP 不是只写一个 registerTool 就结束了。一个可以真正使用的最小闭环包含四部分:
1. MCP Server:注册能力并实现处理函数
↓
2. Transport:使用 stdio 或 Streamable HTTP 传递 MCP 消息
↓
3. MCP Host / Client:连接 Server,发现并调用能力
↓
4. 真实数据或业务系统:文件、数据库、第三方 API 等
2
3
4
5
6
7
“完整”不代表必须同时实现 Tools、Resources 和 Prompts。Server 只提供一个 Tool 也可以构成完整 MCP;关键是 Server 能启动、Host 能连接、能力能被发现和调用,结果能按协议返回。
# stdio 是什么
stdio 是 standard input / standard output(标准输入 / 标准输出)的缩写,是操作系统自带的本地进程通信通道,不需要单独安装:
Host 中的 MCP Client
│
├─ stdin ──→ 向 MCP Server 发送 JSON-RPC 消息
└─ stdout ←── 接收 MCP Server 返回的 JSON-RPC 消息
MCP Server 的 stderr ──→ 输出运行日志
2
3
4
5
6
使用 stdio 时,Host 会把 MCP Server 启动为本机子进程,并管理它的生命周期。因此它适合本地集成,不需要监听端口;远程或需要多个 Client 连接的 Server 通常使用 Streamable HTTP。
stdout 是 MCP 的协议通道,不能混入普通日志,否则会破坏 JSON-RPC 消息。Node.js 中应使用 console.error() 把日志写入 stderr,不要使用 console.log()。
# Streamable HTTP 是什么
Streamable HTTP 是 MCP 面向远程连接的传输方式。它建立在 HTTP / HTTPS 之上,Host 向统一的 MCP 地址发送请求,Server 可以根据场景返回一次性的 JSON,也可以保持连接并持续返回事件或分段结果。
普通调用:Host → POST /mcp → Server 执行 → 返回 JSON
流式调用:Host → POST /mcp → Server 保持连接
├─ 返回进度或事件
├─ 返回分段结果
└─ 完成后结束响应
2
3
4
5
6
“Streamable”强调的是 同一种 HTTP 传输既能返回普通响应,也能按需流式返回,不代表每次调用都必须使用流式输出。
| 对比项 | stdio | Streamable HTTP |
|---|---|---|
| 连接对象 | 本机子进程 | 远程网络服务 |
| Host 配置 | 启动命令和参数 | HTTP / HTTPS 地址 |
| 是否监听端口 | 不需要 | 需要 |
| 常见用途 | 本地 IDE、桌面应用 | 云端服务、跨机器和多人复用 |
| 安全重点 | 本地进程权限、启动参数 | 身份认证、授权、HTTPS、限流和来源校验 |
Streamable HTTP 不等于旧的 HTTP + SSE 传输。旧方案通常使用分开的 HTTP 和 SSE 端点;Streamable HTTP 使用统一的 MCP 端点,并根据请求返回普通 JSON 或流式事件。新开发的远程 MCP Server 应优先采用 Streamable HTTP。
# 配置 MCP 一定需要 HTTPS 地址吗
不一定。MCP 使用哪种配置,取决于 Server 是运行在本机还是远程环境:
| 类型 | Host 配置的核心内容 | 通信方式 | 适用场景 |
|---|---|---|---|
| 本地 MCP Server | command 和 args | stdio | Host 与 Server 在同一台机器 |
| 远程 MCP Server | https://.../mcp | Streamable HTTP | 跨机器、多人或云端使用 |
本地 MCP 通常不需要 URL。Host 根据配置的命令启动 Server,再通过该进程的 stdin 和 stdout 通信:
{
"mcpServers": {
"notes": {
"command": "node",
"args": ["/绝对路径/notes-mcp/dist/index.js"]
}
}
}
2
3
4
5
6
7
8
远程 MCP 才需要网络地址:
{
"mcpServers": {
"notes": {
"url": "https://mcp.example.com/mcp"
}
}
}
2
3
4
5
6
7
如果某个平台只允许填写 HTTPS 地址,通常说明该平台不能启动用户电脑上的本地进程,只支持连接远程 MCP Server。生产环境应使用 HTTPS;本地 HTTP 开发可以使用类似 http://localhost:3000/mcp 的地址。
# 远程 MCP Server 部署在哪里
远程 MCP Server 本质上是一个对外提供 MCP 接口的后端服务,可以部署在云服务器、容器或 Kubernetes、Serverless 平台、边缘运行时,也可以部署在公司的私有网络中。只要 MCP Host 能访问它提供的 Streamable HTTP 地址即可。
AI Host
↓ HTTPS
远程 MCP Server(云服务器、容器或 Serverless 平台)
↓
数据库、GitHub、内部 API、对象存储或向量数据库
2
3
4
5
MCP Server 和真实数据不必部署在同一个地方。例如笔记 MCP Server 可以运行在云端容器中,再调用另一个后端读取 PostgreSQL 或向量数据库。远程 MCP 是部署在服务器上的协议适配服务,不是部署到模型或用户浏览器中。
远程化不只是把 stdio 改成一个 URL。生产环境还要补齐 HTTPS、身份认证、用户授权、数据隔离、Origin 与 Host 校验、限流、超时、日志和密钥管理。
# 从零写一个可运行的本地 MCP Server
下面使用 MCP TypeScript SDK v2。先准备 Node.js 20 或更高版本,再创建项目并安装依赖:
mkdir notes-mcp
cd notes-mcp
npm init -y
npm pkg set type=module
npm install @modelcontextprotocol/server zod tsx
mkdir src
2
3
4
5
6
新建 src/index.ts。这个例子使用内存数组模拟笔记数据,因此复制后就能运行:
import { McpServer } from '@modelcontextprotocol/server'
import { serveStdio } from '@modelcontextprotocol/server/stdio'
// z 来自 Zod,用于定义并校验工具输入。
import * as z from 'zod/v4'
const notes = [
{ title: 'Agent Loop', content: 'Agent 根据观察结果决定下一步。' },
{ title: 'MCP', content: 'MCP 用统一协议连接外部能力。' }
]
function createServer() {
const server = new McpServer({
name: 'notes-server',
version: '1.0.0'
})
server.registerTool(
'search_notes',
{
title: '搜索笔记',
description: '根据关键词搜索笔记标题和正文',
inputSchema: z.object({
query: z.string().min(1).describe('搜索关键词'),
limit: z.number().int().min(1).max(10).default(5)
})
},
async ({ query, limit }) => {
// 真实项目应在这里查询文件、数据库或后端 API,并执行权限过滤。
const rows = notes
.filter(note => `${note.title} ${note.content}`.includes(query))
.slice(0, limit)
return {
content: [{
type: 'text',
text: JSON.stringify(rows)
}]
}
}
)
return server
}
// Host 启动本进程后,SDK 从 stdin 读取请求,并把响应写入 stdout。
void serveStdio(createServer)
// 普通日志必须写入 stderr,不能占用 stdout 协议通道。
console.error('notes MCP server running on stdio')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 先用 Inspector 验证
直接运行 stdio Server 时,它只会等待 Client 发来消息,看起来像 “没有反应”。可以使用官方 Inspector 充当测试 Client:
npx @modelcontextprotocol/inspector npx tsx src/index.ts
在打开的页面中连接 Server,进入 Tools,选择 search_notes,传入 {"query":"Agent","limit":5}。能够看到返回的笔记数组,就证明 Server、stdio 传输、能力发现和工具调用 已经连通。
# 再连接到真正的 Host
不同 Host 的配置文件位置和字段可能不同,但 stdio 配置的核心都是 “用什么命令启动哪个 Server”。常见结构如下:
{
"mcpServers": {
"notes": {
"command": "npx",
"args": ["tsx", "/绝对路径/notes-mcp/src/index.ts"]
}
}
}
2
3
4
5
6
7
8
配置完成后,一次真实调用会经历:
Host 启动 notes MCP Server
→ Client 获取 search_notes 的名称、描述和输入 Schema
→ Host 把工具说明提供给模型
→ 模型提出 search_notes({ query: "Agent", limit: 5 })
→ Host 通过 stdio 把调用发给 Server
→ Server 校验参数并执行处理函数
→ 结果通过 stdout 返回 Host
→ 模型根据结果回答用户
2
3
4
5
6
7
8
到这里才算写完了一个最小但完整的 MCP 接入。真实项目通常只需要把示例中的内存数组替换为文件、数据库或 API,并补上身份传递、服务端权限过滤、超时、错误处理和审计。传输方式不会替代认证与授权:远程服务还要校验身份、令牌受众、权限范围和每次操作的业务约束。
# 生产安全边界
- Server 不信任模型参数,也不信任来自文档的指令;
- Host 只加载用户允许的 Server 和能力;
- 读写工具分离,写操作显示明确预览并绑定用户审批;
- 凭据保存在 Server 或安全执行环境,不进入模型上下文;
- 输出限制大小、去除敏感字段,并标记外部内容不可信;
- 记录 Server、工具、参数摘要、调用结果和审批主体;
- 远程 Server 按最小权限授权,防止 confused deputy(混淆代理)问题。
# MCP 与 API 有什么不同
API 定义某个服务怎样被程序调用;MCP 在 API 之上提供面向 AI 宿主应用的一致能力发现和交互语义。实现 MCP Server 时通常仍会调用数据库或 REST API。MCP 不是取代所有 API,而是减少每个 AI Host 为每个服务重复写适配层。
# 贯穿项目怎样使用
可以把笔记能力做成独立 MCP Server:
- Resource 暴露指定 Markdown 文档;
- Tool 提供
search_notes、get_learning_progress; - Prompt 提供 “模拟技术面试” 入口;
- 删除或改写笔记属于高风险 Tool,默认不暴露,或必须审批;
- 同一 Server 可被站内助手、IDE 和其他允许的 Host 复用。
# 高频面试题与回答
回答顺序:先说结论,再解释原因,最后补一个例子或工程边界。不要逐字背诵,记住这条表达主线即可。
1. 30 秒回答:什么是 MCP参考答案
MCP 可以理解为 AI 应用连接外部能力的一套统一接口。宿主应用负责模型、会话和权限,其中的 MCP Client 连接不同的 MCP Server;Server 可以提供工具、资料和提示模板。它解决的是这些能力怎样被发现和调用,不负责替 Agent 规划任务,也不会自动处理授权、审批、幂等和停止条件。
2. MCP Server 是 Agent 吗?参考答案
通常不是。MCP Server 更像一个能力提供方,它把工具或资料暴露出来;Agent 才围绕目标决定要不要调用、拿到结果后是否继续以及什么时候停止。Server 内部可以包装一个复杂系统,甚至包装另一个 Agent,但 MCP Server 这个协议角色本身不等于 Agent。
3. Resource 和 Tool 怎样选择?参考答案
如果提供的是可以读取的内容,例如文档、配置或数据库结构,更适合 Resource;如果需要传参数后查询、计算,或者会产生写入等副作用,更适合 Tool。简单说,Resource 偏向 “给我资料”,Tool 偏向 “替我做一件事”。
4. 有了 MCP 为什么仍要做权限校验?参考答案
因为 MCP 只是统一了通信方式,不会自动证明这次调用合法。就像统一使用 HTTP,也不代表每个请求都有权限。Host 和 Server 仍要根据真实用户身份做最小权限、参数校验、审批、审计和数据过滤。
5. MCP 和 A2A 有什么区别?参考答案
MCP 主要解决 Agent 怎样接入工具、资料和提示模板;A2A 主要解决两个独立 Agent 怎样发现对方、移交任务、交换消息和跟踪进度。可以简单记成:MCP 连接能力,A2A 连接 Agent。两者可以同时使用。
# 接下来学什么
下一篇学习 Skill 的设计与复用,重点理解 MCP 怎样接入外部能力,以及 Skill 怎样让成熟任务方法得到稳定复用。