基于Python sdk發布自己的第一個mcp-client

說在前面

上一篇文章發布了一個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;網絡 和 渲染。當用戶在地…