MCP 协议深度解析与 Server 开发实战
AI 导读
MCP 协议深度解析与 Server 开发实战 Model Context Protocol 架构原理、TypeScript Server 实现、工具/资源/提示模式与安全设计 引言 Model Context Protocol(MCP)是 Anthropic 于 2024 年底发布的开放协议,旨在为大语言模型提供标准化的上下文接入方式。它解决了一个根本问题:LLM...
MCP 协议深度解析与 Server 开发实战
Model Context Protocol 架构原理、TypeScript Server 实现、工具/资源/提示模式与安全设计
引言
Model Context Protocol(MCP)是 Anthropic 于 2024 年底发布的开放协议,旨在为大语言模型提供标准化的上下文接入方式。它解决了一个根本问题:LLM 应用需要连接各种外部数据源和工具,但每个集成都需要定制化开发,导致 M x N 的组合爆炸。
MCP 的核心思想是将"模型如何获取上下文"这一问题抽象为统一协议,就像 USB 协议统一了外设接入标准一样。
协议架构
整体拓扑
┌──────────────────────────────────────────────────────────┐
│ Host Application │
│ (Claude Desktop / VS Code / Cursor / Custom Client) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Client A│ │ Client B│ │ Client C│ │ Client D│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
└───────┼────────────┼────────────┼────────────┼──────────┘
│ │ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│Server A │ │Server B │ │Server C │ │Server D │
│(Files) │ │(DB) │ │(API) │ │(Tools) │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
Host 应用内部为每个 MCP Server 维护一个独立的 Client 实例。每个 Client-Server 对通过 JSON-RPC 2.0 通信,互相隔离,互不干扰。
三大核心原语
MCP 定义了三种核心原语(Primitives),分别面向不同的交互场景:
| 原语 | 控制方 | 描述 | 典型用途 |
|---|---|---|---|
| Tools | 模型控制 | 可执行的函数,模型自主决定何时调用 | 查询数据库、调用 API、执行计算 |
| Resources | 应用控制 | 结构化数据暴露,类似 REST 端点 | 文件内容、数据库记录、配置 |
| Prompts | 用户控制 | 预定义的提示模板,用户选择触发 | 代码审查模板、报告生成模板 |
这种三角设计的精妙之处在于:控制权分散到了模型、应用和用户三方,避免了单点滥用。
传输层
MCP 支持两种传输方式:
stdio 传输(本地进程):
Host ──stdin/stdout──▶ Server Process
HTTP + SSE 传输(远程服务):
Client ──HTTP POST──▶ Server /message
Client ◀──SSE Stream── Server /sse
stdio 适用于本地工具(如文件系统、Git),延迟极低。HTTP+SSE 适用于远程服务,支持认证和网络穿透。
TypeScript Server 开发实战
项目初始化
// package.json
{
"name": "mcp-server-example",
"version": "1.0.0",
"type": "module",
"bin": { "mcp-example": "./dist/index.js" },
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.23.0"
}
}
最小可用 Server
// src/index.ts
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: "demo-server",
version: "1.0.0",
capabilities: {
tools: {},
resources: {},
prompts: {},
},
});
// Register a tool
server.tool(
"calculate",
"Perform arithmetic calculations",
{
expression: z.string().describe("Math expression to evaluate"),
},
async ({ expression }) => {
try {
// Use Function constructor for safe evaluation
const result = new Function(`return (${expression})`)();
return {
content: [{ type: "text", text: `Result: ${result}` }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
// Register a resource
server.resource(
"config",
"config://app/settings",
{ mimeType: "application/json" },
async () => ({
contents: [{
uri: "config://app/settings",
text: JSON.stringify({ theme: "dark", language: "zh-CN" }),
}],
})
);
// Register a prompt
server.prompt(
"code-review",
"Code review template with focus area",
{ focus: z.string().optional().describe("Review focus: security|performance|readability") },
async ({ focus }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please review the following code with focus on ${focus ?? "general quality"}.
Provide specific, actionable feedback with line references.`,
},
}],
})
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
}
main().catch(console.error);
工具模式进阶
实际开发中,工具设计需要考虑参数校验、错误处理和进度反馈:
// Advanced tool with progress reporting and structured output
server.tool(
"query-database",
"Execute read-only SQL queries against the analytics database",
{
sql: z.string().describe("SQL SELECT query"),
limit: z.number().default(100).describe("Maximum rows to return"),
format: z.enum(["table", "json", "csv"]).default("table"),
},
async ({ sql, limit, format }, { reportProgress }) => {
// Input validation: only allow SELECT
const normalized = sql.trim().toUpperCase();
if (!normalized.startsWith("SELECT")) {
return {
content: [{ type: "text", text: "Error: Only SELECT queries are allowed" }],
isError: true,
};
}
// Report progress for long-running queries
await reportProgress({ progress: 0, total: 100 });
const db = await getConnection();
const safeSql = `${sql} LIMIT ${limit}`;
const rows = await db.query(safeSql);
await reportProgress({ progress: 100, total: 100 });
// Format output based on requested format
let output: string;
switch (format) {
case "json":
output = JSON.stringify(rows, null, 2);
break;
case "csv":
output = rowsToCsv(rows);
break;
default:
output = rowsToMarkdownTable(rows);
}
return {
content: [{
type: "text",
text: `Query returned ${rows.length} rows:\n\n${output}`,
}],
};
}
);
资源模式进阶
资源支持 URI 模板,允许动态参数化访问:
// Dynamic resource with URI template
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
{ mimeType: "application/json" },
async (uri, { userId }) => {
const user = await userService.findById(userId);
if (!user) {
throw new Error(`User ${userId} not found`);
}
return {
contents: [{
uri: uri.href,
text: JSON.stringify({
id: user.id,
name: user.name,
role: user.role,
lastActive: user.lastActive,
}),
}],
};
}
);
// Resource with subscription support for live updates
server.resource(
"system-metrics",
"metrics://system/current",
{ mimeType: "application/json" },
async () => {
const metrics = await collectMetrics();
return {
contents: [{
uri: "metrics://system/current",
text: JSON.stringify(metrics),
}],
};
}
);
// Notify clients when metrics change
setInterval(async () => {
server.notification({
method: "notifications/resources/updated",
params: { uri: "metrics://system/current" },
});
}, 30000);
安全设计
威胁模型
┌─────────────────────────────────────────────────┐
│ MCP 威胁面分析 │
├──────────────────┬──────────────────────────────┤
│ 威胁 │ 缓解措施 │
├──────────────────┼──────────────────────────────┤
│ 提示注入 │ Server 端输入消毒 + 输出标注 │
│ 权限提升 │ 最小权限原则 + 能力声明 │
│ 数据泄露 │ 资源访问控制 + 审计日志 │
│ 拒绝服务 │ 速率限制 + 超时 + 资源配额 │
│ 中间人攻击 │ TLS + 认证令牌 + 签名校验 │
│ 工具滥用 │ 操作确认 + 副作用声明 │
└──────────────────┴──────────────────────────────┘
权限与认证实现
// Middleware-style permission checking
function withPermission(requiredScope: string) {
return (handler: ToolHandler): ToolHandler => {
return async (params, context) => {
const clientId = context.meta?.clientId;
const allowed = await checkPermission(clientId, requiredScope);
if (!allowed) {
return {
content: [{
type: "text",
text: `Permission denied: requires scope '${requiredScope}'`,
}],
isError: true,
};
}
// Audit log every tool invocation
await auditLog({
clientId,
tool: context.toolName,
scope: requiredScope,
params: sanitize(params),
timestamp: Date.now(),
});
return handler(params, context);
};
};
}
// Usage: wrap sensitive tools with permission checks
server.tool(
"delete-record",
"Delete a database record (requires write scope)",
{ id: z.string(), table: z.string() },
withPermission("db:write")(async ({ id, table }) => {
await db.delete(table, id);
return { content: [{ type: "text", text: `Deleted ${table}/${id}` }] };
})
);
输入消毒与输出安全
// Sanitize tool inputs to prevent injection
function sanitizeInput(input: string): string {
// Remove potential prompt injection markers
return input
.replace(/\b(ignore|forget|disregard)\s+(previous|above|all)\b/gi, "[FILTERED]")
.replace(/<\/?system>/gi, "[FILTERED]")
.trim();
}
// Mark tool outputs to help LLM distinguish data from instructions
function wrapOutput(data: string, source: string): string {
return `[BEGIN DATA from ${source}]\n${data}\n[END DATA from ${source}]`;
}
生产部署模式
HTTP+SSE 远程部署
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
// Health check endpoint
app.get("/health", (req, res) => {
res.json({ status: "ok", version: "1.0.0" });
});
// SSE endpoint for server-to-client messages
app.get("/sse", async (req, res) => {
const authHeader = req.headers.authorization;
if (!validateToken(authHeader)) {
res.status(401).json({ error: "Unauthorized" });
return;
}
const transport = new SSEServerTransport("/message", res);
await server.connect(transport);
});
// Message endpoint for client-to-server messages
app.post("/message", async (req, res) => {
// Route message to the correct transport based on session
await transport.handlePostMessage(req, res);
});
app.listen(3001, () => {
console.log("MCP HTTP server listening on :3001");
});
客户端配置
{
"mcpServers": {
"remote-analytics": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.example.com/sse"],
"env": {
"MCP_AUTH_TOKEN": "${MCP_ANALYTICS_TOKEN}"
}
},
"local-filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"],
"env": {}
}
}
}
调试与测试
使用 MCP Inspector
# Start the inspector for interactive testing
npx @modelcontextprotocol/inspector node dist/index.js
# The inspector provides a web UI at http://localhost:5173
# where you can test tools, resources, and prompts interactively
单元测试
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
describe("MCP Server", () => {
let client: Client;
beforeEach(async () => {
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
client = new Client({ name: "test-client", version: "1.0.0" });
await client.connect(clientTransport);
});
it("should list tools", async () => {
const result = await client.listTools();
expect(result.tools).toHaveLength(2);
expect(result.tools[0].name).toBe("calculate");
});
it("should execute calculate tool", async () => {
const result = await client.callTool({
name: "calculate",
arguments: { expression: "2 + 3 * 4" },
});
expect(result.content[0].text).toContain("14");
});
});
设计原则总结
- 单一职责:每个 MCP Server 聚焦一个领域(文件系统、数据库、特定 API),不要构建全能 Server。
- 最小权限:Server 只暴露模型真正需要的能力,工具粒度越细越安全。
- 幂等优先:读操作无条件允许,写操作必须有确认机制或幂等保证。
- 错误透明:工具失败时返回
isError: true和人类可读的错误信息,不要隐藏错误。 - 可观测性:所有工具调用记录审计日志,包含调用方、参数、结果和延迟。
MCP 协议的真正价值不在于"又一个新协议",而在于它把 LLM 与外部世界的交互标准化了。随着生态成熟,MCP 有望成为 AI 应用的事实标准接口层。
Maurice | [email protected]
深度加工(NotebookLM 生成)
基于本文内容生成的 PPT 大纲、博客摘要、短视频脚本与 Deep Dive 播客,用于多场景复用
PPT 大纲(5-8 张幻灯片) 点击展开
MCP 协议深度解析与 Server 开发实战 — ppt
这是一份基于您提供的《MCP 协议深度解析与 Server 开发实战》文章生成的 PPT 大纲。共包含 7 张幻灯片,采用 Markdown 格式输出:
1. MCP 协议简介与核心价值
- 发布背景:Model Context Protocol (MCP) 是 Anthropic 于 2024 年底发布的开放协议,旨在为大语言模型提供标准化的上下文接入方式 [1]。
- 解决核心痛点:解决了大模型应用连接外部数据源时,面临的 M x N 集成组合爆炸问题 [1]。
- 核心思想:将上下文获取抽象为统一标准,类似于统一外设接入的 USB 协议 [1]。
- 发展愿景:通过标准化 LLM 与外部世界的交互,MCP 有望成为 AI 应用的事实标准接口层 [2]。
2. 协议架构与传输层机制
- 整体拓扑:Host 应用(如 Claude Desktop 等)内部为每个 MCP Server 维护一个独立且互不干扰的 Client 实例 [1]。
- 通信标准:Client 与 Server 之间通过标准的 JSON-RPC 2.0 协议进行通信 [1]。
- 本地传输模式:使用 stdio 传输(标准输入/输出),延迟极低,适用于文件系统等本地工具 [1]。
- 远程传输模式:使用 HTTP + SSE 传输,支持认证和网络穿透,适合部署远程服务 [1]。
3. MCP 三大核心原语解析
- 三角设计优势:控制权被巧妙地分散到模型、应用和用户三方,有效避免了单点滥用问题 [1]。
- Tools (工具):由“模型控制”的可执行函数,大模型可自主决定何时调用,如查询数据库或执行计算 [1]。
- Resources (资源):由“应用控制”的结构化数据,类似 REST 端点,支持 URI 模板和动态参数化访问 [1, 3]。
- Prompts (提示词):由“用户控制”的预定义模板,如代码审查模板等,供用户主动选择触发 [1, 3]。
4. TypeScript Server 开发实战
- 极速初始化:利用
@modelcontextprotocol/sdk和 Zod 库,可快速搭建包含参数校验的最小可用 Server [1]。 - 进度反馈机制:在执行长耗时任务(如复杂 SQL 查询)时,支持通过
reportProgressAPI 向客户端汇报进度 [3]。 - 多格式输出:工具开发中可以根据需求,灵活支持返回 JSON、CSV 或 Markdown 表格等多种结构化结果 [3]。
- 实时状态订阅:资源模式支持订阅功能,Server 端可通过定时发送
notification来实现客户端数据的实时更新 [4]。
5. 安全设计与威胁缓解策略
- 细粒度权限控制:遵循最小权限原则,可通过中间件风格拦截器实现基于作用域 (Scope) 的权限校验 [4]。
- 输入消毒处理:对工具输入进行净化(过滤敏感词、标签等),有效防范恶意提示词注入攻击 [4]。
- 输出安全标注:使用特定标记包裹工具输出数据,帮助大语言模型区分原始数据与系统指令 [2, 4]。
- 全面审计日志:强烈建议对所有工具调用记录审计日志,包含调用方、参数和时间戳,以追踪潜在的数据泄露风险 [4]。
6. 生产部署与测试调试方案
- 远程部署实践:通过 Express 框架结合
SSEServerTransport可搭建 HTTP+SSE 生产服务,并集成 Token 认证 [2]。 - 客户端灵活配置:客户端配置文件可同时配置本地进程 Server 和携带认证信息的远程 Server [2]。
- 可视化交互调试:使用官方提供的 MCP Inspector 工具,开发者可以在 Web UI 中交互式测试各类原语 [2]。
- 单元测试体系:借助
InMemoryTransport模块,可以在代码层面对 Server 进行快速、完善的自动化集成测试 [2]。
7. Server 开发五大核心设计原则
- 单一职责:每个 Server 应专注单一领域(如专门处理文件或数据库),避免构建大而全的全能 Server [2]。
- 最小权限:仅向模型暴露真正需要的精简能力,工具粒度拆分得越细越安全 [2]。
- 幂等优先:读操作无条件允许,但写操作必须有用户确认机制或保证其幂等性 [2]。
- 错误透明:遇到工具执行失败时,不要隐藏错误,应返回人类可读的错误信息且标记
isError: true[2]。 - 可观测性:必须建立完善的调用链路日志监控,记录核心参数、结果和延迟信息 [2]。
博客摘要 + 核心看点 点击展开
MCP 协议深度解析与 Server 开发实战 — summary
这是一份为您量身定制的 SEO 友好博客摘要及核心看点:
博客摘要
本文深度解析 Anthropic 最新发布的 Model Context Protocol (MCP) 协议,探讨其如何为大语言模型 (LLM) 提供标准化的外部上下文接入方案 [1]。文章从 MCP 的三大核心原语(Tools、Resources、Prompts)及双重传输层机制入手,剖析了其解决 AI 应用集成碎片化的底层架构 [1]。结合 TypeScript 实战,详细演示了从最小可用 Server 到进阶工具开发的完整流程 [1, 2]。此外,文章全面梳理了针对生产环境的安全防护方案(如防提示注入与权限管控)[3],并详述了 HTTP+SSE 远程部署模式及核心设计原则 [4]。本指南是开发者构建下一代标准化 AI 应用的必读之作。
核心看点
- 统一的标准化架构:MCP 定义了 Tools、Resources 和 Prompts 三大核心原语,巧妙实现了控制权的去中心化 [1]。
- TypeScript 开发实战:覆盖从基础 Server 搭建到动态资源订阅、带进度反馈工具开发的高阶全流程 [1, 2]。
- 高阶安全与部署方案:内置输入消毒与细粒度权限管控机制,并详述 HTTP+SSE 远程部署及单一职责等原则 [3, 4]。
60 秒短视频脚本 点击展开
MCP 协议深度解析与 Server 开发实战 — video
钩子开场:
AI 时代的 USB 接口来了![1]
核心解说:
MCP如大模型USB接口,统一数据接入标准,彻底解决集成难题。[1]
定义工具、资源和提示三大原语,巧妙分散控制权,避免单点滥用。[1]
支持本地与远程传输,坚持最小权限原则,严防数据泄露与注入。[1, 2]
收束:
MCP 有望成为 AI 应用的事实标准接口层![3]
课后巩固
与本文内容匹配的闪卡与测验,帮助巩固所学知识
延伸阅读
根据本文主题,为你推荐相关的学习资料