MCP終極篇!MCP Web Chat項目實戰分享

目錄

前言

MCP Web Chat

功能概要說明

MCP Web Chat代碼調用結構說明

api動態生成MCP Server

方法一(之前的方法)

方法二(現在的方法)

做個比較

相關代碼

相關問題解決說明

穩定性

由此引申而來的異步任務問題

MCP周期問題(待討論)

結語


前言

前面三篇文章,循序漸進的從MCP概念、初步使用到多tool調用到現有api動態生成mcp server,逐步像實際項目邁進。

本篇是MCP終極篇。將介紹如何實現MCP的Web Chat,以及過程中遇到的一些問題與解決。相關代碼,我已經在Github開源。【github地址:loli0123456789/MCPWebChat: 基于MCP的WebChat】

本篇主要內容:

  • 功能概要說明

  • MCP Web Chat主體架構設計說明

通過該部分內容,你可以更好的理解為何如此規劃設計

  • api動態生成MCP Server 功能說明

這塊會說下動態生成MCP Server的兩種思路與比較

  • 相關問題解決說明

MCP系列文章,可通過如下鏈接快速回看:

全網少有-通過Python調用MCP_python mcp-CSDN博客

MCP第二彈,支持Webapi調用與動態MCP【附完整代碼】-CSDN博客

MCP 第三波升級!Function Call 多步調用 + 流式輸出詳解-CSDN博客

MCP Web Chat

功能概要說明

1、通過數據庫或配置文件管理MCP Server

2、內置通用MCP Server,如獲取當前時間、訪問網頁內容等,可自行根據需要添加

3、內置根據api信息自動生成tool的MCP Server

4、可以根據獲取的MCP tools進行Web界面對話,對話可流式顯示工具調用過程、最終結果

MCP Web Chat代碼調用結構說明

在網上的多數MCP代碼案例中,多數MCP的類是Server、Client,其中Client負責連接Server,同時負責通過大模型關聯tools進行chat對話。這里Server只有在需要自己創建MCP Server的情況才需要,因此主要就是Client。

但是這里有兩個問題:

1)把大模型放到Client里,有多個Server需要連接怎么辦?

2)有多個用戶要進行chat對話,消息如何管理?

基于以上問題,我對此的規劃是:MCP_Client、MCP_Host、MCP_Chat。

MCP_Client:用于定義MCP Client

注意: 后續為了解決MCP Client長時間會掛掉的問題,同時為了降低自己寫代碼的復雜性,Client直接使用了百度appbuilder實現的MCP_Client功能。

MCP_Host:負責連接多個MCP_Client,全局單例

MCP_Chat:負責關聯MCP_Host,并對接用戶Chat,每次對話會實例化一個MCP_Chat對象,實現每個對話話的消息記錄單獨管理

一些MCP相關的通用方法,會放到mcp_utils文件。

在chat api層面,就是直接和MCP_Chat實例化對象交互,同時會把最新消息記錄傳遞到對象,從而實現多輪對話。

對于流式輸出,就是在MCP_Chat調用過程中,把相關信息都通過yeild的方式給流式輸出,api層面再傳出去就可以了。前端流式輸出的效果,對content消息增加type區分,就可以知道是思考過程,還是最終結果。

api動態生成MCP Server

之前文章里這塊內容也寫過,但是當時實現方式不夠理想,后來又換了一個更底層,更可控的方法。正好兩個方法可以對比說明下。

方法一(之前的方法)

1)根據api信息,動態生成調用方法

2)通過mcp.add_tool添加1)中方法

方法二(現在的方法)

使用mcp官方的底層server方法,可以自定義list_tool和call_tool方法,這樣靈活性、可控性會更高。也就是說只要把列出tool的方法和調用tool的方法實現,就可以了。

做個比較

1)傳遞給大模型的tool信息完善度

通過自定義list_tool,可以自定義傳遞給大模型的tools信息,這樣你可以設置更完善的function信息,包括參數信息、必填信息等。而通過mcp.add_tool()添加的工具,tool信息是底層自己設置,可能信息不夠全。

對于大模型來說,只有給的信息足夠全,那么最終的效果才會更好。

2)調用tool的可控性

通過自定義call_tool,可以更好的控制如何調用工具,對于需要傳遞鑒權信息,或者有些api調用特殊的情況,都可以很好的自我控制。同樣的,通過mcp.add_tool()添加的工具,調用的底層自己去調用,靈活度就比較低了。

相關代碼
async?def?init_tools():tools?=?[]for?api?in?api_configs:#?編碼,可作為tool名稱code?=?api.get("name",?"")#?方法描述description?=?api.get("discription",?"")#?實際調用接口地址api_url?=?api.get("api_url",?"")#?入參input_params?=?api.get("input_params",?"")tool?=?types.Tool(name=code,description=description,inputSchema=process_input_param(input_params),)tools.append(tool)return?tools@mcp.list_tools()
async?def?list_tools()?->?list[types.Tool]:tools?=?await?init_tools()return?tools

如上代碼,你可以自己控制tool的詳細參數信息,給盡可能完整的信息,讓大模型可以更好的理解上下文。

async?def?request_api(name:?str,?arguments:?dict):"""請求api"""api_url?=?""for?api?in?api_configs:if?api["name"]?==?name:api_url?=?api["api_url"]breakelse:raise?ValueError(f"Unknown?tool:?{name}")result?=?await?post_form_data(api_url,?arguments,?token=None)return?result@mcp.call_tool()
async?def?fetch_tool(name:?str,?arguments:?dict)?->?list[types.Content]:print(f"name:?{name}")print(f"arguments:?{arguments}")result?=?await?request_api(name,?arguments)return?[types.TextContent(type="text",?text=result)]

如上代碼,你可以更好的控制如何去調用api,傳遞token等參數。

相關問題解決說明

過程中遇到的一個主要問題就是MCP連接的穩定性與周期問題。

穩定性

高德MCP Server(amap)在連接一段時間后會不可用:

1)幾分鐘不調用,再調用的時候會報aclose錯誤(它自動關閉連接了,但是我自己開發的MCP Server不會如此)

解決 增加心跳檢測,每2分鐘ping一次,MCP有相應的方法send_ping()(設置3分鐘不行,這個時候已經失效…)

2)雖然有了心跳檢測,但是過了幾個小時候后,再次調用會報錯(大意是驗證信息過期)

解決 每2個小時,重啟一次MCP Server(自己開發的MCP Server沒這個問題,因為也沒做鑒權信息,當然我也沒針對某個MCP Server這么控制重啟)

由此引申而來的異步任務問題

MCP Client底層使用了sse_client用到了task_group,然后FastAPI框架也是異步的。基于task_group的設計,在它下面發起的任務,只能在它這里取消,就很容易報各種cancelscope錯誤。

比如底層創建了一個sse_client,結果在系統重啟MCP Server(需要先關閉再啟動連接)的時候,就報錯了;心跳同樣是在關閉MCP Client的時候需要關閉,也會有一樣的問題。

解決的辦法,就是套娃,在創建心跳任務、重啟任務之外,都加一個task_group或cancel_scope,這樣就不會導致一直向上傳遞導致報錯的問題。

async?def?initialize(self):"""延遲初始化(避免啟動時阻塞)"""if?not?self._initialized:self._task_group?=?anyio.create_task_group()await?self._task_group.__aenter__()self._task_group.start_soon(self.connect_mcp_servers)#?await?self.connect_mcp_servers()self._initialized?=?True#?使用?anyio?創建取消范圍self._heartbeat_cancel_scope?=?anyio.CancelScope()self._heartbeat_task?=?asyncio.create_task(self._run_with_cancel_scope())async?def?_run_with_cancel_scope(self):"""在取消范圍內運行心跳任務"""with?self._heartbeat_cancel_scope:await?self._start_heartbeat()

如上代碼,對于心跳任務,主要是取消,所以創建一個cancelScope就好。對于connect_mcp_servers給他創建一個rask_group。

在disconnect_mcp_servers的時候,還需要每個Client調用各自的task_group去clean_up

for?i,?client?in?enumerate(self.mcp_clients):try:log.info(f"開始清理客戶端?{i}")#?client._session_context._task_groupclient._session_context._task_group.start_soon(client.cleanup)#?self._task_group.start_soon(client.cleanup)log.info(f"已啟動清理客戶端?{i}")except?AttributeError?as?e:log.error(f"清理客戶端?{i}?時出現屬性錯誤:?{e}")traceback.print_exc()except?Exception?as?e:log.error(f"清理客戶端?{i}?時出現異常:?{type(e).__name__}:?{e}")traceback.print_exc()
MCP周期問題(待討論)

這個問題,我目前也不確定哪種方式就是合理

1)程序啟動的時候,MCP Server就都啟動連接,一直到程序關閉的時候關閉連接或定時重啟

好處:用到的時候調用速度會快

問題:可能用不到,造成資源浪費

2)在對話用到了某個MCP的時候,才去啟動連接

好處:節省資源,但是多個對話用到了某個MCP要不要創建多個Client?

問題:響應可能會慢,需要先去連接,獲取tools

3)有一個MCP連接池?在2)的基礎上啟動,不斷放到池子里,通過1)的方式維護

這個問題,歡迎各位討論交流

結語

今天主要講了如何將MCP 打造為一個項目實用的Web Chat應用。項目不僅僅是調用MCP進行chat,還支持直接創建通用方法MCPServer,以及基于現有api創建動態tool的MCPServer。

在文章的后半部分,講了下項目過程中遇到的一些問題以及如何解決,還有一些問題留待各位交流探討。

相關代碼已經開源到Github,?【github地址:loli0123456789/MCPWebChat: 基于MCP的WebChat】。

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

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

相關文章

破解VMware遷移難題

理解VMware遷移的常見挑戰 VMware遷移過程中可能遇到的難題包括兼容性問題、性能瓶頸、數據完整性風險以及網絡配置復雜性。識別這些問題是制定有效遷移策略的基礎。 評估當前環境與目標環境 詳細分析源VMware環境的配置、虛擬機數量、存儲類型和網絡拓撲。對比目標環境的硬件和…

15-STM32F103RCT6的FLASH寫入

STM32F103RCT6的FLASH寫入 1.//*******************************固件升級地址信息******************************// #define STM32_FLASH_BASE 0x08000000 //固件起始地址 #define FLASH_APP_ADDR 0x08005000 //APP開始地址 #define FLASH_PARA_ADDR 0x0803C000 //固件關…

PPO:近端策略優化算法

溫馨提示: 本篇文章已同步至"AI專題精講" PPO:近端策略優化算法 摘要 我們提出了一類新的用于強化學習的 policy gradient 方法,該方法在與環境交互以采樣數據和使用隨機梯度上升優化一個“代理”目標函數之間交替進行。與標準的…

數據結構的算法分析與線性表<1>

一、算法分析: 由于語句執行一次的實際所需時間與機器的軟硬件有關,則算法分析是針對語句執行次數,而非執行時間。 時間復雜度 計算時間復雜度: 常量階 如果算法中的n是固定的,或者說n是常數,或者時間復雜…

esp32使用ESP-IDF在Linux下的升級步驟,和遇到的坑Traceback (most recent call last):,及解決

因為之前使用的是ESP-IDF5.3版本。而5.3版本又不支持ESP32P4。而V5.4版本開始正式對P4的支持。所以我把ESP-IDF 升級到V5.4.2的release版本。 一、升級版本:【根據樂鑫官方的方式升級】ESP-IDF 版本簡介 - ESP32-P4 - — ESP-IDF 編程指南 v5.4.2 文檔 更新至一個穩…

【算法】貪心算法:最大數C++

文章目錄前言題目解析算法原理字典序代碼示例策略證明前言 題目的鏈接,大家可以先試著去做一下再來看一下思路。179. 最大數 - 力扣(LeetCode) 題目解析 還是老樣子,把題目讀懂,畫出有用信息。 認真看示例&#xff0…

網絡安全職業指南:探索網絡安全領域的各種角色

本文旨在為對網絡安全領域感興趣的粉絲讀者提供一份全面的職業指南。我們將探討網絡安全領域中各種不同的職業角色,包括其職責、所需技能以及職業發展路徑,幫助你了解網絡安全領域的職業選擇,并為你的職業規劃提供參考。網絡安全職業概覽 身處…

Design Vision:顯示扇入/扇出邏輯

相關閱讀 Design Visionhttps://blog.csdn.net/weixin_45791458/category_13006970.html?spm1001.2014.3001.5482 在使用Design Vision中查看示意圖時,可以在示意圖中查看所選單元(Cell)、引腳(Pin)、端口(Port)或線網(Net)的扇入/扇出邏輯。用戶可以在當前激活的…

13.7 Meta LLaMA2-Chat核心技術突破:三重強化學習實現91.4%安全評分,超越ChatGPT的對話模型架構全解析

Meta LLaMA2-Chat核心技術突破:三重強化學習實現91.4%安全評分,超越ChatGPT的對話模型架構全解析 指令微調模型:LLaMA2-Chat 技術深度解析 LLaMA2-Chat 作為 Meta 推出的對話優化大模型,其技術實現展現了大模型對齊(Alignment)領域的前沿突破。與基礎版 LLaMA2 相比,該…

二維仿射變換筆記

二維仿射變換筆記 1. 數學基礎 1.1 變換矩陣 二維仿射變換使用3x3的齊次坐標矩陣表示: [a b tx] [c d ty] [0 0 1 ]其中: [a b; c d] 是線性變換部分,表示旋轉、縮放和錯切[tx; ty] 是平移部分最后一行 [0 0 1] 是齊次坐標的固定形式1.2 基本變換 1.2.1 平移變換 將點…

創建自定義Dataset類與多分類問題實戰

codes 文章目錄🌟 6 多分類問題與卷積模型的優化🧩 6.1 創建自定義Dataset類?? 數據集特點:🔑 關鍵實現步驟:🛠? 自定義Dataset類實現📊 數據集劃分與可視化🧠 6.2 基礎卷積模型&…

用vue自定義指令設置頁面權限

1.按鈕權限處理/*** v-hasPermi 按鈕權限處理*/import store from /storeexport default {inserted(el, binding, vnode) {const { value } bindingconst all_permission "*:*:*";const permissions store.getters && store.getters.permissionsif (value…

JPA / Hibernate

1. JPA 和 Hibernate 有什么區別?JPA 是 Java 官方提出的一套 ORM 規范,它只定義了實體映射、關系管理、查詢接口等標準,不包含具體實現。Hibernate 是對 JPA 規范的最常用實現,提供了完整的 ORM 功能,并擴展了許多 JP…

kibana顯示未準備就緒

kibana顯示未準備就緒 最近在研究新版本的ELK(Elasticsearch, Logstash, Kibana)棧時遇到了一個問題:雖然服務器本身能夠訪問ELK服務,但通過瀏覽器嘗試訪問時卻無法成功。這里我將分享一些可能的排查步驟和解決方案。連接es的地址…

語音對話秒譯 + 視頻懸浮字 + 相機即拍即譯:ViiTor 如何破局跨語言場景?

在跨語言信息獲取場景中,語言壁壘常導致效率降低。ViiTor Translate 試圖通過 “場景化功能布局” ,覆蓋 語音、視頻、圖像、文本 四大維度翻譯需求。以下基于產品功能展示,拆解其核心能力: 1. 實時語音對話翻譯:打破交…

國內第一梯隊終端安全產品解析:技術與場景實踐

國內終端安全市場的第一梯隊產品,通常具備技術領先性、場景覆蓋度和規模化落地能力。結合 2025 年最新行業動態與實戰案例,以下從技術架構、核心能力和典型應用三個維度,解析當前市場的頭部產品及其差異化價值。一、技術架構與市場格局國內終…

FTP 備份,一種更安全的備份方式

備份數據后最重要的任務是確保備份安全存儲,最好是異地存儲。您可以通過物理方式將備份介質(例如磁帶和 CD/DVD)移動到異地位置。這是一個乏味、耗時、不方便且不可靠的方式。更簡單的解決方案是通過 FTP 備份到保存在異地的服務器。什么是 F…

理解 HTTP POST 請求中的 json 和 data 參數

在使用 Python 發送 HTTP POST 請求時(無論是使用 requests 還是 aiohttp),json 和 data 參數有明確的區別和使用場景。理解這些區別對正確構建請求至關重要。關鍵區別特性json 參數data 參數內容類型自動設置為 application/json需要手動設置…

C#反射機制與Activator.CreateInstance

本文僅作為參考大佬們文章的總結。 反射是C#和.NET框架中一項強大的功能,允許程序在運行時檢查、創建和操作類型、方法、屬性等元數據。作為反射機制的核心組件,Activator.CreateInstance提供了動態實例化對象的靈活方式。本文將全面剖析C#反射的原理、…

Linux的用戶和用戶組與權限解析、環境變量說明與配置、sudo配置解析和使用

一、Linux的用戶及用戶組與權限 1.1、Linux的用戶和用戶組內容介紹 Linux的用戶角色分類序號Linux的用戶角色說明1超級用戶擁有對系統的最高管理權限,可執行任意操作,默認是root用戶2普通用戶只能對自己目錄下的文件進行訪問和修改,具有登錄系…