说在前面

上一篇文章发布了一个mcp-server,具体的server是否能被正确的访问到?是否能够得到正常的返回? 在github上找到一个客户端的代码实现,我把里面的大模型调用换成了支持国内大模型的方式,一起来验证一下吧~

主要功能

  • 连接mcp-server
  • 获取mcp 工具列表
  • 调用大模型明确需要调用的方法以及参数
  • 执行工具获取返回值
  • 调用大模型进行问题总结
  • 详尽的日志信息,帮助你更好的了解整个过程

一些说明

关于大模型的选择

文章里用的是open-ai sdk,但是因为万能的阿里云连接国际,所以阿里百炼的api-key也是通用的。百炼给新用户都是有免费的大模型调用额度的,放心使用。

大模型的使用

可以参考阿里百炼的api说明,里面有详细的参数,有兴趣的可以自行拼接尝试。

代码

import asyncio
import json
import os
import sys
from typing import Optional, List, Dict
from contextlib import AsyncExitStackfrom mcp import ClientSession
from mcp.client.sse import sse_clientfrom openai import OpenAI
from dotenv import load_dotenvload_dotenv()  # load environment variables from .envclass MCPClient:def __init__(self):# Initialize session and client objects# 表示对象可以是None,也可以是ClientSession类型self.session: Optional[ClientSession] = Noneself.exit_stack = AsyncExitStack()self.openai = OpenAI(api_key="your key your key your key",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",)async def connect_to_sse_server(self, server_url: str):"""Connect to an MCP server running with SSE transport"""# Store the context managers so they stay aliveself._streams_context = sse_client(url=server_url)streams = await self._streams_context.__aenter__()# * 表示将streams解包,将其作为参数传递给ClientSession,假设streams是一个元组,# 那么*streams就等价于ClientSession(stream1, stream2, stream3)self._session_context = ClientSession(*streams)self.session: ClientSession = await self._session_context.__aenter__()# Initializeawait self.session.initialize()# List available tools to verify connectionprint("Initialized SSE client...")print("Listing tools...")response = await self.session.list_tools()tools = response.toolsprint("工具列表:", json.dumps(response.model_dump(), ensure_ascii=False, indent=2))print("\nConnected to server with tools:", [tool.name for tool in tools])async def cleanup(self):"""Properly clean up the session and streams"""if self._session_context:await self._session_context.__aexit__(None, None, None)if self._streams_context:await self._streams_context.__aexit__(None, None, None)async def process_query(self, query: str) -> str:"""Process a query using OpenAI and available tools"""messages = [{"role": "user","content": query}]response = await self.session.list_tools()# 转换工具格式以适应OpenAI的函数调用要求available_tools: List[Dict] = [{ "type": "function","function": {"name": tool.name,"description": tool.description,"parameters": tool.inputSchema  # 假设inputSchema符合OpenAI的参数格式要求}} for tool in response.tools]print(f"大模型调用详情: {json.dumps(messages, ensure_ascii=False, indent=2)}")# 初始OpenAI API调用response = self.openai.chat.completions.create(model="qwen3-32b",  # 使用OpenAI模型max_tokens=1000,messages=messages,tools=available_tools,tool_choice="auto",  # 自动决定是否调用工具extra_body={"enable_thinking": False,})# 打印大模型决策过程print("\n===== 大模型工具调用决策 =====")print(f"原始响应: {json.dumps(response.model_dump(), ensure_ascii=False, indent=2)}")# 处理响应和工具调用tool_results = []final_text = []response_message = response.choices[0].messagetool_calls = response_message.tool_callsprint(f"是否调用工具: {'是' if tool_calls else '否'}")# 打印工具调用详情if tool_calls:print(f"调用工具数量: {len(tool_calls)}")for i, call in enumerate(tool_calls):print(f"工具 {i+1}: {call.function.name}, 参数: {call.function.arguments}")# 如果有工具调用if tool_calls:for tool_call in tool_calls:tool_name = tool_call.function.nametool_args = json.loads(tool_call.function.arguments)# 执行工具调用print(f"\n===== 调用工具 '{tool_name}' =====")print(f"参数: {json.dumps(tool_args, ensure_ascii=False, indent=2)}")result = await self.session.call_tool(tool_name, tool_args)print(f"返回结果: {json.dumps(str(result.content), ensure_ascii=False, indent=2)}")tool_results.append({"call": tool_name, "result": result})final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")# 将工具调用结果添加到对话历史messages.append({"role": "assistant","content": None,"tool_calls": [tool_call.model_dump()]})messages.append({"role": "tool","tool_call_id": tool_call.id,"content": str(result.content)})print(f"大模型调用详情: {json.dumps(messages, ensure_ascii=False, indent=2)}")# 获取OpenAI的下一次响应response = self.openai.chat.completions.create(model="qwen3-32b",max_tokens=1000,messages=messages,extra_body={"enable_thinking": False,})final_response = response.choices[0].message.contentif final_response:final_text.append(final_response)else:# 没有工具调用,直接使用响应内容if response_message.content:final_text.append(response_message.content)return "\n".join(final_text)async def chat_loop(self):"""Run an interactive chat loop"""print("\nMCP Client Started!")print("Type your queries or 'quit' to exit.")while True:try:query = input("\nQuery: ").strip()if query.lower() == 'quit':breakresponse = await self.process_query(query)print("\n" + response)except Exception as e:print(f"\nError: {str(e)}")async def main():# if len(sys.argv) < 2:#     print("Usage: uv run client.py <URL of SSE MCP server (i.e. http://localhost:8080/sse)>")#     sys.exit(1)client = MCPClient()try:# await client.connect_to_sse_server(server_url=sys.argv[1])await client.connect_to_sse_server(server_url="http://localhost:8080/sse")await client.chat_loop()finally:print("Cleaning up...")# await client.cleanup()if __name__ == "__main__":asyncio.run(main())

说到最后

以上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94087.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94087.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94087.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 浮点数与定点数详细解析

C# 浮点数与定点数详细解析 在 C# 中&#xff0c;数值类型主要分为&#xff1a; 整数型&#xff08;int, long 等&#xff09;浮点型&#xff08;float, double&#xff09;定点型&#xff08;decimal&#xff09; 浮点数和定点数在内部的表示方式不同&#xff0c;导致它们的 精…

【小宁学习日记5 stm32】LED闪烁 LED流水灯 蜂鸣器

目录 01.LED闪烁 1、搭建电路板 2、新建工程 &#xff08;1&#xff09;前期准备 &#xff08;2&#xff09;创建工程文件夹结构 &#xff08;3&#xff09;复制固件库文件到对应文件夹 &#xff08;4&#xff09;在 Keil 中创建工程 &#xff08;5&#xff09;配置工程…

openstack的novnc兼容问题

1.今天在部署O版过程中发现了novnc组件不兼容openstack2.novnc一直报错&#xff0c;令牌过期&#xff0c;原本以为是python代码配置的问题&#xff0c;最后经过排查很久发现竟然是novnc的版本和openstack的O版不兼容novncyum remove -y novnc*安装支持版本yum install -y novnc…

Day25 栈 队列 二叉树

day25 栈 队列 二叉树使用栈计算表达式的值 概述 通过两个栈&#xff08;数值栈和符号栈&#xff09;实现中缀表达式求值。算法核心是&#xff1a; 遇到数字时&#xff0c;累加并入数值栈&#xff1b;遇到运算符时&#xff0c;比较其与符号栈顶运算符的优先级&#xff1a; 若当…

阿里云RDS MySQL数据归档全攻略:方案选择指南

引言在日常数据库管理中&#xff0c;数据归档是必不可少的重要环节。随着业务数据的不断增长&#xff0c;将历史数据从生产数据库迁移到更经济的存储方案中&#xff0c;不仅可以降低存储成本&#xff0c;还能提升数据库性能。阿里云提供了丰富的数据归档解决方案&#xff0c;本…

线性回归学习

一、线性回归简介核心思想&#xff1a;线性回归是一种通过属性的线性组合来做预测的模型。它的目标很明确&#xff0c;就是找到一条合适的直线、平面或者更高维度的超平面&#xff0c;让预测出来的值和实际真实值之间的差距尽可能小。比如在预测房屋价格时&#xff0c;就可以根…

如何使用 DeepSeek 助力工作:全面指南​

一、引言​1.1 DeepSeek 简介​DeepSeek 的定位与目标概述​核心技术亮点&#xff08;大语言模型、多模态能力、AI Agent 框架&#xff09;​1.2 工作场景中应用 AI 的趋势​AI 对职场效率提升的重要性​DeepSeek 在众多 AI 工具中的独特地位​二、DeepSeek 基础功能介绍​2.1 …

车载诊断架构 --- EOL引起关于DTC检测开始条件的思考

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

JCTools Spmc 单生产者-多消费者的无锁并发有界队列

SpmcArrayQueue 是 JCTools 中为 单生产者-多消费者&#xff08;Single-Producer-Multi-Consumer&#xff09; 场景设计的有界队列。与 SPSC 模型相比&#xff0c;SPMC 的复杂性主要体现在消费者侧&#xff0c;因为多个消费者线程需要以线程安全的方式竞争消费同一个队列中的元…

SpringAI1.0.1实战教程:避坑指南25年8月最新版

Spring AI 1.0.1 使用教程 项目简介 作为一个Java的开发者 听到Java也有ai框架了 很高兴~~~ 本来想学一下SpringAI但是网上卖课的一大堆&#xff0c;并且大部分课程都是五月的&#xff0c;到2025年的8月份&#xff0c;SpringAI的版本做了很多更新&#xff0c;所以我本人参考…

Maven架构的依赖管理和项目构建

​​​​​​什么是依赖管理对第三方依赖包的管理&#xff0c;可以连接互联网下载项目所需第三方jar包。对自己开发的模块的管理&#xff0c;可以像引用第三方依赖包一样引用自己项目的依赖包。Maven的依赖管理方式和传统方式有什么区别传统方式&#xff1a;从官网手动下载jar包…

微信小程序开发(一):使用开发者工具创建天气预报项目

Hi&#xff0c;我是前端人类学&#xff08;之前叫布兰妮甜&#xff09;&#xff01; 从今天开始&#xff0c;我将开启一个全新的微信小程序开发系列教程&#xff0c;通过实际项目带大家系统学习小程序开发。作为系列的第一篇文章&#xff0c;我们将从最基础的环境搭建开始&…

【链表 - LeetCode】24. 两两交换链表中的节点

24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a; - 迭代 首先是直接遍历的做法&#xff0c;这里注意调整指针指向的顺序。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* List…

爬虫基础学习-链接协议分析,熟悉相关函数

1、urlparse&#xff1a;&#xff08;python标准库中的一个模块&#xff0c;解析和操作url&#xff09;标准的url链接格式&#xff1a;scheme://netloc/path;params?query#fragmentscheme&#xff08;协议&#xff09; http or https netloc&#xff08;网络位置&#xff09; …

kkfileview预览Excel文件去掉左上角的跳转HTML预览、打印按钮

上篇说了使用nginx代理kkfile预览文件&#xff0c;但是又发现个新问题&#xff0c;预览其他文件时都正常&#xff0c;但是预览.xlsx格式的时候&#xff0c;在左上角会有【跳转HTML预览】【打印】两个按钮&#xff0c;如下所示&#xff1a;这篇就来说一下如何去掉。首先这个跟kk…

阿里开源新AI code工具:qoder功能介绍

下载地址&#xff1a; https://qoder.com/ 文档地址&#xff1a; https://docs.qoder.com/ 文章目录1. AI 编码发展趋势2. 真实世界软件开发的挑战3. 我们的方法3.1. 透明度3.1.1. 知识可见性3.1.2. 执行透明度3.2. 增强上下文工程3.3. 规范驱动与任务委托3.3.1. 聊天模式&…

什么是短视频矩阵系统企业立项功能源码开发,支持OEM

短视频矩阵系统企业立项功能源码开发解析在短视频行业蓬勃发展的当下&#xff0c;企业纷纷布局短视频矩阵&#xff0c;以实现多平台、多账号的协同运营。而企业立项作为短视频矩阵项目启动的关键环节&#xff0c;其高效、规范的管理直接影响项目的推进效率与成果。为此&#xf…

当GitHub宕机时,我们如何协作?

问题背景与影响 GitHub作为主流代码托管平台的依赖现状宕机对分布式团队、CI/CD流水线、紧急修复的影响案例其他类似平台&#xff08;GitLab、Bitbucket&#xff09;的潜在连带风险 本地与离线协作方案 利用Git分布式特性&#xff1a;本地仓库继续提交&#xff0c;恢复后同步搭…

【会议跟踪】Model-Based Systems Engineering (MBSE) in Practice 2025

会议主旨与议题 会议宣传链接:https://www.sei.cmu.edu/events/mbse-in-practice/ 本次会议将于2025年8月21日位美国弗吉尼亚州阿灵顿(五角大楼所在地)举行。本次会议主旨为 MBSE in Practice: Bridging the Gap Between Theory and Success(2025)。随着软件定义系统日趋…

浏览器的渲染流程:从 HTML 到屏幕显示

在我们日常使用浏览器浏览网页时&#xff0c;往往忽略了浏览器背后复杂的渲染过程。从输入 URL 到页面最终显示在屏幕上&#xff0c;浏览器需要经过一系列精心设计的步骤。 浏览器渲染的整体流程浏览器的渲染流程可以大致分为两个主要部分&#xff1a;网络 和 渲染。当用户在地…