MCP开发与应用
Model Context Protocol (MCP) 是 Anthropic 于 2024 年 11 月开源的开放标准,用于让 AI 应用以统一、安全、可控的方式连接外部数据源与工具。2025 年它已成为事实标准:OpenAI(Agents SDK 与 Responses API)、Google(ADK / Gemini)等主流厂商相继采纳。本文基于 2026 年的真实协议与官方 SDK 介绍 MCP 的核心概念、架构、开发实践与安全要点,可直接作为面试回答。
目录
- 📦 唯一官方 Node.js SDK
- 🚀 快速开始:30 行写一个 MCP Server
- 🎯 学习目标
- 🔍 MCP 核心概念
- 🏗️ MCP 架构设计
- 🔌 传输层:stdio 与 Streamable HTTP
- 🖥️ MCP 服务器开发
- 💻 MCP 客户端开发
- 🔐 安全性:面试必答
- 🌐 生态与采纳现状
- 📚 延伸阅读
📦 唯一官方 Node.js SDK
MCP 生态里 不存在 @mcp/core、@mcp/resources、@mcp/tools、mcp-express 这类包(历史教程中常见的虚构示例)。Node/TypeScript 唯一官方 SDK 是:
npm install @modelcontextprotocol/sdk zod
核心导出(按子路径导入):
| 用途 | 导入路径 | 关键类/对象 |
|---|---|---|
| 服务器 | @modelcontextprotocol/sdk/server/mcp.js | McpServer |
| stdio 传输(服务端) | @modelcontextprotocol/sdk/server/stdio.js | StdioServerTransport |
| Streamable HTTP 传输(服务端) | @modelcontextprotocol/sdk/server/streamableHttp.js | StreamableHTTPServerTransport |
| 客户端 | @modelcontextprotocol/sdk/client/index.js | Client |
| stdio 传输(客户端) | @modelcontextprotocol/sdk/client/stdio.js | StdioClientTransport |
| Streamable HTTP 传输(客户端) | @modelcontextprotocol/sdk/client/streamableHttp.js | StreamableHTTPClientTransport |
服务端高层 API 主要是:server.tool()(或 registerTool)、server.resource()(或 registerResource)、server.prompt()(或 registerPrompt),并用 Zod 描述入参 Schema。其他语言官方还提供 Python (mcp / modelcontextprotocol)、TypeScript、Java、Kotlin、C#、Go 等 SDK。
官方站点:https://modelcontextprotocol.io,协议规范仓库:modelcontextprotocol/specification。
🚀 快速开始:30 行写一个 MCP Server
下面用 stdio 传输暴露一个「查询天气」的工具,可被 Claude Desktop / Cursor 等宿主直接拉起:
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: "weather-server", version: "1.0.0" });
// 注册一个工具:模型可控(model-controlled)
server.tool(
"get_weather",
"获取指定城市的实时天气",
{ city: z.string().describe("城市名称,如北京、上海") },
async ({ city }) => {
// 实际项目中替换为真实天气 API 调用
const text = `【${city}】当前天气:晴朗,25℃`;
return { content: [{ type: "text", text }] };
}
);
// stdio 传输:宿主以子进程方式启动本进程,stdin/stdout 上收发 JSON-RPC
const transport = new StdioServerTransport();
await server.connect(transport);
// 注意:日志必须走 stderr,stdout 仅用于 JSON-RPC,否则会污染协议
console.error("weather MCP server ready");
要点:工具返回值的 content 是块数组([{ type: "text", text }]),不是单个对象;这是真实 SDK 的约定。
🎯 学习目标
通过本文学习,你将掌握:
- MCP 的核心概念与 Host / Client / Server 三层架构
- 三种能力原语 Tools / Resources / Prompts 的语义与控制方主体
- 基于 JSON-RPC 2.0 的
initialize握手与消息模型 - 两种主流传输:stdio(本地)与 Streamable HTTP(2025 远程标准)
- 用官方 SDK
@modelcontextprotocol/sdk开发 Server 与 Client - MCP 安全风险与最佳实践(提示注入、工具投毒、最小权限、HITL、供应链审计、OAuth 2.1)
🔍 MCP 核心概念
MCP 解决什么问题
在 MCP 之前,每个 AI 应用要接一个数据源/工具,就得写一套私有适配(M 个应用 × N 个工具 = M×N 个集成)。MCP 把它标准化为「一次实现、处处可用」:工具方实现一个 MCP Server,任何兼容 MCP 的宿主都能直接接入,复杂度从 M×N 降为 M+N。它常被类比为「AI 应用的 USB-C 接口」。
三种能力原语:Tools / Resources / Prompts
MCP Server 对外暴露三类能力,区别在于「由谁来控制调用」:
| 原语 | 控制方 | 语义 | 类比 |
|---|---|---|---|
| Tools(工具) | 模型控制 | 模型在推理中自行决定调用,有副作用(查询、写库、发请求) | 函数调用 / POST |
| Resources(资源) | 应用控制 | 由宿主应用决定把哪些只读上下文喂给模型(文件、记录、文档) | 只读数据 / GET |
| Prompts(提示) | 用户控制 | 预置的提示模板/工作流,通常由用户显式触发(如斜杠命令) | 模板 / 快捷指令 |
这套「谁控制」的划分是面试高频考点:Tools 是模型主动调,Resources 是应用主动喂,Prompts 是用户主动选。
MCP vs 传统集成方式
| 特性 | 传统私有集成 | MCP |
|---|---|---|
| 标准化 | 各自实现、互不通用 | 统一协议、跨宿主复用 |
| 集成复杂度 | M×N | M+N |
| 能力发现 | 文档约定 | 运行时 tools/list 等动态发现 |
| 传输 | 各自约定 | 标准化 stdio / Streamable HTTP |
| 生态 | 封闭 | 开放,官方与社区大量现成 Server |
🏗️ MCP 架构设计
Host / Client / Server 三层模型
MCP 采用清晰的三层职责划分:
- Host(宿主):用户直接使用的 AI 应用,如 Claude Desktop、Cursor、ChatGPT、各类 IDE/Agent 运行时。Host 负责承载大模型、管理会话与权限,并在内部为每个外部 Server 创建一个 Client。
- Client(客户端):由 Host 内嵌、与某个 Server 保持 1:1 连接的协议组件,负责能力协商、消息收发。
- Server(服务器):独立进程/服务,对外暴露 Tools / Resources / Prompts,对接真实数据源与工具。
记忆点:一个 Host 内可有多个 Client,每个 Client 1:1 连一个 Server;Server 之间彼此隔离、互不感知。
JSON-RPC 2.0 与 initialize 握手
MCP 的线协议是 JSON-RPC 2.0,三种消息:请求(带 id,需响应)、响应(带 id,含 result 或 error)、通知(无 id,不需响应)。
连接建立时先进行 initialize 握手:Client 发送自己支持的 protocolVersion 与 capabilities,Server 回应自己的版本与能力,Client 再发 notifications/initialized 通知确认。协议版本采用日期串(截至 2026 年常见为 2025-06-18)。
// Client -> Server:初始化请求
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": {}, "resources": {}, "prompts": {} },
"clientInfo": { "name": "my-host", "version": "1.0.0" }
}
}
// Server -> Client:初始化响应(声明自身能力)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true, "listChanged": true },
"prompts": { "listChanged": true }
},
"serverInfo": { "name": "weather-server", "version": "1.0.0" }
}
}
握手完成后,常用方法包括 tools/list、tools/call、resources/list、resources/read、prompts/list、prompts/get 等。
数据流程
🔌 传输层:stdio 与 Streamable HTTP
MCP 把「消息语义」与「传输方式」解耦。2026 年官方主推两种传输:
| 传输 | 适用场景 | 形态 | 说明 |
|---|---|---|---|
| stdio | 本地子进程(首选) | 宿主拉起 Server 子进程,stdin/stdout 收发 JSON-RPC | 无网络、低延迟、最简单,适合 IDE/本地工具 |
| Streamable HTTP | 远程服务(2025 远程标准) | 单一 /mcp 端点,POST 发请求,必要时以 SSE 流式返回 | 防火墙友好、可水平扩展、支持鉴权 |
⚠️ 重要:旧的 HTTP+SSE「双端点」传输(一个 GET
/sse建流 + 一个 POST/messages发消息)已在 2025-03-26 版本被 Streamable HTTP 取代并标记为 deprecated。新项目远程传输一律用 Streamable HTTP,不要再新接 deprecated 的 SSE transport。
Streamable HTTP 服务端最小示例:
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { randomUUID } from "node:crypto";
import { z } from "zod";
const app = express();
app.use(express.json());
function buildServer() {
const server = new McpServer({ name: "remote-weather", version: "1.0.0" });
server.tool("get_weather", "查询天气", { city: z.string() }, async ({ city }) => ({
content: [{ type: "text", text: `${city}:晴 25℃` }],
}));
return server;
}
// 单一 /mcp 端点同时承载请求与(按需的)SSE 流
app.all("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
});
const server = buildServer();
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000, () => console.error("MCP Streamable HTTP on :3000/mcp"));
🖥️ MCP 服务器开发
注册工具(Tools)
工具是「模型可控、可能有副作用」的能力,入参用 Zod 声明:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "demo", version: "1.0.0" });
server.tool(
"create_issue",
"在项目中创建一个 issue(高危:会写入外部系统)",
{
title: z.string().describe("标题"),
body: z.string().optional().describe("正文"),
},
async ({ title, body }) => {
const issue = await createIssueInTracker({ title, body }); // 你的真实实现
return { content: [{ type: "text", text: `已创建 #${issue.id}` }] };
}
);
工具出错时,推荐返回带 isError: true 的结果而非抛异常,让模型能感知并自我纠正:
return { content: [{ type: "text", text: "数据库连接失败" }], isError: true };
注册资源(Resources)
资源是「应用可控的只读上下文」,用 URI 标识;可以是静态 URI,也可以用模板:
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
// 静态资源
server.resource("readme", "file:///app/README.md", async (uri) => ({
contents: [{ uri: uri.href, mimeType: "text/markdown", text: await readReadme() }],
}));
// 模板资源:动态参数
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(await getUser(userId)) }],
})
);
注册提示(Prompts)
提示是「用户可控的模板化工作流」,常映射为宿主里的斜杠命令:
server.prompt(
"code-review",
"对给定代码做结构化审查",
{ code: z.string().describe("待审查代码") },
({ code }) => ({
messages: [
{
role: "user",
content: { type: "text", text: `请从可读性、性能、安全三方面审查:\n\n${code}` },
},
],
})
);
💻 MCP 客户端开发
宿主侧通过 Client 连接 Server。下面演示以 stdio 拉起本地 Server 并调用工具:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["./weather-server.js"],
});
const client = new Client({ name: "my-host", version: "1.0.0" });
await client.connect(transport); // 内部完成 initialize 握手
// 1) 发现工具
const { tools } = await client.listTools();
console.log("可用工具:", tools.map((t) => t.name));
// 2) 调用工具
const result = await client.callTool({
name: "get_weather",
arguments: { city: "北京" },
});
console.log(result.content);
// 3) 读取资源
const res = await client.readResource({ uri: "file:///app/README.md" });
连接远程 Server 时,把传输换成 StreamableHTTPClientTransport(new URL("https://host/mcp")) 即可,其余调用方式一致。
🔐 安全性:面试必答
MCP 把外部世界引入模型,安全是核心考点。要点如下:
-
提示注入(Prompt Injection)与工具投毒(Tool Poisoning)
- 工具返回的内容、资源文本可能藏有恶意指令,诱导模型执行越权动作。
- 工具的
description/ 参数说明本身也可能被投毒(让模型误用工具)。 - 缓解:对 Server 返回内容做不可信处理、隔离展示、必要时做内容审查;固定/审计工具描述。
-
最小权限(Least Privilege)
- Server 只暴露必要的工具与资源;数据库账号、文件目录、API scope 都按最小集授予。
- 为高危工具与只读工具分离凭据。
-
高危工具的人工确认(HITL,Human-in-the-Loop)
- 删除、转账、发邮件、写生产库等有副作用的工具,应在宿主侧弹出确认。
- 设计工具时标注危险等级,宿主据此决定是否需要人工批准。
-
Server 供应链审计
- 第三方 MCP Server 等同于在你环境里运行第三方代码。安装前审查来源、权限、依赖;锁定版本;优先官方/可信发布者。
- 把「MCP Server 审查」纳入安全评审与发布清单。
-
远程 OAuth 2.1 授权
- 远程(Streamable HTTP)Server 的鉴权采用 OAuth 2.1:基于 token 的授权、PKCE、scope 限定;Server 充当资源服务器,校验访问令牌。
- 切忌把长效密钥硬编码进客户端配置。
-
传输与隔离
- 远程一律 HTTPS;校验
Origin、绑定会话;对 stdio Server 控制其可访问的本地资源边界。
- 远程一律 HTTPS;校验
🌐 生态与采纳现状
- Anthropic:2024.11 开源 MCP,Claude Desktop / Claude Code 原生支持。
- OpenAI:Responses API 支持 MCP(可直接挂远程 MCP Server),Agents SDK 亦内置 MCP 接入。
- Google:ADK(Agent Development Kit)/ Gemini 生态采纳 MCP。
- IDE / 工具:Cursor、VS Code、各类 Agent 运行时广泛支持。
- 官方与社区 Server:filesystem、git、github、postgres、sqlite、slack、puppeteer 等大量现成实现可直接复用。
到 2026 年,MCP 已是连接「模型 ↔ 工具/数据」的通用标准;掌握它的三层架构、三种原语、两种传输与安全实践,是 AI 工程面试的必备项。
📚 延伸阅读
- 官方文档:https://modelcontextprotocol.io
- 协议规范:modelcontextprotocol/specification
- TypeScript SDK:
@modelcontextprotocol/sdk - 本站延伸:MCP高级特性与最佳实践、MCP企业级应用案例、MCP、SSE 与 WebSocket:分层原理与协作关系
💡 面试提示:被问到 MCP,先用一句话定位——「MCP 是 AI 应用连接外部工具/数据的开放标准,Anthropic 2024.11 开源、2025 成事实标准」;再展开 Host/Client/Server 三层、Tools/Resources/Prompts 三原语、stdio/Streamable HTTP 两传输、JSON-RPC 2.0 + initialize 握手,最后落到 安全(提示注入、最小权限、HITL、供应链、OAuth 2.1)。代码层面强调唯一官方 SDK
@modelcontextprotocol/sdk。