一、mcp server 部署
使用fastmcp框架 部署 mcp server, 以下是源代碼
# 引入 fastmcp 依賴包
from fastmcp import FastMCP# 新建fastmcp實例, 名字叫做 weather
mcp = FastMCP("weather")@mcp.tool(name="weather", tags={"weather"})
def weather(city: str) -> str:"""獲取制定城市的天氣信息:param city: 城市名稱:return: 天氣信息"""print(f"正在獲取 {city} 的天氣信息...")return f"{city} 的天氣是晴天,溫度 25 度。"if __name__ == '__main__':# mcp.run(transport="stdio")mcp.run(transport="streamable-http", host="0.0.0.0", port=8000, path="/weather")
運行python文件,啟動 mcp server , 以下是啟動成功界面
二、理解mcp服務調用原理
模型上下文協議 (MCP) 為客戶端-服務器連接定義了嚴格的生命周期,以確保適當的功能協商和狀態管理。
- 初始化 :能力協商和協議版本協議
- 操作 :正常協議通信
- Shutdown:正常終止連接
初始化
初始化階段必須是客戶端和服務器之間的第一次交互。在此階段,客戶端和服務器:
- 建立協議版本兼容性
- 交換和獲取功能
- 獲取實現詳情
客戶端必須通過發送包含以下內容的 initialize 請求來啟動此階段:
- 支持的協議版本
- 客戶端功能
- 客戶端實現信息
initialize request
{"jsonrpc": "2.0","id": 1,"method": "initialize","params": {"protocolVersion": "2025-03-26","capabilities": {"roots": {"listChanged": true},"sampling": {}},"clientInfo": {"name": "ExampleClient","version": "1.0.0"}}
}
initialize 請求不可以作為 JSON-RPC 的一部分 batch,因為在初始化完成之前,其他請求和通知是不可能的。這還允許向后兼容未明確支持 JSON-RPC 批處理的先前協議版本。
服務器必須使用自己的功能和信息進行響應:
{"jsonrpc": "2.0","id": 1,"result": {"protocolVersion": "2025-03-26","capabilities": {"logging": {},"prompts": {"listChanged": true},"resources": {"subscribe": true,"listChanged": true},"tools": {"listChanged": true}},"serverInfo": {"name": "ExampleServer","version": "1.0.0"},"instructions": "Optional instructions for the client"}
}
成功初始化后,客戶端必須發送初始化通知,以指示它已準備好開始正常作:
initialize notifications
{"jsonrpc": "2.0","method": "notifications/initialized"
}
注意:
客戶端 一定不能 在 服務器 響應 initialize 請求之前發送 ping 以外的請求。
服務器在接收初始化通知之前不應發送 ping 和 logging 以外的請求。
版本協商
在 initialize 請求中,客戶端必須發送它支持的協議版本。這應該是客戶端支持的最新版本 。
如果服務器支持請求的協議版本,則它必須使用相同的版本進行響應。否則,服務器必須使用它支持的另一個協議版本進行響應。這應該是服務器支持的最新版本 。
如果客戶端不支持服務器響應中的版本,則它應該 斷開。
能力協商
客戶端和服務器功能確定在會話期間哪些可選協議功能將可用。
主要功能包括:
- roots: 提供文件系統 root 能力
- sampling: 支持 LLM采樣請求
- experimental: 描述對非標準實驗性功能的支持
- prompts: 提供提示模板
- resources: 提供可讀資源
- tools: 公開可調用工具
- logging: 發出結構化日志消息
- completions: 支持參數自動補全
- experimental: 描述對非標準實驗性功能的支持
- subscribe:支持訂閱單個項目的更改(僅限資源)
功能對象可以描述子功能,例如:
listChanged:支持列表更改通知(用于提示、資源和工具)
subscribe:支持訂閱單個項目的更改(僅限資源)
Operation
在操作階段,客戶端和服務端根據協商的能力進行消息交換。
雙方都應該 :
- 遵循協商的協議版本
- 僅使用已成功協商的功能
Shutdown
在 shutdown 階段,一端(通常是 client)干凈地終止協議連接。沒有定義特定的關閉消息,而是使用底層傳輸機制來發出連接終止信號:
stdio
對于 stdio 傳輸 ,客戶端應通過以下方式啟動關閉:
- 首先,關閉子進程(服務器)的輸入流
- 等待服務器退出,如果服務器未在合理時間內退出,則發送 SIGTERM
- 如果服務器在 SIGTERM 之后的合理時間內未退出,則發送 SIGKILL
服務器可以通過關閉其對 Client 端的輸出流并退出來啟動關閉。
HTTP 協議
對于 HTTP 傳輸 ,通過關閉關聯的 HTTP 連接來指示關閉。
Timeouts
實現應為所有發送的請求建立超時,以防止連接掛起和資源耗盡。當請求在超時期限內未收到成功或錯誤響應時,發送者應針對該請求發出取消通知并停止等待響應。
SDK 和其他中間件應允許按請求配置這些超時。
實現可以選擇在收到與請求相對應的進度通知時重置超時時鐘,因為這意味著工作實際上正在進行。但是,無論進度通知如何,實現都應始終強制執行最大超時,以限制行為異常的客戶端或服務器的影響。
Error Handling
實現應該準備好處理這些錯誤情況:
- 協議版本不匹配
- 無法協商所需的功能
- 請求超時
初始化錯誤示例:
{"jsonrpc": "2.0","id": 1,"error": {"code": -32602,"message": "Unsupported protocol version","data": {"supported": ["2024-11-05"],"requested": "1.0.0"}}
}
三、請求案例
1. 首先發送初始化請求
調用工具之前, 首先需要初始化連接:
- 新增請求頭: Accept: application/json, text/event-stream
- 構建請求體
{"jsonrpc": "2.0","method": "initialize","params": {"protocolVersion": "2025-07-17","capabilities": {},"clientInfo": {"name": "example-client","version": "1.0.0"}},"id": 0
}
- 請求測試
從相應頭中,可以拿到 mcp-session-id:
2. 響應初始化
-
新增請求頭: mcp-session-id:18251f0529ec4bef90da4d3ffb34b81b
-
構建請求體:
{"jsonrpc": "2.0","method": "notifications/initialized"
}
-檢查響應, 服務器端返回的內容為空,正確
3. 在當前session下進行基本操作測試
3.1 獲取可用工具列表
- 請求體:
{"jsonrpc": "2.0","id": 1,"method": "tools/list","params": {}
}
- 響應內容
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"weather","description":"獲取制定城市的天氣信息\n:param city: 城市名稱\n:return: 天氣信息","inputSchema":{"properties":{"city":{"title":"City","type":"string"}},"required":["city"],"type":"object"},"outputSchema":{"properties":{"result":{"title":"Result","type":"string"}},"required":["result"],"title":"_WrappedResult","type":"object","x-fastmcp-wrap-result":true}}]}}
3.2 調用工具
- 請求體:
{"jsonrpc": "2.0","id": 2,"method": "tools/call","params": {"name": "weather","arguments": {"city": "深圳"}}
}
}
- 響應內容
event: message
data: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"深圳 的天氣是晴天,溫度 25 度。"}],"structuredContent":{"result":"深圳 的天氣是晴天,溫度 25 度。"},"isError":false}}
常見錯誤
1. Not Acceptable: Client must accept both application/json and text/event-stream
報錯信息
{"jsonrpc": "2.0","id": "server-error","error": {"code": -32600,"message": "Not Acceptable: Client must accept both application/json and text/event-stream"}
}
原因
客戶端請求頭沒有支持 application/json 和 text/event-stream
解決
新增請求頭: Accept: application/json, text/event-stream
2. Bad Request: Missing session ID
報錯信息
{
“jsonrpc”: “2.0”,
“id”: “server-error”,
“error”: {
“code”: -32600,
“message”: “Bad Request: Missing session ID”
}
}
原因
客戶端請求頭沒有 session id
解決
請求頭新增字段:mcp-session-id , 這個 session id 需要 請求 初始化方法, 從相應頭中獲取
3. Invalid request parameters
報錯信息
event: message
data: {"jsonrpc":"2.0","id":1,"error":{"code":-32602,"message":"Invalid request parameters","data":""}}
原因
沒有 調用相應初始化方法
解決
請求響應初始化方法
- 構建請求體:
{"jsonrpc": "2.0","method": "notifications/initialized"
}