【動手學MCP從0到1】2.5 MCP中的Context日志輸出、進度匯報和服務端調用客戶端的大模型項目實現步驟詳解

MCP中的Context

  • 1. Context
  • 2. 日志輸出
    • 2.1 服務端
    • 2.2 客戶端
      • 2.2.1 客戶端代碼調試
      • 2.2.2 客戶端全部代碼
  • 3. 進度匯報
    • 3.1 服務端
    • 3.2 客戶端
      • 3.2.1 客戶端代碼調試
      • 3.2.2 客戶端全部代碼
  • 4. 模型調用
    • 4.1 服務端
    • 4.2 客戶端
      • 4.2.1 客戶端代碼調試
      • 4.2.2 客戶端全部代碼

1. Context

Context對象給MCP Server提供了更多獲取客戶端信息、以及和客戶端進行交互的接口。通過Context對象,能夠獲取到以以下對象:

  • 當前請求的id:request_id
  • 客戶端id:client_id
  • 服務端的session對象

能夠在單次請求中額外發送以下數據給客戶端:

  • 日志輸出:可以發送服務端的日志給客戶端
  • 進度匯報:在處理一些耗時操作時,可以在處理過程中發送處理進度給客戶端
  • 模型調用:當服務端需要客戶端的大模型能力時,可以調用客戶端的大模型能力

通過Context,可以實現更加復雜的需求。但是注意,Context對象只能在Tool中使用,不能在 ResourcePrompt 中使用。使用方式也非常簡單,只需要在函數上添加一個 Context 類型的參數即可。

項目文件架構:新建一個Context_mcp文件夾,下面再分別創建三個子文件夾為Log_output、Load_report和Model_call。然后再三個子文件夾中都分別創建兩個py文件,命名為server.py和client.py

2. 日志輸出

如果服務端代碼在執行過程中想要將執行過程的日志發送給客戶端,那么借助 Context 非常方便的實現。

2.1 服務端

在Log_output文件夾下的server.py文件中,添加 Context 信息,添加的方式是接著tool工具,然后再函數中添加 Context 參數,參數的具體名稱不限制,往往采用ctx或者content進行命名.

比如定義日志輸出的函數為log_tool,參數分別為兩個:filesctx。前者是指定文件列表,用于存放文件路徑的容器,第二個就是Context對應的參數。

"""
-------------------------------------------------------------------------------
@Project : MCP projects
File    : client.py
Time    : 2025-06-05 17:20
author  : musen
Email   : xianl828@163.com
-------------------------------------------------------------------------------
"""
from mcp.server.fastmcp import FastMCP,Context# app =  FastMCP
mcp: FastMCP = FastMCP()#兩種書寫方式,都可以
# @app.tool()
@mcp.tool()
async def log_tool(files:list[str],ctx:Context):'''處理文件的接口:param files: 文件列表:param ctx: 上下文對象,無需客戶端傳遞:return: 處理結果'''for index,file in enumerate(files):await asyncio.sleep(1)# ctx.log()await ctx.info(f"正在處理第{index+1}個文件")return "所有文件處理完成"if __name__ == '__main__':mcp.run(transport='sse')

服務端的代碼中,通過log函數進行信息的傳遞,其屬于最基礎的操作,點擊函數進入技術文檔可以知道如果使用log進行消息傳遞,需要指定levelmessage兩個重要參數,其中level包含具體的信息類型。

在這里插入圖片描述

通過往下滑, 可以發現文檔中已經有關于會話信息操作的封裝函數,如下(剛好對應上面level參數中指定的4類,比如這里服務端的代碼使用ctx.info()函數進行消息傳遞)

在這里插入圖片描述

2.2 客戶端

2.2.1 客戶端代碼調試

在Log_output文件夾下的client.py文件中,先進行架構的搭建

import asyncio
from mcp.client.sse import sse_client
from mcp import ClientSessionasync def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream, write_stream) as session:await session.initialize()# 獲取所有工具tools = (await session.list_tools()).toolsprint(tools)if __name__ == "__main__":asyncio.run(run())

執行結果如下:(以上代碼是之前項目中都使用的框架,熟悉的操作,就看是不是結果可以正常輸出)
在這里插入圖片描述

目前tool工具對象中只有一個數據,因為進行演示demo,這里可以直接進行列表對象的索引(以往的項目都是遍歷循環)

tool = tools[0]
response = await session.call_tool(name=tool.name,arguments={"files":["a.txt","b.txt"]})
print(response)

代碼執行輸出結果如下:(輸出結果中出現“所有文件處理完畢”,說明客戶端中成功調用了服務端中的日志輸出工具)

在這里插入圖片描述

現在可以成功調用工具,我們的目標是獲取客戶端發過來的日志信息,需要結合這個session中的logging_callback參數。

通過點擊加logging_callback參數j,進入技術文檔,可以發現,這參數需要制定一個回調函數。

在這里插入圖片描述

進一步,點擊一個回調函數,查看具體說明,主要查看這個函數需要傳入的參數類別,如下

在這里插入圖片描述

因此,在client.py中定一個回調函數,命名為logging_handle,然后這個函數指定的對應就是上面紅框中的數據對象,然后再把這個回調函數賦值給logging_callback參數,如下

from mcp.types import LoggingMessageNotificationParamsasync def logging_handle(params: LoggingMessageNotificationParams):print(params)async def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream,write_stream,logging_callback=logging_handle) as session:await session.initialize()....

執行代碼,輸出結果如下:(此時,我們就可以成功將服務端的信息在客戶端打印出來了,即獲取到客戶端的日志信息)

在這里插入圖片描述

由此,就可以根據自己的需求完成一些日志方面的操作,比如將日志信息保存本地,進行日志操作之間的交互(增加用戶體驗)等。

2.2.2 客戶端全部代碼

給出client.py文件的全部代碼,方便學習理解

import asyncio
from mcp.client.sse import sse_client
from mcp import ClientSession
from mcp.types import LoggingMessageNotificationParamsasync def logging_handle(params: LoggingMessageNotificationParams):print(params)async def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream,write_stream,logging_callback=logging_handle) as session:await session.initialize()# 獲取所有工具tools = (await session.list_tools()).tools# print(tools)tool = tools[0]response = await session.call_tool(name=tool.name,arguments={"files":["a.txt","b.txt"]})print(response)if __name__ == "__main__":asyncio.run(run())

3. 進度匯報

當服務端的代碼在處理一些耗時操作時,可以向客戶端實時反饋執行的進度。可以通過report_process()函數進行設置

3.1 服務端

在Load_report文件夾下的server.py文件中,輸入代碼如下

import asyncio
from mcp.server.fastmcp import FastMCP,Context
from mcp.types import RequestParamsmcp: FastMCP = FastMCP()@mcp.tool()
async def load_task(files:list[str],ctx: Context):'''處理多個文件進行進度匯報:param files: 多個文件路徑:param ctx: 上下文對象,無需客戶端傳遞:return: 處理結果'''for index,file in enumerate(files):await asyncio.sleep(1)ctx.request_context.meta = RequestParams.Meta(progressToken=ctx.request_id)await ctx.report_progress(index,len(files))return "處理完畢"if __name__ == '__main__':mcp.run(transport="sse")

代碼中,關于調用ctx.report_progress()函數前,需要添加一行代碼ctx.request_context.meta = RequestParams.Meta(),具體原因可以通過查看ctx.report_progress()函數技術文檔,如下(這個函數中有一個progress_token參數,如果這個參數的賦值為None,這調用函數直接返回為空,相當于函數不會發送信息。而要求函數發送信息,則要求progress_token參數不為None,進一步找到前面的request_context.meta參數,這個值不能為None,然后就返回request_context.meta.progressToken對象)

在這里插入圖片描述

進一步點擊request_context.meta.progressToken,查看它的技術文檔,可以發現這個參數下還是一個函數嵌套。

在這里插入圖片描述

進一步點擊函數,進入下一次技術文檔,如下(可知這個進度的Token需要指定一個字符串或者整形的數據,避免None值出現)

在這里插入圖片描述

因此,為了在執行ctx.report_progress()函數前,添加一行代碼ctx.request_context.meta = RequestParams.Meta(),而且里面的這個參數設置需要時唯一的,這里采用的就是每一個請求的id。 做開發項目,最有趣的過程就是在進行探索的過程,這個過程自己過一遍后,收獲感會很充實。

3.2 客戶端

3.2.1 客戶端代碼調試

在Load_report文件夾下的client.py文件中,與前面的日志輸出類似,這里也有一個message_handler參數進行回調。同樣,進入該參數的技術文檔,查看詳細說明,如下

在這里插入圖片描述

進一步點擊進去,查看詳細說明,如下(該函數回調只有一個參數,就是message,可接受三種數據類型)

在這里插入圖片描述

因此在定義回調函數時候,指定傳入的參數類型設置,可以直接把技術文檔中的說明復制過來,如下


from mcp.types import LoggingMessageNotificationParams,ServerNotification,ClientResult,ServerRequest
from mcp.client.session import RequestResponder
async def message_handler(message: RequestResponder[ServerRequest, ClientResult]| ServerNotification| Exception):print("*"*30)print(message)print("*" * 30)async def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream,write_stream,logging_callback=logging_handle,message_handler=message_handler  #這個參數設置) as session:await session.initialize()

執行代碼輸出結果如下:(可以輸出加載信息)

在這里插入圖片描述

3.2.2 客戶端全部代碼

import asyncio
from mcp.client.sse import sse_client
from mcp import ClientSession
from mcp.types import LoggingMessageNotificationParams,ServerNotification,ClientResult,ServerRequest
from mcp.client.session import RequestResponderasync def message_handler(message: RequestResponder[ServerRequest, ClientResult]| ServerNotification| Exception):print("*"*30)print(message)print("*" * 30)async def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream,write_stream,logging_callback=logging_handle,message_handler=message_handler) as session:await session.initialize()# 獲取所有工具tools = (await session.list_tools()).tools# print(tools)tool = tools[0]response = await session.call_tool(name=tool.name,arguments={"files":["a.txt","b.txt"]})print(response)if __name__ == "__main__":asyncio.run(run())

4. 模型調用

有時候服務端可能需要調用大模型的能力,那么可以使用MCP提供的sampling功能來實現。(注意是服務端調用大模型能力,之前項目都是客戶端調用大模型來執行服務端中的Tool)

4.1 服務端

在Mdel_call文件夾下的server.py文件中,具體實現就是調用Context對象下面的session.create_message()函數

"""import asyncio
from mcp.server.fastmcp import FastMCP,Context
from mcp.types import SamplingMessage, TextContentmcp: FastMCP = FastMCP()@mcp.tool()
async def sampling_tool(ctx:Context):# 直接發送一個Sampling的消息response = await ctx.session.create_message(max_token=2048,messages=[SamplingMessage(role="user",content=TextContent(type="text",text="請幫我按照主題“2025年高考”為主題寫兩篇詩詞"))])print(response)return "采樣成功"if __name__ == '__main__':mcp.run(transport="sse")

關于函數中具體參數的配置,也可以參考本博客中前2個案例,都是通過技術文檔中的說明,逐步進行完善,然后填寫完整,這個過程不是要背具體的方式,而是要學會具體的方法。比如這里對于大模型能力的應用,知道借助上下文Context對象下面的session.create_message()函數創建就可以了,然后就是具體的參數設置直接借助說明文檔快速完成。

4.2 客戶端

4.2.1 客戶端代碼調試

在Mdel_call文件夾下的client.py文件中,客服端中對應的就是sampling_callback參數完成

點擊該參數,進入技術文檔,如下

在這里插入圖片描述

然后進入下一級的技術文檔,如下(此時就出現了具體的參數和數據類型了)

在這里插入圖片描述

在客戶端,新定一個函數為sampling_handler(),然后把上圖中的下面介紹兩個參數及對應的數據類型的代碼全部復制到創建的函數中。還需要注意,技術文檔中回調函數需要返回CreateMessageResult數據類型。我們可以先手動創建一個類數據對象,如下

from mcp.types import CreateMessageRequestParams, TextContent, CreateMessageResult
from mcp.client.session import RequestContext
async def sampling_handler(context: RequestContext["ClientSession", Any],params: CreateMessageRequestParams,):print(f"context: {context}")print(f"params: {params}")return CreateMessageResult(role= "assistant",  # 大模型返回的信息,此時的角色對應的是assistantcontent=TextContent(type="text", text="手動輸出的結果"),model="deepseek-chat")

將回調函數復制給對應的參數后,執行客戶端代碼,結果輸出如下(檢查客戶端輸出沒有報錯,然后服務端出現自己手動創建的CreateMessageResult數據,即證明代碼可以跑通)

客戶端:
在這里插入圖片描述

服務端:

在這里插入圖片描述

那么接下來,就是換用加入大模型,讓其進行返回結果到服務端,如下(關于message變量的賦值,可以參考上圖客戶端輸出結果進行獲取,由此而進一步獲得對應的rolecontent內容)

async def sampling_handler(context: RequestContext["ClientSession", Any],params: CreateMessageRequestParams,):print(f"context: {context}")print(f"params: {params}")deepseek = OpenAI(api_key="sk-5d307e0xxxxx5a6ce4575ff9",base_url="https://api.deepseek.com",)message = params.messages[0]   messages = [{"role": message.role,"content": message.content.text}]response = deepseek.chat.completions.create(messages=messages,model="deepseek-chat")print(response)return CreateMessageResult(role= "assistant",content=TextContent(type="text", text="手動輸出的結果"),model="deepseek-chat")

這里執行代碼,輸出如下(此時,只是測試代碼是否正常運行,輸出的結果是在客戶端的輸出窗口)

在這里插入圖片描述

最后,就是把return中返回的結果使用response變量中的數據進行替換(根據上圖的輸出結果,逐步進行獲取里面content內容),即可,代碼如下

print(response)
text = response.choices[0].message.content
return CreateMessageResult(role= "assistant",content=TextContent(type="text", text=text),model="deepseek-chat"

重新執行客戶端的代碼,輸出結果如下
在這里插入圖片描述

當客戶端的代碼運行完畢后,此時,點擊服務端的輸出窗口,檢查是否可以獲取到客戶端調用大模型輸出的結果,如下(完美獲取想要的結果)

在這里插入圖片描述

4.2.2 客戶端全部代碼

在強調一遍,這個項目是服務端獲取客戶端調用大模型返回的結果,這里是功能實現,具體后續的擴展開發就任憑需求了。

"""
-------------------------------------------------------------------------------
@Project : MCP projects
File    : client.py
Time    : 2025-06-05 17:20
author  : musen
Email   : xianl828@163.com
-------------------------------------------------------------------------------
"""import asyncio
from typing import Any
from mcp.client.sse import sse_client
from mcp import ClientSession
from mcp.types import CreateMessageRequestParams, TextContent, CreateMessageResult
from mcp.client.session import RequestContext
from openai import OpenAIasync def sampling_handler(context: RequestContext["ClientSession", Any],params: CreateMessageRequestParams,):print(f"context: {context}")print(f"params: {params}")deepseek = OpenAI(api_key="sk-5d307e0a45xxxxx4575ff9",base_url="https://api.deepseek.com",)message = params.messages[0]messages = [{"role": message.role,"content": message.content.text}]response = deepseek.chat.completions.create(messages=messages,model="deepseek-chat")print(response)text = response.choices[0].message.contentreturn CreateMessageResult(role= "assistant",content=TextContent(type="text", text=text),model="deepseek-chat")async def run():async with sse_client("http://127.0.0.1:8000/sse") as (read_stream, write_stream):async with ClientSession(read_stream,write_stream,sampling_callback=sampling_handler) as session:await session.initialize()# 獲取所有工具tools = (await session.list_tools()).tools# print(tools)tool = tools[0]response = await session.call_tool(name=tool.name)  #服務端的tool中函數沒有參數arguments,這里就不需要指定print(response)if __name__ == "__main__":asyncio.run(run())

至此,關于 MCP中的Context的日志輸出、進度匯報和服務端調用客戶端的大模型輸出結果的三個項目的實戰詳細梳理就完結了,撒花??ヽ(°▽°)ノ?。

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

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

相關文章

QT自定義資源管理器

使用qt 和 C實現。還在優化中 項目地址:GitHub - Linda1226/FileResourceManager: 自定義資源管理器 有問題可以交流

[華為eNSP] OSPF綜合實驗

目錄 配置流程 畫出拓撲圖、標注重要接口IP 配置客戶端IP 配置服務端IP 配置服務器服務 配置路由器基本信息:名稱和接口IP 配置路由器ospf協議 測試結果 通過配置OSPF路由協議,實現跨多路由器的網絡互通,并驗證終端設備的訪問能力。 …

如何把本地服務器變成公網服務器?內網ip網址轉換到外網連接訪問

? 內網IP只能在本地內部網絡連接訪問,當本地搭建服務器部署好相關網站或應用后,在局域網內可以通過內網IP訪問,但在外網是無法直接訪問異地內網IP端口應用的,只有公網IP和域名才能實現互聯網上的訪問。那么需要如何把本地服務器變…

Linux-文件管理及歸檔壓縮

1.根下的目錄作用說明: /:Linux系統中所有的文件都在根下/bin:(二進制命令目錄)存放常用的用戶命令/boot:系統啟動時的引導文件(內核的引導配置文件,grub配置文件,內核配置文件) 例…

從零開始的python學習(七)P95+P96+P97+P98+P99+P100+P101

本文章記錄觀看B站python教程學習筆記和實踐感悟,視頻鏈接:【花了2萬多買的Python教程全套,現在分享給大家,入門到精通(Python全棧開發教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

Linux 查找特定字符詳細講解

CentOS 7 中使用 grep 查找特定字符詳細筆記? 一、grep 命令概述? grep 全稱為 Global Regular Expression Print,即全局正則表達式打印,是 CentOS 7 系統中用于文本搜索的核心工具。它基于正則表達式或固定字符串,在文件、標準輸入流中進…

uniappx插件nutpi-idcard 開發與使用指南(適配鴻蒙)

uniappx插件nutpi-idcard 開發與使用指南(適配鴻蒙) 前言 nutpi-idcard 是一個基于 UTS (uni-app TypeScript Syntax) 開發的 uni-app 插件適配鴻蒙,主要用于解析身份證號碼,提取其中的關鍵信息,如地區、出生日期、性…

Grafana-ECharts應用講解(玫瑰圖示例)

工具: MySQL 數據庫 MySQL Workbench 數據庫管理工具(方便編輯數據) Grafana v11.5.2 Business Charts 6.6(原 Echarts插件) 安裝 安裝 MySQL社區版安裝 MySQL Workbench安裝 Grafana在 Grafana 插件中搜索 Business Charts 進行安裝以上安裝步驟網上教程很多,自行搜…

React狀態管理Context API + useReducer

在 React 中,Context API useReducer 是一種輕量級的狀態管理方案,適合中小型應用或需要跨組件共享復雜狀態的場景。它避免了 Redux 的繁瑣配置,同時提供了清晰的狀態更新邏輯。 1. 基本使用步驟 (1) 定義 Reducer 類似于 Redux 的 reduce…

3 個優質的終端 GitHub 開源工具

1、Oh My Zsh Oh My Zsh 是一個幫助你管理和美化 zsh 終端的開源工具。它讓你的終端更炫酷、更高效。安裝后,你可以快速使用各種插件和主題,比如常見的 git 命令簡化、支持多種編程語言工具等,每次打開終端都會有驚喜。無論你是開發者還是普…

無人機巡檢智能邊緣計算終端技術方案??——基于EFISH-SCB-RK3588工控機/SAIL-RK3588核心板的國產化替代方案?

一、方案核心價值? ?實時AI處理?:6TOPS NPU實現無人機影像的實時缺陷檢測(延遲<50ms)?全國產化?:芯片、操作系統、算法工具鏈100%自主可控?極端環境適配?:-40℃~85℃穩定運行,IP65防護等…

SpringAI 1.0.0 正式版——利用Redis存儲會話(ChatMemory)

官方文檔:Chat Memory :: Spring AI Reference 1. 引言 SpringAI 1.0.0 改動了很多地方,本文根據官方的InMemoryChatMemoryRepository實現了自定義的RedisChatMemoryRepository,并使用MessageWindowChatMemory創建ChatMemory 2. 實現 2.1.…

RFC8489-STUN

0. 學習參考 RFC5389 中文翻譯 中文RFC RFC文檔 RFC翻譯 RFC中文版 RFC 5389:NAT 的會話遍歷實用程序 (STUN) --- RFC 5389: Session Traversal Utilities for NAT (STUN) 1. RFC 3489的演變 自 RFC 3489 發布以來的經驗發現,…

開始在本地部署自己的 Gitea 服務器

0.簡介 在軟件開發和團隊協作中,代碼管理是至關重要的環節。筆者一直使用gitblit管理自己的倉庫。然鵝,這個軟件已經很久沒有更新了。經過多方考察,發現Gitea 是一款輕量級的開源代碼托管平臺,具有易于部署、資源占用少、功能豐富…

Xsens-AAA工作室品質,為動畫師準備

每一幀都講述著一個故事,當動作真實呈現時,故事便鮮活起來。我們打造并改進了 Xsens Animate,助力專業人士突破數字動畫的界限。 通過升級后的 Xsens Animate,您可以獲得女性和男性解剖模型以及更精確的運動引擎,從一…

嵌入(Embedding)技術的實現原理與應用場景解析

嵌入(Embedding)技術的實現原理與應用場景解析 引言:從One-Hot到語義空間 在自然語言處理的演進歷程中,嵌入技術(Embedding)的誕生標志著一個重要轉折點——它讓離散的符號表示突破了維度詛咒&#xff0c…

金倉數據庫征文-金倉KES數據同步優化實踐:邏輯解碼與增量同步

目錄 一.同步場景與方案選型 二.什么是KES 三.同步環境配置 1.前置條件驗證 2.邏輯解碼配置 四.同步實施與問題排查 1.結構映射規則 2.增量數據捕獲 3.數據一致性校驗 五.性能調優實踐 1.同步線程優化 2.批量提交優化 3.資源監控指標 六.典型場景解決方案 1.雙向…

開源語義分割工具箱mmsegmentation基于Lovedata數據集訓練模型

開源語義分割工具箱mmsegmentation安裝環境 文章目錄 1、下載數據集2、整理數據集3、下載預訓練模型4、測試5、訓練模型參考官方數據處理步驟 https://github.com/open-mmlab/mmsegmentation/blob/main/docs/zh_cn/user_guides/2_dataset_prepare.md#loveda 數據集類別標簽:…

Python概率統計可視化——概率分布、假設檢驗與分子運動模型

Python概率統計可視化——概率分布、假設檢驗與分子運動模型 前言 概率統計作為描述不確定性和隨機現象的數學工具,廣泛應用于物理學、生物學、經濟學等領域。然而,抽象的概率分布和統計推斷過程往往難以直觀理解。可視化技術通過將概率密度、假設檢驗邏…

NLP學習路線圖(二十二): 循環神經網絡(RNN)

在自然語言處理(NLP)的廣闊天地中,序列數據是絕對的核心——無論是流淌的文本、連續的語音還是跳躍的時間序列,都蘊含著前后緊密關聯的信息。傳統神經網絡如同面對一幅打散的拼圖,無法理解詞語間的順序關系&#xff0c…