核心架构
了解 MCP 如何连接客户端、服务器和 LLM
模型上下文协议 (MCP) 建立在灵活、可扩展的架构之上,可实现 LLM 应用程序和集成之间的无缝通信。本文档涵盖了核心架构组件和概念。
概述
MCP 遵循客户端-服务器架构,其中:
- 主机是发起连接的 LLM 应用程序(如 Claude Desktop 或 IDE)
- 客户端在主机应用程序内部与服务器保持 1:1 连接
- 服务器向客户提供上下文、工具和提示
Server Process
Server Process
Host
Transport Layer
Transport Layer
MCP Client
MCP Client
MCP Server
MCP Server
核心组件
协议层
协议层处理消息框架、请求/响应链接和高级通信模式。
- TypeScript
- Python
class Protocol<Request, Notification, Result> {
// Handle incoming requests
setRequestHandler<T>(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise<Result>): void
// Handle incoming notifications
setNotificationHandler<T>(schema: T, handler: (notification: T) => Promise<void>): void
// Send requests and await responses
request<T>(request: Request, schema: T, options?: RequestOptions): Promise<T>
// Send one-way notifications
notification(notification: Notification): Promise<void>
}
主要课程包括:
Protocol
Client
Server
传输层
传输层负责处理客户端和服务器之间的实际通信。MCP 支持多种传输机制:
-
Stdio 传输
- 使用标准输入/输出进行通信
- 非常适合本地流程
-
带有 SSE 传输的 HTTP
- 使用服务器发送事件来发送服务器到客户端的消息
- 客户端到服务器消息的 HTTP POST
所有传输均使用JSON-RPC 2.0 交换消息。有关模型上下文协议 (MCP) 消息格式的详细信息,请参阅规范。
消息类型
MCP 有以下主要类型的消息:
-
请求期望得到对方的响应:
interface Request { method: string; params?: { ... }; }
-
结果是对请求的成功响应:
interface Result { [key: string]: unknown; }
-
错误表明请求失败:
interface Error { code: number; message: string; data?: unknown; }
-
通知是单向消息,不期望得到响应:
interface Notification { method: string; params?: { ... }; }
连接生命周期
1.初始化
ServerClientServerClientConnection ready for useinitialize requestinitialize responseinitialized notification
- 客户端发送
initialize
带有协议版本和功能的请求 - 服务器以其协议版本和功能进行响应
- 客户端发送
initialized
通知作为确认 - 开始正常消息交换
2. 消息交换
初始化后,支持以下模式:
- 请求-响应:客户端或服务器发送请求,对方响应
- 通知:任何一方发送单向消息
3. 终止
任何一方都可以终止连接:
- 通过以下方式干净关机
close()
- 传输断开
- 错误条件
错误处理
MCP 定义了以下标准错误代码:
enum ErrorCode {
// Standard JSON-RPC error codes
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603
}
SDK 和应用程序可以定义自己的高于 -32000 的错误代码。
错误通过以下方式传播:
- 对请求的错误响应
- 传输中的错误事件
- 协议级错误处理程序
实现示例
以下是实现 MCP 服务器的基本示例:
- TypeScript
- Python
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {
resources: {}
}
});
// Handle requests
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "example://resource",
name: "Example Resource"
}
]
};
});
// Connect transport
const transport = new StdioServerTransport();
await server.connect(transport);
根
理解 MCP 中的根源
根是 MCP 中的一个概念,它定义了服务器可以运行的边界。它为客户端提供了一种方式,可以告知服务器相关资源及其位置。
什么是根?
根是客户端建议服务器关注的 URI。当客户端连接到服务器时,它会声明服务器应该使用哪些根。虽然根主要用于文件系统路径,但它可以是任何有效的 URI,包括 HTTP URL。
例如,根可以是:
file:///home/user/projects/myapp
https://api.example.com/v1
为什么要使用 Roots?
根有几个重要用途:
- 指导:它们向服务器告知相关资源和位置
- 清晰度:根目录明确哪些资源属于您的工作空间
- 组织:多个根使您可以同时使用不同的资源
根如何工作
当客户端支持根时,它:
roots
在连接期间声明能力- 向服务器提供建议的根列表
- 当根目录发生改变时通知服务器(如果支持)
虽然根是信息性的且不严格执行,但服务器应该:
- 尊重提供的根
- 使用根 URI 来定位和访问资源
- 优先考虑根边界内的操作
常见用例
根通常用于定义:
- 项目目录
- 存储库位置
- API 端点
- 配置位置
- 资源边界
最佳实践
处理根时:
- 仅建议必要的资源
- 使用清晰、描述性的名称来命名根
- 监控根可访问性
- 妥善处理根更改
例子
以下是典型的 MCP 客户端可能暴露根的方式:
{
"roots": [
{
"uri": "file:///home/user/projects/frontend",
"name": "Frontend Repository"
},
{
"uri": "https://api.example.com/v1",
"name": "API Endpoint"
}
]
}
此配置建议服务器关注本地存储库和 API 端点,同时保持它们在逻辑上分离。
最佳实践
运输选择
-
本地沟通
- 对本地进程使用 stdio 传输
- 高效同机通信
- 简单的流程管理
-
远程通信
- 对于需要 HTTP 兼容性的场景使用 SSE
- 考虑安全影响,包括身份验证和授权
消息处理
-
请求处理
- 彻底验证输入
- 使用类型安全模式
- 优雅地处理错误
- 实施超时
-
进度报告
- 对长时间操作使用进度标记
- 逐步报告进度
- 已知时包括总体进度
-
错误管理
- 使用适当的错误代码
- 包含有用的错误消息
- 发生错误时清理资源
安全注意事项
-
运输安全
- 使用 TLS 进行远程连接
- 验证连接来源
- 需要时实施身份验证
-
消息验证
- 验证所有传入消息
- 净化输入
- 检查邮件大小限制
- 验证 JSON-RPC 格式
-
资源保护
- 实施访问控制
- 验证资源路径
- 监视资源使用情况
- 速率限制请求
-
错误处理
- 不要泄露敏感信息
- 记录与安全相关的错误
- 实施适当的清理
- 处理 DoS 场景
调试和监控
-
日志记录
- 记录协议事件
- 跟踪消息流
- 监控性能
- 记录错误
-
诊断
- 实施健康检查
- 监视连接状态
- 跟踪资源使用情况
- 个人资料表现
-
测试
- 测试不同的传输方式
- 验证错误处理
- 检查边缘情况
- 负载测试服务器
资源
将服务器中的数据和内容公开给 LLM
资源是模型上下文协议 (MCP) 中的核心原语,允许服务器公开可由客户端读取并用作 LLM 交互上下文的数据和内容。
资源被设计为由应用程序控制,这意味着客户端应用程序可以决定如何以及何时使用它们。不同的 MCP 客户端可能会以不同的方式处理资源。例如:
- Claude Desktop 目前要求用户明确选择资源才能使用
- 其他客户端可能会根据启发式方法自动选择资源
- 一些实现甚至可能允许人工智能模型本身决定使用哪些资源
在实现资源支持时,服务器开发者应该准备好处理这些交互模式。为了自动向模型公开数据,服务器开发者应该使用模型控制的原语,例如Tools。
概述
资源是指 MCP 服务器希望向客户端提供的任何类型的数据。这些可以包括:
- 文件内容
- 数据库记录
- API 响应
- 实时系统数据
- 截图和图片
- 日志文件
- 以及更多
每个资源由唯一的 URI 标识,并且可以包含文本或二进制数据。
资源 URI
资源使用遵循以下格式的 URI 进行标识:
[protocol]://[host]/[path]
例如:
file:///home/user/documents/report.pdf
postgres://database/customers/schema
screen://localhost/display1
协议和路径结构由 MCP 服务器实现定义。服务器可以定义自己的自定义 URI 方案。
资源类型
资源可以包含两种类型的内容:
文本资源
文本资源包含 UTF-8 编码的文本数据。这些资源适用于:
- 源代码
- 配置文件
- 日志文件
- JSON/XML 数据
- 纯文本
二进制资源
二进制资源包含以 Base64 编码的原始二进制数据。这些资源适用于:
- 图片
- 音频文件
- 视频文件
- 其他非文本格式
资源发现
客户端可以通过两种主要方法发现可用资源:
直接资源
服务器通过端点公开具体资源列表resources/list
。每个资源包括:
{
uri: string; // Unique identifier for the resource
name: string; // Human-readable name
description?: string; // Optional description
mimeType?: string; // Optional MIME type
}
资源模板
对于动态资源,服务器可以公开URI 模板,客户端可以使用它来构建有效的资源 URI:
{
uriTemplate: string; // URI template following RFC 6570
name: string; // Human-readable name for this type
description?: string; // Optional description
mimeType?: string; // Optional MIME type for all matching resources
}
阅读资源
要读取资源,客户端需要resources/read
使用资源 URI 发出请求。
服务器以资源内容列表进行响应:
{
contents: [
{
uri: string; // The URI of the resource
mimeType?: string; // Optional MIME type
// One of:
text?: string; // For text resources
blob?: string; // For binary resources (base64 encoded)
}
]
}
服务器可能会在一次请求中返回多个资源resources/read
。例如,当读取目录时,可以返回目录中的文件列表。
资源更新
MCP通过两种机制支持资源的实时更新:
列出更改
当服务器可用资源列表发生变化时,服务器可以通过notifications/resources/list_changed
通知通知客户端。
内容变更
客户可以订阅特定资源的更新:
- 客户端发送
resources/subscribe
资源 URI notifications/resources/updated
资源发生变化时服务器发送- 客户端可以通过以下方式获取最新内容
resources/read
- 客户端可以取消订阅
resources/unsubscribe
示例实现
以下是在 MCP 服务器中实现资源支持的简单示例:
- TypeScript
- Python
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {
resources: {}
}
});
// List available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file:///logs/app.log",
name: "Application Logs",
mimeType: "text/plain"
}
]
};
});
// Read resource contents
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
if (uri === "file:///logs/app.log") {
const logContents = await readLogFile();
return {
contents: [
{
uri,
mimeType: "text/plain",
text: logContents
}
]
};
}
throw new Error("Resource not found");
});
提示
创建可重复使用的提示模板和工作流程
提示使服务器能够定义可重复使用的提示模板和工作流程,客户端可以轻松地将其呈现给用户和 LLM。它们提供了一种强大的方法来标准化和共享常见的 LLM 交互。
提示被设计为由用户控制,这意味着它们从服务器暴露给客户端,目的是让用户能够明确地选择它们来使用。
概述
MCP 中的提示是预定义的模板,可以:
- 接受动态参数
- 包括资源中的上下文
- 链接多个交互
- 指导具体的工作流程
- 表面作为 UI 元素(如斜线命令)
提示结构
每个提示定义为:
{
name: string; // Unique identifier for the prompt
description?: string; // Human-readable description
arguments?: [ // Optional list of arguments
{
name: string; // Argument identifier
description?: string; // Argument description
required?: boolean; // Whether argument is required
}
]
}
发现提示
客户端可以通过prompts/list
端点发现可用的提示:
// Request
{
method: "prompts/list"
}
// Response
{
prompts: [
{
name: "analyze-code",
description: "Analyze code for potential improvements",
arguments: [
{
name: "language",
description: "Programming language",
required: true
}
]
}
]
}
使用提示
要使用提示,客户端需要提出prompts/get
请求:
// Request
{
method: "prompts/get",
params: {
name: "analyze-code",
arguments: {
language: "python"
}
}
}
// Response
{
description: "Analyze Python code for potential improvements",
messages: [
{
role: "user",
content: {
type: "text",
text: "Please analyze the following Python code for potential improvements:\n\n```python\ndef calculate_sum(numbers):\n total = 0\n for num in numbers:\n total = total + num\n return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```"
}
}
]
}
动态提示
提示可以是动态的,包括:
嵌入式资源上下文
{
"name": "analyze-project",
"description": "Analyze project logs and code",
"arguments": [
{
"name": "timeframe",
"description": "Time period to analyze logs",
"required": true
},
{
"name": "fileUri",
"description": "URI of code file to review",
"required": true
}
]
}
处理prompts/get
请求时:
{
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Analyze these system logs and the code file for any issues:"
}
},
{
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "logs://recent?timeframe=1h",
"text": "[2024-03-14 15:32:11] ERROR: Connection timeout in network.py:127\n[2024-03-14 15:32:15] WARN: Retrying connection (attempt 2/3)\n[2024-03-14 15:32:20] ERROR: Max retries exceeded",
"mimeType": "text/plain"
}
}
},
{
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "file:///path/to/code.py",
"text": "def connect_to_service(timeout=30):\n retries = 3\n for attempt in range(retries):\n try:\n return establish_connection(timeout)\n except TimeoutError:\n if attempt == retries - 1:\n raise\n time.sleep(5)\n\ndef establish_connection(timeout):\n # Connection implementation\n pass",
"mimeType": "text/x-python"
}
}
}
]
}
多步骤工作流程
const debugWorkflow = {
name: "debug-error",
async getMessages(error: string) {
return [
{
role: "user",
content: {
type: "text",
text: `Here's an error I'm seeing: ${error}`
}
},
{
role: "assistant",
content: {
type: "text",
text: "I'll help analyze this error. What have you tried so far?"
}
},
{
role: "user",
content: {
type: "text",
text: "I've tried restarting the service, but the error persists."
}
}
];
}
};
示例实现
以下是在 MCP 服务器中实现提示的完整示例:
- TypeScript
- Python
import { Server } from "@modelcontextprotocol/sdk/server";
import {
ListPromptsRequestSchema,
GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types";
const PROMPTS = {
"git-commit": {
name: "git-commit",
description: "Generate a Git commit message",
arguments: [
{
name: "changes",
description: "Git diff or description of changes",
required: true
}
]
},
"explain-code": {
name: "explain-code",
description: "Explain how code works",
arguments: [
{
name: "code",
description: "Code to explain",
required: true
},
{
name: "language",
description: "Programming language",
required: false
}
]
}
};
const server = new Server({
name: "example-prompts-server",
version: "1.0.0"
}, {
capabilities: {
prompts: {}
}
});
// List available prompts
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: Object.values(PROMPTS)
};
});
// Get specific prompt
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const prompt = PROMPTS[request.params.name];
if (!prompt) {
throw new Error(`Prompt not found: ${request.params.name}`);
}
if (request.params.name === "git-commit") {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}`
}
}
]
};
}
if (request.params.name === "explain-code") {
const language = request.params.arguments?.language || "Unknown";
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}`
}
}
]
};
}
throw new Error("Prompt implementation not found");
});
工具
启用 LLM 通过您的服务器执行操作
工具是模型上下文协议 (MCP) 中一个强大的原语,它使服务器能够向客户端公开可执行功能。通过工具,LLM 可以与外部系统交互、执行计算并在现实世界中采取行动。
工具被设计为模型控制,这意味着工具从服务器暴露给客户端,目的是让 AI 模型能够自动调用它们(由人工参与批准)。
概述
MCP 中的工具允许服务器公开可执行函数,这些函数可供客户端调用,并由 LLM 用来执行操作。这些工具的关键方面包括:
- 发现
tools/list
:客户端可以通过端点列出可用的工具 - 调用:使用端点调用工具
tools/call
,服务器执行请求的操作并返回结果 - 灵活性:工具范围从简单的计算到复杂的 API 交互
与资源类似,工具也由唯一名称标识,并可包含用于指导其使用的描述。然而,与资源不同的是,工具代表着动态操作,可以修改状态或与外部系统交互。
工具定义结构
每个工具都按照以下结构定义:
{
name: string; // Unique identifier for the tool
description?: string; // Human-readable description
inputSchema: { // JSON Schema for the tool's parameters
type: "object",
properties: { ... } // Tool-specific parameters
},
annotations?: { // Optional hints about tool behavior
title?: string; // Human-readable title for the tool
readOnlyHint?: boolean; // If true, the tool does not modify its environment
destructiveHint?: boolean; // If true, the tool may perform destructive updates
idempotentHint?: boolean; // If true, repeated calls with same args have no additional effect
openWorldHint?: boolean; // If true, tool interacts with external entities
}
}
实施工具
以下是在 MCP 服务器中实现基本工具的示例:
- TypeScript
- Python
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {
tools: {}
}
});
// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [{
name: "calculate_sum",
description: "Add two numbers together",
inputSchema: {
type: "object",
properties: {
a: { type: "number" },
b: { type: "number" }
},
required: ["a", "b"]
}
}]
};
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "calculate_sum") {
const { a, b } = request.params.arguments;
return {
content: [
{
type: "text",
text: String(a + b)
}
]
};
}
throw new Error("Tool not found");
});
工具图案示例
以下是服务器可以提供的工具类型的一些示例:
系统操作
与本地系统交互的工具:
{
name: "execute_command",
description: "Run a shell command",
inputSchema: {
type: "object",
properties: {
command: { type: "string" },
args: { type: "array", items: { type: "string" } }
}
}
}
API 集成
包装外部 API 的工具:
{
name: "github_create_issue",
description: "Create a GitHub issue",
inputSchema: {
type: "object",
properties: {
title: { type: "string" },
body: { type: "string" },
labels: { type: "array", items: { type: "string" } }
}
}
}
数据处理
转换或分析数据的工具:
{
name: "analyze_csv",
description: "Analyze a CSV file",
inputSchema: {
type: "object",
properties: {
filepath: { type: "string" },
operations: {
type: "array",
items: {
enum: ["sum", "average", "count"]
}
}
}
}
}
错误处理
工具错误应在结果对象中报告,而不是作为 MCP 协议级错误报告。这样,LLM 才能发现并处理错误。当工具遇到错误时:
- 在结果中设置
isError
为true
content
在数组中包含错误详细信息
以下是工具正确错误处理的示例:
- TypeScript
- Python
try {
// Tool operation
const result = performOperation();
return {
content: [
{
type: "text",
text: `Operation successful: ${result}`
}
]
};
} catch (error) {
return {
isError: true,
content: [
{
type: "text",
text: `Error: ${error.message}`
}
]
};
}
这种方法允许 LLM 发现发生的错误并可能采取纠正措施或请求人工干预。
工具注释
工具注释提供有关工具行为的额外元数据,帮助客户端了解如何呈现和管理工具。这些注释只是描述工具性质和影响的提示,不应作为安全决策的依据。
工具注释的用途
工具注释有几个主要用途:
- 在不影响模型上下文的情况下提供特定于 UX 的信息
- 帮助客户适当分类和展示工具
- 传达有关工具潜在副作用的信息
- 协助开发直观的工具审批界面
可用的工具注释
MCP 规范为工具定义了以下注释:
注解 | 类型 | 默认 | 描述 |
---|---|---|---|
title | 细绳 | - | 工具的可读标题,有助于 UI 显示 |
readOnlyHint | 布尔值 | 错误的 | 如果为 true,则表示该工具不会修改其环境 |
destructiveHint | 布尔值 | 真的 | 如果为真,该工具可能会执行破坏性更新(仅当为readOnlyHint 假时才有意义) |
idempotentHint | 布尔值 | 错误的 | 如果为真,则使用相同参数重复调用该工具不会产生额外效果(仅当为readOnlyHint 假时才有意义) |
openWorldHint | 布尔值 | 真的 | 如果属实,该工具可能会与外部实体的“开放世界”进行交互 |
示例用法
以下是针对不同场景使用注释定义工具的方法:
// A read-only search tool
{
name: "web_search",
description: "Search the web for information",
inputSchema: {
type: "object",
properties: {
query: { type: "string" }
},
required: ["query"]
},
annotations: {
title: "Web Search",
readOnlyHint: true,
openWorldHint: true
}
}
// A destructive file deletion tool
{
name: "delete_file",
description: "Delete a file from the filesystem",
inputSchema: {
type: "object",
properties: {
path: { type: "string" }
},
required: ["path"]
},
annotations: {
title: "Delete File",
readOnlyHint: false,
destructiveHint: true,
idempotentHint: true,
openWorldHint: false
}
}
// A non-destructive database record creation tool
{
name: "create_record",
description: "Create a new record in the database",
inputSchema: {
type: "object",
properties: {
table: { type: "string" },
data: { type: "object" }
},
required: ["table", "data"]
},
annotations: {
title: "Create Database Record",
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: false
}
}
在服务器实现中集成注释
- TypeScript
- Python
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [{
name: "calculate_sum",
description: "Add two numbers together",
inputSchema: {
type: "object",
properties: {
a: { type: "number" },
b: { type: "number" }
},
required: ["a", "b"]
},
annotations: {
title: "Calculate Sum",
readOnlyHint: true,
openWorldHint: false
}
}]
};
});
采样
让你的服务器请求 LLM 完成
采样是 MCP 的一项强大功能,允许服务器通过客户端请求 LLM 完成,从而实现复杂的代理行为,同时保持安全性和隐私性。
Claude Desktop 客户端尚不支持 MCP 的此功能。
采样的工作原理
采样流程遵循以下步骤:
sampling/createMessage
服务器向客户端发送请求- 客户审核请求并可以修改
- 来自法学硕士 (LLM) 的客户样本
- 客户检查完成情况
- 客户端返回结果给服务器
这种人机交互设计确保用户能够控制 LLM 所看到和生成的内容。
消息格式
采样请求使用标准化的消息格式:
{
messages: [
{
role: "user" | "assistant",
content: {
type: "text" | "image",
// For text:
text?: string,
// For images:
data?: string, // base64 encoded
mimeType?: string
}
}
],
modelPreferences?: {
hints?: [{
name?: string // Suggested model name/family
}],
costPriority?: number, // 0-1, importance of minimizing cost
speedPriority?: number, // 0-1, importance of low latency
intelligencePriority?: number // 0-1, importance of capabilities
},
systemPrompt?: string,
includeContext?: "none" | "thisServer" | "allServers",
temperature?: number,
maxTokens: number,
stopSequences?: string[],
metadata?: Record<string, unknown>
}
请求参数
消息
该messages
数组包含要发送给 LLM 的对话历史记录。每条消息包含:
-
role
:“用户”或“助手” -
content
:消息内容,可以为:text
带有字段的文本内容data
带有(base64)和mimeType
字段的图像内容
模型偏好
该modelPreferences
对象允许服务器指定其模型选择偏好:
-
hints
:客户可以使用它来选择合适型号的一系列型号名称建议:name
:可以匹配完整或部分模型名称的字符串(例如“claude-3”,“sonnet”)- 客户端可以将提示映射到来自不同提供商的等效模型
- 多个提示按优先顺序进行评估
-
优先级值(0-1标准化):
costPriority
:降低成本的重要性speedPriority
:低延迟响应的重要性intelligencePriority
:高级模型能力的重要性
客户根据这些偏好和可用的模型做出最终的模型选择。
系统提示
可选systemPrompt
字段允许服务器请求特定的系统提示。客户端可以修改或忽略此字段。
上下文包含
该includeContext
参数指定要包含哪些 MCP 上下文:
"none"
:没有其他背景信息"thisServer"
:包含来自请求服务器的上下文"allServers"
:包含所有已连接 MCP 服务器的上下文
客户端控制实际包含的上下文。
采样参数
使用以下方法微调 LLM 采样:
temperature
:控制随机性(0.0 到 1.0)maxTokens
:生成的最大令牌数stopSequences
:停止生成的序列数组metadata
:其他特定于提供商的参数
响应格式
客户端返回完成结果:
{
model: string, // Name of the model used
stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string,
role: "user" | "assistant",
content: {
type: "text" | "image",
text?: string,
data?: string,
mimeType?: string
}
}
示例请求
以下是向客户请求采样的示例:
{
"method": "sampling/createMessage",
"params": {
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "What files are in the current directory?"
}
}
],
"systemPrompt": "You are a helpful file system assistant.",
"includeContext": "thisServer",
"maxTokens": 100
}
}
交通
了解 MCP 的通信机制
模型上下文协议 (MCP) 中的传输协议为客户端和服务器之间的通信提供了基础。传输协议负责处理消息发送和接收的底层机制。
消息格式
MCP 使用JSON-RPC 2.0 作为其传输格式。传输层负责将 MCP 协议消息转换为 JSON-RPC 格式进行传输,并将接收到的 JSON-RPC 消息转换回 MCP 协议消息。
使用的 JSON-RPC 消息有三种类型:
请求
{
jsonrpc: "2.0",
id: number | string,
method: string,
params?: object
}
回应
{
jsonrpc: "2.0",
id: number | string,
result?: object,
error?: {
code: number,
message: string,
data?: unknown
}
}
通知
{
jsonrpc: "2.0",
method: string,
params?: object
}
内置传输类型
MCP 包括两种标准传输实现:
标准输入/输出(stdio)
stdio 传输支持通过标准输入和输出流进行通信。这对于本地集成和命令行工具尤其有用。
在以下情况下使用 stdio:
- 构建命令行工具
- 实施本地整合
- 需要简单的流程沟通
- 使用 Shell 脚本
- TypeScript(服务器)
- TypeScript(客户端)
- Python(服务器)
- Python(客户端)
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new StdioServerTransport();
await server.connect(transport);
服务器发送事件 (SSE)
SSE 传输通过 HTTP POST 请求实现服务器到客户端的流式传输,从而实现客户端到服务器的通信。
在以下情况下使用 SSE:
- 仅需要服务器到客户端的流式传输
- 使用受限网络
- 实现简单更新
安全警告:DNS重新绑定攻击
如果没有妥善保护,SSE 传输可能容易受到 DNS 重新绑定攻击。为了防止这种情况发生:
- 始终验证传入 SSE 连接上的 Origin 标头,以确保它们来自预期的来源
- ****在本地运行时,避免将服务器绑定到所有网络接口(0.0.0.0) - 仅绑定到本地主机(127.0.0.1)
- ****为所有 SSE 连接实施适当的身份验证
如果没有这些保护措施,攻击者可以使用 DNS 重新绑定从远程网站与本地 MCP 服务器进行交互。
- TypeScript(服务器)
- TypeScript(客户端)
- Python(服务器)
- Python(客户端)
import express from "express";
const app = express();
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
let transport: SSEServerTransport | null = null;
app.get("/sse", (req, res) => {
transport = new SSEServerTransport("/messages", res);
server.connect(transport);
});
app.post("/messages", (req, res) => {
if (transport) {
transport.handlePostMessage(req, res);
}
});
app.listen(3000);
定制运输
MCP 可以轻松实现针对特定需求的自定义传输。任何传输实现只需遵循 Transport 接口即可:
您可以为以下对象实现自定义传输:
- 自定义网络协议
- 专业沟通渠道
- 与现有系统集成
- 性能优化
- TypeScript
- Python
interface Transport {
// Start processing messages
start(): Promise<void>;
// Send a JSON-RPC message
send(message: JSONRPCMessage): Promise<void>;
// Close the connection
close(): Promise<void>;
// Callbacks
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
}
错误处理
传输实现应该处理各种错误情况:
- 连接错误
- 消息解析错误
- 协议错误
- 网络超时
- 资源清理
错误处理示例:
- TypeScript
- Python
class ExampleTransport implements Transport {
async start() {
try {
// Connection logic
} catch (error) {
this.onerror?.(new Error(`Failed to connect: ${error}`));
throw error;
}
}
async send(message: JSONRPCMessage) {
try {
// Sending logic
} catch (error) {
this.onerror?.(new Error(`Failed to send message: ${error}`));
throw error;
}
}
}
最佳实践
实施或使用 MCP 传输时:
- 正确处理连接生命周期
- 实施适当的错误处理
- 连接关闭时清理资源
- 使用适当的超时
- 发送前验证消息
- 记录传输事件以进行调试
- 在适当的时候实现重新连接逻辑
- 处理消息队列中的背压
- 监控连接健康状况
- 实施适当的安全措施
安全注意事项
实施运输时:
身份验证和授权
- 实施适当的身份验证机制
- 验证客户端凭据
- 使用安全令牌处理
- 实施授权检查
数据安全
- 使用 TLS 进行网络传输
- 加密敏感数据
- 验证消息完整性
- 实施邮件大小限制
- 净化输入数据
网络安全
- 实施速率限制
- 使用适当的超时
- 处理拒绝服务情况
- 监控异常模式
- 实施适当的防火墙规则
- 对于 SSE 传输,验证 Origin 标头以防止 DNS 重新绑定攻击
- 对于本地 SSE 服务器,仅绑定到本地主机 (127.0.0.1),而不是所有接口 (0.0.0.0)
调试传输
调试传输问题的提示:
- 启用调试日志记录
- 监控消息流
- 检查连接状态
- 验证消息格式
- 测试错误场景
- 使用网络分析工具
- 实施健康检查
- 监视资源使用情况
- 测试边缘情况
- 使用适当的错误跟踪