MCP:用标准协议连接工具、资源与提示模板

# MCP:用标准协议连接工具、资源与提示模板

本篇目标

建立 MCP 的 Host、Client、Server 心智模型,理解 Tools、Resources、Prompts 的职责,以及传输、授权和安全边界。

看懂协议角色区分三类能力实现最小 Server应对协议追问

# 先记住一句话

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:数据库
1
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 等
1
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 ──→ 输出运行日志
1
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 保持连接
                              ├─ 返回进度或事件
                              ├─ 返回分段结果
                              └─ 完成后结束响应
1
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"]
    }
  }
}
1
2
3
4
5
6
7
8

远程 MCP 才需要网络地址:

{
  "mcpServers": {
    "notes": {
      "url": "https://mcp.example.com/mcp"
    }
  }
}
1
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、对象存储或向量数据库
1
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
1
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')
1
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
1

在打开的页面中连接 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"]
    }
  }
}
1
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
  → 模型根据结果回答用户
1
2
3
4
5
6
7
8

到这里才算写完了一个最小但完整的 MCP 接入。真实项目通常只需要把示例中的内存数组替换为文件、数据库或 API,并补上身份传递、服务端权限过滤、超时、错误处理和审计。传输方式不会替代认证与授权:远程服务还要校验身份、令牌受众、权限范围和每次操作的业务约束。

# 生产安全边界

  1. Server 不信任模型参数,也不信任来自文档的指令;
  2. Host 只加载用户允许的 Server 和能力;
  3. 读写工具分离,写操作显示明确预览并绑定用户审批;
  4. 凭据保存在 Server 或安全执行环境,不进入模型上下文;
  5. 输出限制大小、去除敏感字段,并标记外部内容不可信;
  6. 记录 Server、工具、参数摘要、调用结果和审批主体;
  7. 远程 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 怎样让成熟任务方法得到稳定复用。

# 参考资料

上次更新时间: 2026年09月10日 00:05:23