深度解析:Anthropic MCP 協議
正如 LSP 成爲了 IDE 的通用標準一樣,Anthropic 正在將 MCP 打造成 LLM 集成的開放標準。
前段時間 OpenAI 發佈了一個實時訪問第三方應用的功能來爲 ChatGPT 提供上下文(ChatGPT 升級爲實時協作助手),沒想到 Claude 這麼快就帶來了一個 LLM 協議標準,直接將 AI 能力拉滿(現在下結論爲時尚早)。不過當我看完整個協議以及簡單上手體驗後,我想說:“真牛逼,它以一種非入侵方式最大限度獲取到系統權限來拓展 AI 的能力邊界”!
模型上下文協議(MCP)是 Anthropic 推出的開放標準,旨在通過統一的客戶端-服務器
架構解決 LLM 應用與數據源連接的難題。它支持通過同一協議訪問本地資源(如數據庫、文件)和遠程資源(如 Slack、GitHub API),無需定製集成。MCP 不僅共享數據,還可公開工具和交互模板,且內置安全性,確保資源由服務器完全掌控。目前 MCP 支持本地運行,未來將引入企業級認證的遠程支持,實現團隊間的安全共享。通過 Claude 桌面應用,開發者可在短時間內集成 MCP,快速連接多種數據源,推動 AI 集成的標準化發展。
MCP 簡介
近日,Model Context Protocol[1](MCP,模型上下文協議)正式開源。作爲一項連接 AI 助手與數據系統的新標準,MCP 的誕生旨在解決當前 AI 模型因數據孤島限制而無法充分發揮潛力的難題。這項由 Claude 推動的技術創新爲開發者提供了一個開放的、統一的解決方案,使 AI 系統能夠與多種內容存儲庫、業務工具和開發環境高效對接,顯著提升模型的響應質量與相關性。
背景
解決碎片化問題,爲 AI 打開數據大門。
當前,AI 助手已成爲主流工具,模型能力的進步使推理和質量得以迅速提升。然而,數據訪問的瓶頸依然存在。每個數據源需要獨立的定製集成,這種碎片化的方式不僅效率低下,還限制了 AI 的可擴展性。
MCP 的出現就是爲了改變現狀。它作爲一個通用的開放協議,爲數據源與 AI 系統之間的連接提供了統一標準,替代複雜的多源整合方式。這種設計極大簡化了數據接入過程,降低開發者的工作量,同時讓 AI 系統能夠更加全面和準確地訪問數據,推動系統從孤立走向協同。
MCP 核心
MCP 的架構清晰且開放,開發者可以通過 MCP 服務器對外提供數據,或構建 MCP 客戶端,將 AI 應用與這些服務器連接。爲推動開發者快速上手,MCP 開源了以下三大核心工具:
-
MCP 規範及 SDK:幫助開發者輕鬆理解和實現協議功能。
-
MCP 官網:
https://modelcontextprotocol.io
-
MCP GitHub:
https://github.com/modelcontextprotocol
-
本機 MCP 服務支持:通過 Claude 桌面應用快速實現本地化數據連接,應用安裝鏈接
https://claude.ai/download
。 -
開源服務代碼庫:包含 Google Drive、Slack、GitHub 等流行系統的預構建實現,便於直接部署和測試。訪問鏈接
https://github.com/modelcontextprotocol/servers
。
此外,Claude 3.5 Sonnet 模型還支持快速開發 MCP 服務器,使個人和企業能夠以最低的門檻實現與重要數據集的對接。
行業動態
目前,MCP 已被 Block 和 Apollo 等企業率先應用,並逐步融入 Zed[2](Zed MCP 源碼實現 context_server/protocol.rs[3])、Replit[4]、Codeium[5] 和 Sourcegraph[6] 等開發工具平臺。這些公司通過 MCP 增強 AI 對上下文的理解能力,使 AI 能夠在編碼任務中高效檢索相關信息,生成更準確、更具功能性的代碼。
Block 的首席技術官 Dhanji R. Prasanna 表示:“在 Block,開源不僅僅是一種開發模式,它是我們工作的基石,更是一種承諾——致力於創造能夠推動深遠變革、造福公衆的技術。像 Model Context Protocol 這樣的開源技術,是將 AI 與現實應用連接起來的橋樑,確保創新以開放、透明和協作爲核心。我們非常高興能參與這一協議的開發,並藉助它構建自主化系統,讓人們擺脫機械性任務的束縛,專注於更具創造性的工作。”
通過 MCP,開發者不再需要爲每個數據源維護獨立的連接器,而是可以基於標準協議構建一套通用的解決方案。隨着生態系統的不斷完善,AI 系統將能夠在不同工具和數據集之間保持上下文一致性,爲企業和開發者帶來更具前景的技術架構。
未來展望
Claude 團隊表示,他們致力於將 MCP 打造成一個協作性的開源生態系統,鼓勵開發者、企業以及早期技術探索者共同參與,推動具有上下文感知能力的 AI 工具走向更廣闊的未來。
開發者目前可以通過 Claude 桌面應用快速部署 MCP 服務,也可以根據官方提供的快速入門指南構建自己的 MCP 解決方案。同時,開源社區已開放了連接器和實現的代碼庫,支持開發者貢獻自己的擴展功能。
隨着 MCP 的普及,AI 系統將更好地突破數據隔離的限制,真正實現與現實環境的無縫對接。對於技術領域而言,這無疑是一次重要的里程碑,也爲 AI 生態的可持續發展帶來了全新可能。
lencx 演示
我自己根據文檔幾分鐘就跑通了本地數據庫連接,在開始前需要做一些額外準備:
-
打開桌面應用的開發者模式,方便進行日誌調試(菜單
Help → Enable Developer Mode -> 點擊彈窗 Enable 按鈕
)。 -
啓用開發者模式後,會在菜單中多一個
Developer
菜單項,點擊Open MCP Log File
可以打開日誌文件,查看到操作日誌,方便排查問題。
📌 前置條件
macOS 或 Windows 系統
已安裝最新版本的 Claude 桌面應用(當前爲 0.7.1 版本)
uv[7] 0.4.18 或更高版本(可通過
uv --version
檢查)Git(
git --version
檢查)SQLite(
sqlite3 --version
檢查)如果系統環境不存在 uv、Git、SQLite,可通過以下方式在命令行中進行安裝:
macOS 安裝
# Using Homebrew brew install uv git sqlite3 # Or download directly: # uv: https://docs.astral.sh/uv/ # Git: https://git-scm.com # SQLite: https://www.sqlite.org/download.html
Windows 安裝
# Using winget winget install --id=astral-sh.uv -e winget install git.git sqlite.sqlite # Or download directly: # uv: https://docs.astral.sh/uv/ # Git: https://git-scm.com # SQLite: https://www.sqlite.org/download.html
操作步驟
-
設置本地 SQLite 數據庫
-
通過 MCP 將 Claude 桌面應用連接到該數據庫
-
安全地查詢和分析數據
Step 1:創建測試數據庫
macOS 請執行以下命令(路徑:/Users/YOUR_USERNAME/test.db
):
sqlite3 ~/test.db <<EOF
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
price REAL
);
INSERT INTO products (name, price) VALUES
('Widget', 19.99),
('Gadget', 29.99),
('Gizmo', 39.99),
('Smart Watch', 199.99),
('Wireless Earbuds', 89.99),
('Portable Charger', 24.99),
('Bluetooth Speaker', 79.99),
('Phone Stand', 15.99),
('Laptop Sleeve', 34.99),
('Mini Drone', 299.99),
('LED Desk Lamp', 45.99),
('Keyboard', 129.99),
('Mouse Pad', 12.99),
('USB Hub', 49.99),
('Webcam', 69.99),
('Screen Protector', 9.99),
('Travel Adapter', 27.99),
('Gaming Headset', 159.99),
('Fitness Tracker', 119.99),
('Portable SSD', 179.99);
EOF
Windows 用戶執行以下命令(路徑:C:\\Users\\YOUR_USERNAME\\test.db
):
$sql = @'
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
price REAL
);
INSERT INTO products (name, price) VALUES
('Widget', 19.99),
('Gadget', 29.99),
('Gizmo', 39.99),
('Smart Watch', 199.99),
('Wireless Earbuds', 89.99),
('Portable Charger', 24.99),
('Bluetooth Speaker', 79.99),
('Phone Stand', 15.99),
('Laptop Sleeve', 34.99),
('Mini Drone', 299.99),
('LED Desk Lamp', 45.99),
('Keyboard', 129.99),
('Mouse Pad', 12.99),
('USB Hub', 49.99),
('Webcam', 69.99),
('Screen Protector', 9.99),
('Travel Adapter', 27.99),
('Gaming Headset', 159.99),
('Fitness Tracker', 119.99),
('Portable SSD', 179.99);
'@
cd ~
& sqlite3 test.db $sql
Step 2:配置 Claude 應用
配置文件路徑:
-
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
-
Windows:
%APPDATA%\Claude\claude_desktop_config.json
文件可通過命令打開,也可以通過 Claude 設置界面打開(點擊 編輯配置(Edit Config)
按鈕)。
用自己喜歡的編輯器將以下內容複製到 claude_desktop_config.json
中。注意將 /Users/lencx/test.db
路徑改爲自己的本機文件路徑。
{
"mcpServers": {
"sqlite": {
"command": "uvx",
"args": [
"mcp-server-sqlite",
"--db-path",
"/Users/lencx/test.db"
]
}
}
}
這裏告訴 Claude 桌面應用:
-
有一個名爲 “sqlite” 的 MCP 服務器
-
通過運行
uvx mcp-server-sqlite
命令來啓動它 -
將其連接到你的測試數據庫(即本地創建的 test.db 文件)
-
保存文件後,重新啓動 Claude 桌面應用
Step 3:測試一下
將以下 Prompt 發送給 Claude,來驗證一切是否正常:
Can you connect to my SQLite database and tell me what products are available, and their prices?
如果一切正常,Claude 將連接到 SQLite MCP 服務器,然後查詢本地數據庫,使用格式化方式呈現出結果。
你還可以測試這些 Prompt:
-
基本查詢:
What's the average price of all products in the database?
-
數據分析:
Can you analyze the price distribution and suggest any pricing optimizations?
-
複雜操作:
Could you help me design and create a new table for storing customer orders?
運行原理
當你通過 MCP 與 Claude 桌面應用交互時,會經過以下步驟:
-
服務器發現:Claude 桌面應用在啓動時會連接到你配置的 MCP 服務器。
-
協議握手:當你詢問數據時,Claude 桌面應用會:
-
確定哪個 MCP 服務器可以提供幫助(例如,本例中的 SQLite 服務器)。
-
通過協議協商服務器的功能和權限。
-
向 MCP 服務器請求數據或執行操作。
- 交互流程:
-
Claude 桌面應用通過 MCP 服務器與本地資源交互。
-
所有操作均嚴格限制在服務器允許的範圍內。
在安全性方面:
-
受控能力:MCP 服務器僅暴露特定且受控的功能。
-
本地運行:MCP 服務器運行在本地計算機上,訪問的資源不會暴露在互聯網中。
-
用戶確認:對於敏感操作,Claude 桌面應用需要用戶確認後才能執行。
這一設計確保了在使用 Claude 分析或交互本地數據時,用戶始終保持對數據訪問和操作的完全控制權,同時最大限度保障數據安全性。
常見問題
如果 Claude 桌面應用中沒有顯示內容,可以通過以下步驟排查問題:首先,檢查是否啓用了 MCP,點擊聊天框旁的 🔌 圖標,展開 “已安裝的 MCP 服務器”(Installed MCP Servers)確認配置的服務器是否顯示。然後導航到 Claude > Settings… 打開 “開發者(Developer)” 標籤頁驗證配置。最後完全退出並重啓 Claude 桌面應用以確保更改生效。
如果遇到 MCP 或數據庫錯誤,可以檢查 Claude 桌面應用的日誌,運行命令 tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
查看最近的日誌信息。也可以測試數據庫連接,例如運行 sqlite3 ~/test.db ".tables"
確認數據庫是否正常工作。常見的修復方法包括檢查配置文件中的文件路徑、驗證數據庫文件的權限,以及確保 SQLite 已正確安裝。通過這些步驟,可以有效解決大部分問題。
MCP 協議詳解
官方文檔內容很長,爲了方便大家對 MCP 有一個全面瞭解,我對文檔做了簡單梳理。需要注意:目前文檔主要適配 macOS,其他系統指南將在晚些時候給出。
快速開始
目前 MCP 有三種方式可以幫助你快速開始,Python 或 TypeScript 選一個自己比較熟悉的構建服務即可。
-
快速入門(MCP Quickstart[8]):不到 5 分鐘即可開始使用 MCP,可在 Claude 桌面應用和本地服務之間建立安全連接(以上的 “lencx 演示” 就是基於該部分文檔實現)。
-
構建第一個 Python 服務 (MCP Python[9]):15 分鐘內用 Python 創建一個簡單的 MCP 服務器。
-
構建第一個 TypeScript 服務(MCP TypeScript[10]):15 分鐘內用 TypeScript 創建一個簡單的 MCP 服務器。
開發工具
開發 MCP 服務器或將其與應用程序集成時,有效的調試至關重要。所以 MCP 提供了幾種不同層次的調試工具:
-
MCP 檢查器(MCP Inspector[11])
-
交互式調試界面
-
直接服務器測試
-
Claude 桌面開發工具(Claude Desktop Developer Tools)
-
集成測試
-
日誌收集
-
Chrome DevTools 集成
-
服務器日誌(Server Logging)
-
自定義日誌記錄實現
-
錯誤追蹤
-
性能監控
概念:核心架構(Core architecture)
MCP 遵循客戶端 - 服務器架構(client-server),其中:
-
MCP 主機(MCP Hosts):希望通過 MCP 訪問資源的程序(例如 Claude Desktop、IDE 或 AI 工具),用於發起連接。
-
MCP 客戶端(MCP Clients):與服務器保持 1:1 連接的協議客戶端。
-
MCP 服務器(MCP Servers):輕量級程序,每個程序都通過標準化模型上下文協議公開特定功能。爲客戶端提供上下文、工具和 prompt 信息。
-
本地資源(Local Resources):你的計算機資源中可供 MCP 服務器安全訪問的資源(數據庫、文件、服務)。
-
遠程資源(Remote Resources):MCP 服務器可以連接到的互聯網資源(例如通過 API)。
核心組件
協議層(Protocol layer)
協議層負責消息的封裝、請求 / 響應的關聯,以及高層通信模式的管理。 主要類包括: Protocol 、Client 、 Server 等。以 Protocol 類爲例(TypeScript 版):
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>
}
傳輸層(Transport layer)
傳輸層負責客戶端和服務器之間的實際通信。MCP 支持多種傳輸機制:
-
Stdio 傳輸
-
使用標準輸入 / 輸出進行通信
-
適合本地進程間通信
-
基於 HTTP 和 SSE 的傳輸
-
使用 Server-Sent Events(SSE) 進行服務器到客戶端的消息傳遞
-
使用 HTTP POST 進行客戶端到服務器的消息傳遞
所有傳輸機制都採用 JSON-RPC 2.0 協議進行消息交換。詳細的 MCP 消息格式規範可參考相關文檔。
消息類型(Message types)
MCP 定義了以下主要消息類型:
-
請求(Request):需要另一方提供響應
interface Request { method: string; params?: { ... }; }
-
通知(Notification):單向消息,不需要響應
interface Notification { method: string; params?: { ... }; }
-
結果(Result):成功響應請求的消息
interface Result { [key: string]: unknown; }
-
錯誤(Error):表示請求失敗的消息
interface Error { code: number; message: string; data?: unknown; }
Connection 生命週期
初始化(Initialization)
-
客戶端發送
initialize
請求,包含協議版本和能力信息 -
服務器響應其協議版本和能力信息
-
客戶端發送
initialized
通知以確認 -
正常消息交換開始
消息交換(Message exchange)
初始化後,支持以下通信模式:
-
請求 - 響應模式(Request-Response):客戶端或服務器發送請求,另一方響應
-
通知模式(Notifications):任一方發送單向消息
終止連接(Termination)
任一方可以終止連接:
-
通過
close()
進行正常關閉 -
通過傳輸層斷開連接
-
因錯誤條件導致中斷
錯誤處理(Error handling)
錯誤通過以下方式傳播:
-
請求的錯誤響應
-
傳輸中的錯誤事件
-
協議級錯誤處理程序
enum ErrorCode {
// Standard JSON-RPC error codes
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603
}
SDK 和應用程序可以自定義 -32000
以上的錯誤碼。
代碼示例
以下是實現 MCP 服務器的基本代碼示例:
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);
概念:資源(Resources)
資源是模型上下文協議(MCP)的核心組件之一,允許服務器將數據和內容暴露給客戶端,以便用作 LLM 交互的上下文信息。MCP 資源設計爲由應用程序控制,這意味着客戶端應用程序可以決定資源的使用方式和時機。例如:
-
某些應用可能需要用戶顯式選擇資源。
-
另一些應用可能基於啓發式算法或 AI 模型自身的判斷自動選擇資源。
所以資源代表 MCP 服務器希望向客戶端提供的任何類型的數據,包括:
-
文件內容(File contents)
-
數據庫記錄(Database records)
-
API 響應(API responses)
-
實時系統數據(Live system data)
-
屏幕截圖和圖像(Screenshots and images)
-
日誌文件(Log files)
-
...
每個資源通過唯一的 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 編碼的原始二進制數據,適用於:圖像、PDF 文件、音頻文件、視頻文件、其他非文本格式等。
資源發現
客戶端主要通過兩種方式發現可用資源:
-
直接資源(Direct resources):服務器通過端點公開具體資源的列表
resources/list
。{ uri: string; // Unique identifier for the resource name: string; // Human-readable name description?: string; // Optional description mimeType?: string; // Optional MIME type }
-
資源模板(Resource templates):對於動態資源,服務器可以公開 URI 模板 [12],客戶端可以使用它來構建有效的資源 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 }
-
閱讀資源(Reading 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) } ] }
資源更新
MCP 通過兩種機制支持資源的實時更新:
-
列出更改(List changes):當可用資源列表發生變化時,服務器可以通過
notifications/resources/list_changed
通知客戶端 -
內容變更(Content changes):用戶可以訂閱特定資源的更新
-
客戶端發送
resources/subscribe
資源 URI -
notifications/resources/updated
資源發生變化時服務器發送 -
客戶端可以使用
resources/read
-
客戶端可以取消訂閱
resources/unsubscribe
📌 最佳實踐
使用清晰且具有描述性的資源名稱和 URI,提供有助於 LLM 理解的資源描述,併爲已知資源設置合適的 MIME 類型。動態內容可以通過資源模板實現,而對於頻繁變化的資源,建議使用訂閱機制。此外,應優雅地處理錯誤,提供明確的錯誤信息,對於大規模資源列表可以使用分頁,並在適當情況下對資源內容進行緩存。URI 在處理前需要驗證,同時記錄任何自定義的 URI 方案以便後續參考。
在暴露資源時,安全性至關重要。必須驗證所有資源 URI,實施適當的訪問控制,並清理文件路徑以防止目錄遍歷攻擊。對二進制數據的處理需特別謹慎,可以考慮爲資源讀取操作設置速率限制並對資源訪問進行審計。傳輸中的敏感數據應加密,MIME 類型需要驗證,同時爲長時間運行的讀取操作設置超時機制。最後,資源的清理操作也應妥善處理,確保系統穩定性和安全性。
代碼實現
以下是在 MCP 服務器中實現資源支持的簡單示例:
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");
});
概念:Prompts
Prompts 允許服務器定義可重用的 prompt 模板和工作流,方便客戶端呈現給用戶和 LLM。這是一種強大的方法,可以標準化並共享常見的 LLM 交互。Prompts 設計爲由用戶控制,這意味着它們從服務器暴露給客戶端,供用戶顯式選擇使用。
MCP 中的 Prompts 是預定義的模板,具備以下功能:
-
接受動態參數
-
包含來自資源的上下文
-
鏈接多個交互
-
引導特定工作流
-
以用戶界面(UI)元素形式呈現(如斜槓命令)
Prompt 結構定義
{
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
客戶端可以通過 prompts/list
端點發現可用的 prompt:
// Request(請求)
{
method: "prompts/list"
}
// Response(響應)
{
prompts: [
{
name: "analyze-code",
description: "Analyze code for potential improvements",
arguments: [
{
name: "language",
description: "Programming language",
required: true
}
]
}
]
}
使用 Prompts
要使用 prompts,客戶端需要發出 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```"
}
}
]
}
動態 Prompts
Prompts 可以是動態的,主要有兩種:
-
嵌入資源上下文(Embedded resource context)
{ "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 } ] }
-
多步驟工作流程(Multi-step workflows)
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." } } ]; } };
📌 最佳實踐
在實現 prompts 功能時,應使用清晰且具有描述性的 prompt 名稱,爲 prompt 及其參數提供詳細說明,並驗證所有必需參數的完整性。同時,應優雅地處理缺失參數的情況,並考慮爲 prompt 模板實現版本控制。在適當情況下,可以緩存動態內容,記錄參數的預期格式,並考慮 prompt 的可組合性。此外,需實現錯誤處理機制,並使用多種輸入場景對 prompt 進行充分測試。
prompt 可通過多種方式集成到客戶端用戶界面,包括斜槓命令、快捷操作、上下文菜單項、命令面板入口、引導式工作流和交互式表單。對於 prompt 的更新和變更,服務器可以通過
prompts.listChanged
能力通知客戶端,通過notifications/prompts/list_changed
類型發送通知,客戶端則需重新獲取 prompt 列表。在安全性方面,需驗證所有參數的合法性並清理用戶輸入以防止惡意內容,同時考慮對 prompt 調用進行速率限制,實施訪問控制並審計 prompt 使用情況。對於敏感數據,應適當加密和保護,驗證生成內容的安全性,併爲 prompt 處理設置超時機制。此外,需注意 prompt 注入攻擊的風險,並記錄和公開安全需求文檔以保障 prompt 的可靠性和安全性。
代碼示例
以下是在 MCP 服務器中實現 prompts 的完整示例:
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");
});
概念:工具(Tools)
工具是模型上下文協議(MCP)中的一項強大功能,允許服務器向客戶端暴露可執行的功能。通過工具,LLM 可以與外部系統交互、執行計算並在現實世界中採取行動。
工具設計爲由模型控制,這意味着工具從服務器暴露給客戶端,供 AI 模型自動調用(通常需要人類介入進行授權)。MCP 中的工具允許服務器暴露可被客戶端調用的可執行功能,這些功能可供 LLM 用於執行動作。工具的關鍵特性包括:
-
發現(Discovery):客戶端可以通過
tools/list
接口列出可用工具。 -
調用(Invocation):工具通過
tools/call
接口被調用,服務器執行請求的操作並返回結果。 -
靈活性(Flexibility):工具的功能範圍可以從簡單的計算擴展到複雜的 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
}
}
工具模式
以下是服務器可以提供的一些工具類型的示例。
系統操作(System operations)
:與本地系統交互的工具
{
name: "execute_command",
description: "Run a shell command",
inputSchema: {
type: "object",
properties: {
command: { type: "string" },
args: { type: "array", items: { type: "string" } }
}
}
}
API 集成(API integrations)
:包裝外部 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" } }
}
}
}
數據處理(Data processing)
:轉換或分析數據的工具
{
name: "analyze_csv",
description: "Analyze a CSV file",
inputSchema: {
type: "object",
properties: {
filepath: { type: "string" },
operations: {
type: "array",
items: {
enum: ["sum", "average", "count"]
}
}
}
}
}
代碼示例
以下是在 MCP 服務器中實現基本工具的示例:
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 {
toolResult: a + b
};
}
throw new Error("Tool not found");
});
概念:採樣(Sampling)
採樣是 MCP 的一項強大功能,允許服務器通過客戶端請求 LLM 完成,從而實現複雜的代理行爲,同時保持安全性和隱私性。目前 Claude 桌面客戶端尚未支持此功能。
採樣流程包括以下步驟:
-
服務器向客戶端發送
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)
messages
數組包含需要發送給 LLM 的對話歷史。每條消息包括:
-
role:消息角色,值可以是
"user"
(用戶)或"assistant"
(助手) -
content:消息內容,可以是:
-
文本內容:包含
text
字段 -
圖像內容:包含
data
(Base64 編碼)和mimeType
字段
模型偏好(Model preferences)
modelPreferences
對象允許服務器指定模型選擇偏好:
-
hints
:模型名稱建議的數組,客戶端可以使用這些建議選擇合適的模型: -
name:字符串,可匹配完整或部分模型名稱(如
"claude-3"
或"sonnet"
) -
客戶端可能會將提示映射到不同提供商的等效模型
-
多個提示按照優先順序進行評估
-
優先級(0-1 範圍內歸一化):
-
costPriority
:最小化成本的優先級權重 -
speedPriority
:低延遲響應的優先級權重 -
intelligencePriority
:高模型能力的優先級權重
客戶端根據這些偏好和可用模型最終決定模型選擇。
系統提示(System prompt)
systemPrompt
是一個可選字段,允許服務器請求特定的系統提示。客戶端可以修改或忽略此字段。
上下文包含(Context inclusion)
includeContext
參數指定 MCP 上下文的包含範圍:
-
none
:不包含額外上下文 -
thisServer
:僅包含來自請求服務器的上下文 -
allServers
:包含所有連接的 MCP 服務器的上下文
客戶端最終決定實際包含的上下文內容。
採樣參數(Sampling parameters)
可以使用以下參數微調 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
}
}
📌 最佳實踐
在實現採樣功能時,應提供清晰且結構良好的提示,恰當地處理文本和圖像內容,並設置合理的標記數限制(token limits)。通過
includeContext
參數包含相關上下文,並在使用響應前進行驗證,同時優雅地處理錯誤。此外,應考慮對採樣請求實施速率限制,記錄預期的採樣行爲,使用多種模型參數進行測試,並監控採樣成本。採樣功能設計考慮了人類監督。對於提示,客戶端應向用戶展示擬定的提示內容,用戶可以修改或拒絕提示,系統提示則可以被過濾或修改,上下文包含由客戶端控制。對於生成結果,客戶端應向用戶展示結果,用戶可以修改或拒絕生成結果,客戶端也可以過濾或修改結果,並由用戶決定使用的模型。
在安全性方面,需要驗證消息內容的合法性,清理敏感信息,並實施速率限制和數據傳輸加密。同時,妥善處理用戶數據隱私,審計採樣請求,控制成本暴露風險,設置超時機制,並優雅地處理模型錯誤。
採樣支持多種代理式工作流模式,例如讀取和分析資源、基於上下文決策、生成結構化數據、處理多步驟任務以及提供交互式協助。上下文管理應請求最小必要的上下文,清晰組織其結構,處理大小限制,根據需要更新上下文並清理過期內容。可靠的錯誤處理需要捕獲採樣失敗、處理超時錯誤、管理速率限制、驗證響應內容、提供備用行爲並記錄錯誤日誌。
需要注意的是,採樣功能存在一些限制,例如依賴客戶端能力、用戶控制行爲、上下文大小限制、速率限制和成本控制。此外,模型的可用性和響應時間可能會有所不同,並非所有內容類型都被支持。
概念:傳輸(Transports)
傳輸是模型上下文協議(MCP)的核心組件之一,爲客戶端和服務器之間的通信提供基礎。傳輸機制負責處理消息的發送和接收的底層邏輯。
MCP 使用 JSON-RPC 2.0 作爲傳輸格式。傳輸層負責將 MCP 協議消息轉換爲 JSON-RPC 格式進行傳輸,並將接收到的 JSON-RPC 消息還原爲 MCP 協議消息。
JSON-RPC 使用三種類型的消息:
-
請求消息(Requests)
{ jsonrpc: "2.0", id: number | string, method: string, params?: object }
-
響應消息(Responses)
{ jsonrpc: "2.0", id: number | string, result?: object, error?: { code: number, message: string, data?: unknown } }
-
通知消息(Notifications)
{ jsonrpc: "2.0", method: string, params?: object }
內置傳輸類型
MCP 包括以下兩種標準傳輸實現:
標準輸入 / 輸出(Input/Output,stdio)
stdio
傳輸通過標準輸入和輸出流實現通信,特別適合本地集成和命令行工具。 適用場景:
-
構建命令行工具
-
實現本地集成
-
需要簡單的進程間通信
-
與 Shell 腳本協作
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new StdioServerTransport();
await server.connect(transport);
服務器發送事件(SSE:Server-Sent Events)
SSE
傳輸通過 HTTP POST 實現客戶端到服務器的通信,同時支持服務器到客戶端的流式傳輸。 適用場景:
-
僅需要服務器到客戶端的流式傳輸
-
在受限網絡環境中工作
-
實現簡單的更新機制
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new SSEServerTransport("/message", response);
await server.connect(transport);
自定義傳輸(Custom Transports)
MCP 支持輕鬆實現自定義傳輸,以滿足特定需求。任何傳輸實現只需符合 Transport
接口即可。 你可以爲以下場景實現自定義傳輸:
-
自定義網絡協議
-
專用通信通道
-
與現有系統集成
-
性能優化
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;
}
錯誤處理(Error Handling)
傳輸實現需要處理各種錯誤場景,包括:
-
連接錯誤(Connection errors)
-
消息解析錯誤(Message parsing errors)
-
協議錯誤(Protocol errors)
-
網絡超時(Network timeouts)
-
資源清理(Resource cleanup)
通過設計健壯的錯誤處理機制,可以確保傳輸的穩定性和可靠性。 參考示例:
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 加密網絡傳輸,保護敏感數據,驗證消息完整性,限制消息大小,並清理輸入數據以防止惡意內容。在網絡安全層面,需實施速率限制、設置合適的超時時間、處理拒絕服務(DoS)攻擊場景、監控異常通信模式,並制定合適的防火牆規則。
爲有效調試傳輸問題,可啓用調試日誌記錄、監控消息流量、檢查連接狀態並驗證消息格式,同時測試各種錯誤場景。使用網絡分析工具和錯誤跟蹤工具有助於發現問題。此外,可以通過健康檢查和資源使用監控,驗證系統在邊緣情況和高負載條件下的穩定性,從而確保傳輸機制的健壯性和安全性。
LSP 簡介
因 LSP 一定程度上影響了 MCP 的設計理念,所以感覺有必要介紹一下 LSP(非編程人士大概率都沒聽說過)。
概述
語言服務器協議(LSP[13]:Language Server Protocol)是一種開放的、基於 JSON-RPC 的通信協議,用於在編輯器或集成開發環境(IDE)與語言服務器之間進行交互。它提供了編程語言的核心功能,如自動補全、跳轉到定義、查找所有引用、懸停文檔提示等。這一協議通過標準化通信方式,使語言服務器和開發工具之間的協作更加高效。
背景 & 目標
爲特定編程語言提供功能(如自動補全、跳轉到定義、查找引用)需要耗費大量資源,尤其是傳統方式需要針對每種開發工具分別開發插件。這導致重複勞動並增加了開發成本。LSP 的目標是通過標準化協議,解決這一複雜性問題。具體來說:
-
減少重複工作:語言社區只需開發一個高性能的語言服務器,而工具社區可以構建一個支持 LSP 的通用擴展模塊。
-
實現互操作性:一個語言服務器可以被多個支持 LSP 的工具使用,而工具也可以支持多種語言。
-
降低開發成本:開發者可以專注於語言或工具本身,而無需爲每個工具或語言重複適配工作。
語言服務器 & 客戶端
-
語言服務器(Language Server):提供編程語言的語義分析能力,例如代碼補全、跳轉到定義等。
-
客戶端(Client,編輯器或 IDE):與語言服務器通信,展示語言功能併爲開發者提供界面交互。
通過 LSP,客戶端和語言服務器之間的交互基於 JSON-RPC 格式的消息。
核心功能
-
自動補全(Auto Complete):提供基於上下文的代碼建議。
-
跳轉到定義(Go to Definition):快速跳轉到變量、函數或類的定義位置。
-
查找所有引用(Find All References):搜索代碼中變量或函數的所有使用位置。
-
懸停提示(Hover Documentation):在光標懸停時顯示相關的文檔或註釋。
-
代碼重構(Code Refactoring):支持重命名、提取函數等代碼優化操作。
協議基礎:JSON-RPC
LSP 的基礎是 JSON-RPC 協議,這種協議定義了請求和響應的結構。在一次典型交互中,客戶端會發送請求給語言服務器,例如請求代碼補全建議,而語言服務器則根據請求返回執行結果或錯誤信息。這種基於輕量級 JSON 數據格式的通信方式,不僅使協議實現簡單高效,還能適配多種開發環境。
-
無狀態:每個請求都是獨立的,不依賴於先前的交互。
-
輕量級:協議簡單,使用 JSON 格式,易於解析和實現。
-
傳輸靈活:可以通過 HTTP、WebSocket 或其他傳輸協議實現。
-
雙向通信:支持服務器向客戶端發送通知(沒有響應的請求)。
請求 & 響應
-
請求格式:
-
jsonrpc
:協議版本號(目前固定爲2.0
)。 -
method
:要調用的方法名稱。 -
params
:調用方法所需的參數(可以是數組或對象)。 -
id
:唯一標識請求的 ID,用於匹配響應。 -
響應格式:
-
jsonrpc
:協議版本號。 -
result
:請求成功時返回的結果。 -
error
:請求失敗時返回的錯誤對象,包含錯誤碼和錯誤信息。 -
id
:對應請求的 ID,用於區分多個響應。
代碼示例
以下是一個使用 JSON-RPC 進行交互的完整示例:
-
客戶端發送請求
{ "jsonrpc": "2.0", "method": "add", "params": [5, 3], "id": 1 }
-
服務器成功響應
{ "jsonrpc": "2.0", "result": 8, "id": 1 }
-
服務器錯誤響應:如果請求的方法不存在或參數錯誤,返回以下結構
{ "jsonrpc": "2.0", "error": { "code": -32601, "message": "Method not found" }, "id": 1 }
LSIF
LSIF(語言服務器索引格式)是 LSP 的補充協議(發音類似 “else if”),用於以圖結構存儲編程工件信息。它的目標是支持在開發工具或 Web 界面中進行離線代碼導航,無需本地源代碼(瞭解更多區別 LSP vs LSIF[14])。
LSP 的優勢
-
統一的語言支持:一個語言服務器可以被多種編輯器複用。
-
高效的開發協作:語言社區專注於語言服務器開發,工具社區專注於客戶端擴展開發。
-
擴展性強:易於支持新語言和新工具,降低成本。
例如 CSS LSP 服務器支持 Atom 和 Eclipse 中的 CSS 自動補全。Python、Java 等語言都實現了各自的語言服務器,且已被廣泛應用於主流開發工具中。
當前規範與實現
-
最新 LSP 規範爲 3.17 版本。
-
LSIF 的規範正在逐步完善。
-
已有許多編程語言(如 Python、Java、JavaScript 等)實現了 LSP,並被集成到多個編輯器(如 VSCode、Sublime Text、Eclipse 等)。
微軟在覈心 LSP 倉庫中維護了一份語言服務器實現列表,同時社區站點(如 langserver.org[15])提供了關於各語言服務器和客戶端功能的更多信息。
總結
語言服務器協議(LSP)通過標準化語言服務器與開發工具的通信方式,極大地提升了開發效率和工具生態的擴展性。它是語言社區和工具社區之間的橋樑,使開發者能夠以更低成本享受高級編程功能。LSP 的出現標誌着現代開發工具在互操作性和用戶體驗上的一次重要飛躍。而 MCP 的出現,就是要做 LLM 界的 LSP 標準(野心挺大的)。
References
[1]
Model Context Protocol: https://www.anthropic.com/news/model-context-protocol
[2]
Zed: https://zed.dev/blog/mcp
[3]
context_server/protocol.rs: https://github.com/zed-industries/zed/blob/3901d4610115989d1b7e4d5c637a297da8219809/crates/context_server/src/protocol.rs
[4]
Replit: https://replit.com/ai
[5]
Codeium: https://codeium.com
[6]
Sourcegraph: https://sourcegraph.com/blog/cody-supports-anthropic-model-context-protocol
[7]
uv: https://docs.astral.sh/uv/
[8]
MCP Quickstart: https://modelcontextprotocol.io/quickstart
[9]
MCP Python: https://modelcontextprotocol.io/docs/first-server/python
[10]
MCP TypeScript: https://modelcontextprotocol.io/docs/first-server/typescript
[11]
MCP Inspector: https://modelcontextprotocol.io/docs/tools/inspector
[12]
URI 模板: https://datatracker.ietf.org/doc/html/rfc6570
[13]
LSP: https://microsoft.github.io/language-server-protocol
[14]
LSP vs LSIF: https://microsoft.github.io/language-server-protocol/overviews/lsif/overview
[15]
langserver.org: https://langserver.org
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ASmcjW53HKokdYt1m-xyXA