当前位置: 首页 > web >正文

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.xdnf.cn/news/15527.html

相关文章:

  • 【牛客刷题】小红的数字删除
  • 算法:投票法
  • VUE export import
  • MinIo快速入门
  • JJ20 Final Lap演唱会纪念票根生成工具
  • MIPI DSI (一) MIPI DSI 联盟概述
  • Oracle 学习笔记
  • Docker入门基础
  • GaussDB between的用法
  • 文心一言 4.5 开源深度剖析:中文霸主登场,开源引擎重塑大模型生态
  • 用基础模型构建应用(第九章)AI Engineering: Building Applications with Foundation Models学习笔记
  • # 检测 COM 服务器在线状态
  • python 双下划线开头函数
  • 网络协议和基础通信原理
  • Go泛型完全指南:从基础到实战应用
  • Fluent许可文件安装和配置
  • 车载诊断框架 --- 车载诊断GuideLine
  • 如何集成光栅传感器到FPGA+ARM系统中?
  • 如何更改Blender插件安装位置呢?
  • qt 使用memcpy进行内存拷贝时注意的问题
  • 硬盘爆满不够用?这个免费神器帮你找回50GB硬盘空间
  • EasyExcel实现Excel文件导入导出
  • [Nagios Core] 事件调度 | 检查执行 | 插件与进程
  • 解决Qt中“known incorrect sRGB profile“警告的Photoshop修改方法
  • 如何基于FFMPEG 实现视频推拉流
  • DataWhale AI夏令营 Task2笔记
  • asyncio.Task` 的工作机制与高级应用
  • 嵌入式硬件篇---单稳态多谐施密特电路
  • 【WRFDA实操第一期】服务器中安装 WRFPLUS 和 WRFDA
  • 2025年睿抗机器人开发者大赛CAIP-编程技能赛本科组(省赛)解题报告 | 珂学家