MCP基礎知識二(實戰通信方式之Streamable HTTP)

介紹

MCP 使用 JSON-RPC 2.0 作為其傳輸格式。傳輸層負責將 MCP 協議消息轉換為 JSON-RPC 格式進行傳輸,并將接收到的 JSON-RPC 消息轉換回 MCP 協議消息。其中SSE被廢棄了(Server-Sent Events (SSE) - Deprecated)

SSE?as?a?standalone?transport?is?deprecated?as?of?protocol?version?2024-11-05.?It?has?been?replaced?by?Streamable?HTTP,?which?incorporates?SSE?as?an?optional?streaming?mechanism.?For?backwards?compatibility?information,?see?the?backwards?compatibility?section?below.

自協議版本 2024-11-05 起,SSE 作為獨立傳輸已被棄用。它已被流式 HTTP 取代,后者將 SSE 作為可選的流式機制。有關向后兼容性信息,請參閱下方的向后兼容性部分。

MCP官網:Transports - Model Context Protocol

實戰

1.編寫一個py代碼

from __future__ import annotations
import argparse
import asyncio
import json
from typing import Any, AsyncIterator
import httpx
from fastapi import FastAPI, Request, Response, status
from fastapi.responses import StreamingResponse
# ---------------------------------------------------------------------------
# Server constants
# ---------------------------------------------------------------------------
SERVER_NAME = "WeatherServer"
SERVER_VERSION = "1.0.0"
PROTOCOL_VERSION = "2024-11-05" # Cherry Studio current
# ---------------------------------------------------------------------------
# Weather helpers
# ---------------------------------------------------------------------------
OPENWEATHER_URL = "https://api.openweathermap.org/data/2.5/weather"
API_KEY: str | None = None
USER_AGENT = "weather-app/1.0"
async def fetch_weather(city: str) -> dict[str, Any]:if not API_KEY:return {"error": "API_KEY 未設置,請提供有效的 OpenWeather API Key。"}params = {"q": city, "appid": API_KEY, "units": "metric", "lang": "zh_cn"}headers = {"User-Agent": USER_AGENT}async with httpx.AsyncClient(timeout=30.0) as client:try:r = await client.get(OPENWEATHER_URL, params=params, headers=headers)r.raise_for_status()return r.json()except httpx.HTTPStatusError as exc:return {"error": f"HTTP 錯誤: {exc.response.status_code} - {exc.response.text}"}except httpx.RequestError as exc:return {"error": f"網絡請求失敗: {exc}"}except json.JSONDecodeError:return {"error": "OpenWeather 返回的數據不是有效的 JSON"}def format_weather(data: dict[str, Any]) -> str:if "error" in data:return data["error"]city = data.get("name", "未知")country = data.get("sys", {}).get("country", "未知")temp = data.get("main", {}).get("temp", "N/A")humidity = data.get("main", {}).get("humidity", "N/A")wind = data.get("wind", {}).get("speed", "N/A")desc = data.get("weather", [{}])[0].get("description", "未知")return (f"🌍 {city}, {country}\n"f"🌡 溫度: {temp}°C\n"f"💧 濕度: {humidity}%\n"f"🌬 風速: {wind} m/s\n"f"🌤 天氣: {desc}")async def stream_weather(city: str, req_id: int | str) -> AsyncIterator[bytes]:# 進度提示(不會出錯的部分放在try外面)yield json.dumps({"jsonrpc": "2.0","id": req_id,"stream": f"查詢{city}天氣中…"}).encode() + b"\n"try:await asyncio.sleep(0.3)data = await fetch_weather(city)  # 主要可能出錯點if "error" in data:yield json.dumps({"jsonrpc": "2.0","id": req_id,"error": {"code": -32002,  # 保留業務錯誤碼"message": data["error"]}}).encode() + b"\n"return# 正常結果(json.dumps理論上不會出錯)yield json.dumps({"jsonrpc": "2.0","id": req_id,"result": {"content": [{"type": "text", "text": format_weather(data)}],"isError": False}}).encode() + b"\n"except Exception as exc:# 系統級錯誤單獨處理yield json.dumps({"jsonrpc": "2.0","id": req_id,"error": {"code": -32003,  # 保留系統錯誤碼"message": f"服務器內部錯誤: {str(exc)}"}}).encode() + b"\n"# ---------------------------------------------------------------------------# FastAPI app# ---------------------------------------------------------------------------
app = FastAPI(title="WeatherServer HTTP-Stream v8")
TOOLS_REGISTRY = {"tools": [{"name": "get_weather","description": "用于進行天氣信息查詢的函數,輸入城市英文名稱,即可獲得當前城市天氣信息。","inputSchema": {"type": "object","properties": {"city": {"type": "string","description": "City name, e.g. 'Hangzhou'"}},"required": ["city"]}}],"nextCursor": "qinqing"
}
@app.get("/mcp")
async def mcp_initialize_via_get():
# GET 請求也執行了 initialize 方法return {"jsonrpc": "2.0","id": 0,"result": {"protocolVersion": PROTOCOL_VERSION,"capabilities": {"streaming": True,"tools": {"listChanged": True}},"serverInfo": {"name": SERVER_NAME,"version": SERVER_VERSION},"instructions": "Use the get_weather tool to fetch weather by cityname."}
}
@app.post("/mcp")
async def mcp_endpoint(request: Request):try:body = await request.json()# ? 打印客戶端請求內容print("💡 收到請求:", json.dumps(body, ensure_ascii=False, indent=2))except Exception:return {"jsonrpc": "2.0", "id": None, "error": {"code": -32700,"message": "Parse error"}}req_id = body.get("id", 1)method = body.get("method")# ? 打印當前方法類型print(f"🔧 方法: {method}")# 0) Ignore initialized notification (no response required)if method == "notifications/initialized":return Response(status_code=status.HTTP_204_NO_CONTENT)# 1) Activation probe (no method)if method is None:return {"jsonrpc": "2.0", "id": req_id, "result": {"status": "MCP serveronline."}}# 2) initializeif method == "initialize":return {"jsonrpc": "2.0","id": req_id,"result": {"protocolVersion": PROTOCOL_VERSION,"capabilities": {"streaming": True,"tools": {"listChanged": True}},"serverInfo": {"name": SERVER_NAME, "version": SERVER_VERSION},"instructions": "Use the get_weather tool to fetch weather bycity name."}}# 3) tools/listif method == "tools/list":print(json.dumps(TOOLS_REGISTRY, indent=2, ensure_ascii=False))return {"jsonrpc": "2.0", "id": req_id, "result": TOOLS_REGISTRY}# 4) tools/callif method == "tools/call":params = body.get("params", {})tool_name = params.get("name")args = params.get("arguments", {})if tool_name != "get_weather":return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32602,"message": "Unknown tool"}}city = args.get("city")if not city:return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32602,"message": "Missing city"}}# return StreamingResponse(stream_weather(city, req_id),media_type="application/json")data = await fetch_weather(city)return {"jsonrpc": "2.0","id": req_id,"result": {"content": [{"type": "text", "text": format_weather(data)}],"isError": False}}# 5) unknown methodreturn {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message":"Method not found"}}
# ---------------------------------------------------------------------------
# Runner
# ---------------------------------------------------------------------------
def main() -> None:parser = argparse.ArgumentParser(description="Weather MCP HTTP-Stream v8")parser.add_argument("--api_key", required=False,default='xxxx')parser.add_argument("--host", default="127.0.0.1")parser.add_argument("--port", type=int, default=8000)args = parser.parse_args()global API_KEYAPI_KEY = args.api_keyimport uvicornuvicorn.run(app, host=args.host, port=args.port, log_level="info")
if __name__ == "__main__":# npx -y @modelcontextprotocol/inspector uv run weather2.pymain()

其中api_key 需要自己申請即可,可以免費調用大概1000次(測試和學習基本夠用了)?

2. 使用mcp的檢查器進行測試

npx -y @modelcontextprotocol/inspector uv run xxxx.py

參考官網:Inspector - Model Context Protocol

3. 將py進行啟動運行

4. 檢查器啟動成功之后進行測試

簡單的例子Streamable HTTP就成功了 ~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89036.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89036.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89036.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

量子計算與AI的融合:開啟智能革命的“量子躍遷”新范式

當量子計算的并行算力與人工智能的深度學習能力相遇,一場顛覆傳統認知的技術革命正在醞釀。從藥物研發到自動駕駛,從金融風控到氣候預測,兩者的融合不僅突破了經典計算的算力天花板,更催生出全新的算法范式與產業生態。本文將深入解析量子計算與AI融合的技術邏輯、核心突破…

【氮化鎵】不同偏壓應力下電荷俘獲效應導致的P-GaN HEMT閾值電壓不穩定性

2022年12月7日,意大利國家研究委員會微電子與微系統研究所的Giuseppe Greco等人在《Applied Physics Letters》期刊發表了題為《Threshold voltage instability by charge trapping effects in the gate region of p-GaN HEMTs》的文章,基于對p-GaN高電子遷移率晶體管(HEMTs…

ONLYOFFICE深度解鎖系列.10-如何識別圖像和PDF掃描件中的文本?用ONLYOFFICE的AI OCR輕松搞定!

ONLYOFFICE 文檔版本 9.0帶來多項 AI 關鍵改進,顯著提升您處理電子表格和 PDF 文件的工作效率。本指南將重點介紹新增的 OCR 功能,并講解如何在 PDF 編輯器中利用 AI 助手將圖像轉為可編輯文本。什么是 OCR 文字識別?OCR 技術能夠掃描各類文檔…

單例模式詳解:確保一個類只有一個實例

在軟件開發中,設計模式是解決常見問題的經典方案。單例模式(Singleton Pattern)作為創建型設計模式中最簡單也最常用的一種,確保一個類只有一個實例,并提供一個全局訪問點。本文將全面探討單例模式的概念、多種實現方式…

Appdynamic 配置 PostgreSQL 收集器

配置 PostgreSQL 收集器 您可以使用數據庫可見性監控任何版本的 PostgreSQL。 連接詳細信息 部分場地描述創建新的收集器數據庫類型您想要監控的數據庫類型。代理人管理收集器的數據庫代理。收藏家姓名您想要用來識別收集器的名稱。連接詳細信息主機名或 IP 地址運行數據庫的機…

其他常見 HTTP 方法

除了最常用的四種方法(GET、POST、PUT、DELETE),HTTP 協議還定義了一些較少使用但非常有用的請求方法,常用于調試、部分更新、跨域預檢等場景。1. HEAD 方法:獲取響應頭 特點: 用途:與 GET 類似…

Web應用防火墻(WAF)技術

目錄 一:簡介 1.1 Web安全現狀 1.2 傳統防御的局限性 二:Web應用防火墻技術解析 2.1 WAF核心架構 2.2 關鍵技術特性 三:WAF必要性 3.1 典型防護場景 3.2 與傳統方案對比 四:進階防護方案 4.1 智能WAF架構 4.2 關鍵技術…

機器學習之線性回歸(七)

機器學習之線性回歸(七) 文章目錄機器學習之線性回歸(七)一、線性回歸線性回歸超全指南:從“一條直線”到“正則化調參”的完整旅程0. 先對齊語言:標稱型 vs 連續型1. 問題形式化2. 損失函數全景3. 求解方法…

基于開源AI大模型、AI智能名片與S2B2C商城小程序源碼的用戶價值引導與核心用戶沉淀策略研究

摘要:在數字化商業生態中,用戶留存與核心用戶培育是產品成功的關鍵。本文聚焦開源AI大模型、AI智能名片與S2B2C商城小程序源碼的協同應用,探討如何通過技術賦能實現用戶價值引導與核心用戶沉淀。研究結合工業品供應鏈、美妝品牌、健康食品行業…

課題申報書成功率提升85%!借助大模型AI精準選題、搭綜述框架及提煉創新點(附實操AI提示詞)

大家好,感謝關注。我是七哥,一個在高校里不務正業,折騰用大模型AI實操的學術人。可以添加七哥(qige500)交流學術寫作或ChatGPT、Claude等學術大模型AI領域相關問題,多多交流,相互成就,共同進步。 寫一份高質量的課題申報書往往面臨許多困難,對很多同仁來說,難就難在…

Spring之【寫一個簡單的IOC容器EasySpring】

目錄 EasySpring 注解 EasyAutowired EasyComponent EasyComponentScan EasyLazy EasyPostConstruct EasyProtoType EasyValue Bean定義信息 EasyBeanDefinition 管理Bean定義信息 EasyBeanDefinitionRegister Aware EasyAware EasyBeanFactoryAware EasyBea…

Selenium動態網頁爬蟲編寫與解釋

使用Selenium來抓取動態網頁。動態網頁通常是指那些通過JavaScript動態加載內容的網頁,這些內容在初始HTML中并不存在,因此使用傳統的requests庫無法獲取到這些動態生成的內容。Selenium可以模擬瀏覽器行為,等待JavaScript執行并渲染頁面&…

element el-table中使用el-image圖片預覽被其他表格遮擋

或者::v-deep .el-table__cell {position: static !important;}

MyBatis與Spring整合優化實戰指南:從配置到性能調優

一、SqlSessionFactory配置最佳實踐 1.1 數據源配置優化 <!-- Spring配置示例 --> <bean id"dataSource" class"com.zaxxer.hikari.HikariDataSource" destroy-method"close"><property name"driverClassName" value&q…

LUA(初學)

條件語句if if then endlocal a 2 if a < 6 thenprint(a) end2條件語句if else if then else endlocal a 2 local b 3 if a > 6 thenprint(a) elseprint(b) end3while循環語句 while do endlocal a 2 while a < 5 doa a 1print(a) end3 4 5for循環語句 for do …

JMeter 連接與配置 ClickHouse 數據庫

其他人都需要好幾十積分提供jar包&#xff0c;我5積分提供給大家 jar包地址&#xff1a;https://download.csdn.net/download/weixin_41853064/91370401 1、將jar包內的文件放入jmeter/lib/exc目錄并重啟jmeter 2、配置jmeter JDBC連接 3、復制 click hourse的類名&#xff1…

Kmeams聚類算法詳解

文章目錄一、聚類任務的簡介1.1 聚類的核心特征1.2 聚類的典型應用場景二、Kmeans的思想和數學原理2.1 核心思想2.2 數學原理三、Kmeans計算過程示例3.1 數據集3.2 步驟1&#xff1a;確定K值并初始化簇中心3.3 步驟2&#xff1a;計算樣本到簇中心的距離并分配簇3.4 步驟3&#…

平升智慧水務整體解決方案,大數據驅動的智慧水務,讓城市供水更智能

平升電子智慧水務整體解決方案 智慧供水整體解決方案&#xff0c;在調度中心搭建智慧水務平臺&#xff0c;為供水各環節安裝智能測控設備&#xff0c;應用物聯網、互聯網、大數據、云計算、人工智能等新一代信息技術&#xff0c;構建智慧水務綜合管理系統&#xff0c;貫穿從水源…

Samba配置使用

主要作用&#xff1a;將Linux系統中的文件共享給windows配置過程&#xff1a;&#xff08;1&#xff09;打開命令終端&#xff1a;獲取超級用戶權限后運行以下指令:apt-get install samba&#xff08;2&#xff09;修改samba配置文件&#xff1a;gedit /etc/samba/smb.conf :找…

Datawhale AI數據分析 筆記

Part1&#xff1a;數據分析入門--信息統計知識點&#xff1a;什么是提示詞&#xff08;Prompt&#xff09;&#xff1f;在人工智能&#xff08;AI&#xff09;領域&#xff0c;"提示詞"是一個關鍵概念&#xff0c;它指的是輸入給AI模型的文本或指令&#xff0c;用于引…