文章目录

  • MCP基础概念
  • 文件操作服务器
  • 文件操作MCP接入谷歌ADK
    • 项目创建
    • 多轮对话代码

MCP基础概念

  • MCP技术体系中,会将外部工具运行脚本称作服务器,而接入这些外部工具的大模型运行环境称作客户端。
    在这里插入图片描述
  • 一个客户端可以接入多个不同类型的服务器,但都要遵循MCP通信协议。
  • MCP服务器的输出内容是一种标准格式的内容,只能被MCP客户端所识别。在客户端和服务器都遵循MCP协议的时候,客户端就能够像Function calling中大模型调用外部工具一样,调用MCP服务器里面的工具。
    在这里插入图片描述
  • ADK作为客户端,接入MCP工具。核心MCPToolset类,该类是ADK连接到MCP服务器的桥梁。
  • 在实际过程中,ADK代理将执行以下操作MCPToolset
    1. 连接:与MCP服务器进程建立连接。该服务器可以是通过标准输入/输出 ( StdioServerParameters ) 进行通信的本地服务器,也可以是使用服务器发送事件 ( SseServerParams ) 的远程服务器。
    2. 发现:查询MCP服务器以获取可用工具(list_tools MCP 方法)。
    3. 适应:将MCP工具模式转换为ADK兼容BaseTool实例。
    4. 公开:将这些适配的工具呈现给ADK Agent
    5. 代理调用:当Agent决定使用其中一个工具时,发到MCP服务器并返回结果。MCPToolset将调用(call_tool MCP方法)转
    6. 管理连接:处理与MCP服务器进程的连接的生命周期,通常需要明确清理的周期(如进程结束后清理)。

文件操作服务器

  • Filesystem服务器是一个最基础同时也是最常用的MCP服务器,同时也是官方推荐的服务器,服务器项目地址。

文件操作MCP接入谷歌ADK

项目创建

  1. 项目框架搭建:
    # 初始化项目
    uv init adk_mcp
    # 进入项目目录
    cd adk_mcp
    # 创建虚拟环境
    uv venv
    # 激活虚拟环境
    .venv\Scripts\activate
    # 安装依赖
    uv add google-adk litellm
    
  2. 创建环境配置文件.env
    OPENAI_API_KEY=xxx
    OPENAI_API_BASE=https://api.openai-hk.com/v1
    MODEL=openai/gpt-4o-mini
    
  3. 创建main.py,代码内容如下:
    # 导入基础库
    import os
    import asyncio
    from dotenv import load_dotenv
    from google.genai import types
    from google.adk.agents import Agent
    from google.adk.models.lite_llm import LiteLlm
    from google.adk.agents.llm_agent import LlmAgent
    from google.adk.runners import Runner
    from google.adk.sessions import InMemorySessionService
    from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters,StdioConnectionParamsDS_API_KEY = os.getenv("OPENAI_API_KEY")
    DS_BASE_URL = os.getenv("OPENAI_API_BASE")
    DS_MODEL = os.getenv("MODEL")model = LiteLlm(model=DS_MODEL,api_base=DS_BASE_URL,api_key=DS_API_KEY
    )# --- Step 1: 创建导入MCP工具函数 ---
    async def get_tools_async():"""Gets tools from the File System MCP Server."""print("Attempting to connect to MCP Filesystem server...")# 确保目录存在test_dir = "D:\\Code\\adk_mcp\\test"if not os.path.exists(test_dir):os.makedirs(test_dir)print(f"Created directory: {test_dir}")try:# 创建MCP工具集实例mcp_toolset = MCPToolset(# 这里采用Studio通信方式进行调用connection_params=StdioConnectionParams(server_params=StdioServerParameters(command='npx',args=["-y", "@modelcontextprotocol/server-filesystem", test_dir],)))# 等待服务器启动await asyncio.sleep(2)# 获取工具列表tools = await mcp_toolset.get_tools()print("MCP Toolset created successfully.")print(f"Fetched {len(tools)} tools from MCP server.")# 返回工具和工具集对象用于清理return tools, mcp_toolsetexcept Exception as e:print(f"Error creating MCP tools: {e}")raise# --- Step 2: 创建ADK Agent --
    async def get_agent_async():"""Creates an ADK Agent equipped with tools from the MCP Server."""try:tools, mcp_toolset = await get_tools_async()root_agent = Agent(model=model,name='filesystem_assistant',instruction='Help user interact with the local filesystem using available tools.',tools=tools,  # 将MCP工具加载到Agent中)return root_agent, mcp_toolsetexcept Exception as e:print(f"Error creating agent: {e}")raise# --- Step 3: 执行主逻辑 ---
    async def async_main():mcp_toolset = Nonetry:# 创建会话管理器session_service = InMemorySessionService()session = await session_service.create_session(state={}, app_name='mcp_filesystem_app', user_id='user_fs')# 用户输入query = "请帮我查找目前文件夹里都有哪些文件?"print(f"User Query: '{query}'")content = types.Content(role='user', parts=[types.Part(text=query)])root_agent, mcp_toolset = await get_agent_async()runner = Runner(app_name='mcp_filesystem_app',agent=root_agent,session_service=session_service,)print("Running agent...")events_async = runner.run_async(session_id=session.id, user_id=session.user_id, new_message=content)async for event in events_async:print(f"Event received: {event}")except Exception as e:print(f"Error during main execution: {e}")raisefinally:# 运行完成后,关闭MCP服务器连接if mcp_toolset:print("Closing MCP server connection...")await mcp_toolset.close()print("Cleanup complete.")if __name__ == '__main__':try:asyncio.run(async_main())except Exception as e:print(f"An error occurred: {e}")
    
  • 执行结果如下:
    (adk_mcp) D:\Code\adk_mcp>uv run main.py
    D:\Code\adk_mcp\.venv\Lib\site-packages\pydantic\_internal\_fields.py:198: UserWarning: Field name "config_type" in "SequentialAgent" shadows an attribute in parent "BaseAgent"warnings.warn(
    User Query: '请帮我查找目前文件夹里都有哪些文件?'
    Attempting to connect to MCP Filesystem server...
    D:\Code\adk_mcp\.venv\Lib\site-packages\google\adk\tools\mcp_tool\mcp_tool.py:87: UserWarning: [EXPERIMENTAL] BaseAuthenticatedTool: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.super().__init__(
    auth_config or auth_config.auth_scheme is missing. Will skip authentication.Using FunctionTool instead if authentication is not required.
    MCP Toolset created successfully.
    Fetched 14 tools from MCP server.
    Running agent...
    Event received: content=Content(parts=[Part(text="""首先,我需要确定您当前的工作目录位置。由于您没有指定具体路径,我将先获取允许访问的目录列表:"""),Part(function_call=FunctionCall(args={},id='call_5201be00eeb24a989be18f',name='list_allowed_directories')),],role='model'
    ) grounding_metadata=None partial=False turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None usage_metadata=GenerateContentResponseUsageMetadata(candidates_token_count=627,prompt_token_count=1806,total_token_count=2433
    ) live_session_resumption_update=None invocation_id='e-1710d865-f562-4895-ae06-4a3f0155c138' author='filesystem_assistant' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=set() branch=None id='71634100-b10a-4a81-b779-f34f52df12eb' timestamp=1754979735.932518
    Event received: content=Content(parts=[Part(function_response=FunctionResponse(id='call_5201be00eeb24a989be18f',name='list_allowed_directories',response={'result': CallToolResult(content=[<... Max depth ...>,],isError=False)})),],role='user'
    ) grounding_metadata=None partial=None turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None usage_metadata=None live_session_resumption_update=None invocation_id='e-1710d865-f562-4895-ae06-4a3f0155c138' author='filesystem_assistant' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=None branch=None id='00b7f823-5a66-493d-95bd-55ee93466fc2' timestamp=1754979761.37467
    Event received: content=Content(parts=[Part(text="""根据系统配置,允许访问的目录是 `D:\Code\adk_mcp\test`。我将列出该目录下的文件:"""),Part(function_call=FunctionCall(args={'path': 'D:\\Code\\adk_mcp\\test'},id='call_2f66909ac2054847b6f9d3',name='list_directory')),],role='model'
    ) grounding_metadata=None partial=False turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None usage_metadata=GenerateContentResponseUsageMetadata(candidates_token_count=1105,prompt_token_count=1906,total_token_count=3011
    ) live_session_resumption_update=None invocation_id='e-1710d865-f562-4895-ae06-4a3f0155c138' author='filesystem_assistant' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=set() branch=None id='39358200-064d-478e-90f6-ab0855f13ec4' timestamp=1754979761.380695
    Event received: content=Content(parts=[Part(function_response=FunctionResponse(id='call_2f66909ac2054847b6f9d3',name='list_directory',response={'result': CallToolResult(content=[<... Max depth ...>,],isError=False)})),],role='user'
    ) grounding_metadata=None partial=None turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None usage_metadata=None live_session_resumption_update=None invocation_id='e-1710d865-f562-4895-ae06-4a3f0155c138' author='filesystem_assistant' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=None branch=None id='2d1197f7-c81d-41a5-9fc5-15652c50fa7e' timestamp=1754979803.754635
    Event received: content=Content(parts=[Part(text="""当前目录 `D:\Code\adk_mcp\test` 中的文件如下:- 📄 **系统架构设计师教程_带目录高清版.pdf**"""),],role='model'
    ) grounding_metadata=None partial=False turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None usage_metadata=GenerateContentResponseUsageMetadata(candidates_token_count=128,prompt_token_count=2021,total_token_count=2149
    ) live_session_resumption_update=None invocation_id='e-1710d865-f562-4895-ae06-4a3f0155c138' author='filesystem_assistant' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=None branch=None id='15fdd91c-e645-46fe-a613-76e1f28323c5' timestamp=1754979803.761915
    Closing MCP server connection...
    Cleanup complete.
    

多轮对话代码

  • 以下代码是main.py的多轮对话的版本:
    # 导入基础库
    import os
    import asyncio
    from dotenv import load_dotenv
    from google.genai import types
    from google.adk.agents import Agent
    from google.adk.models.lite_llm import LiteLlm
    from google.adk.agents.llm_agent import LlmAgent
    from google.adk.runners import Runner
    from google.adk.sessions import InMemorySessionService
    from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters,StdioConnectionParamsDS_API_KEY = os.getenv("OPENAI_API_KEY")
    DS_BASE_URL = os.getenv("OPENAI_API_BASE")
    DS_MODEL = os.getenv("MODEL")model = LiteLlm(model=DS_MODEL,api_base=DS_BASE_URL,api_key=DS_API_KEY
    )# --- Step 1: 创建导入MCP工具函数 ---
    async def get_tools_async():"""Gets tools from the File System MCP Server."""print("Attempting to connect to MCP Filesystem server...")# 确保目录存在test_dir = "D:\\Code\\adk_mcp\\test"if not os.path.exists(test_dir):os.makedirs(test_dir)print(f"Created directory: {test_dir}")try:# 创建MCP工具集实例mcp_toolset = MCPToolset(# 这里采用Studio通信方式进行调用connection_params=StdioConnectionParams(server_params=StdioServerParameters(command='npx',  # Command to run the serverargs=["-y",  # Arguments for the command"@modelcontextprotocol/server-filesystem",test_dir],)))# 等待服务器启动await asyncio.sleep(2)# 获取工具列表tools = await mcp_toolset.get_tools()print("MCP Toolset created successfully.")print(f"Fetched {len(tools)} tools from MCP server.")# 返回工具和工具集对象用于清理return tools, mcp_toolsetexcept Exception as e:print(f"Error creating MCP tools: {e}")raise# --- Step 2: 创建ADK Agent --
    async def get_agent_async():"""Creates an ADK Agent equipped with tools from the MCP Server."""try:tools, mcp_toolset = await get_tools_async()root_agent = Agent(model=model,name='filesystem_assistant',instruction='Help user interact with the local filesystem using available tools.',tools=tools,  # 将MCP工具加载到Agent中)return root_agent, mcp_toolsetexcept Exception as e:print(f"Error creating agent: {e}")raise# 多轮对话函数
    async def chat_loop(runner, user_id, session_id) -> None:print("\n🤖ADK + MCP对话已启动!输入'quit'退出。")while True:query = input("\n你: ").strip()if query.lower() == "quit":breaktry:print(f"\n>>> User Query: {query}")# Prepare the user's message in ADK formatcontent = types.Content(role='user', parts=[types.Part(text=query)])final_response_text = "Agent did not produce a final response."  # Default# Key Concept: run_async executes the agent logic and yields Events.# We iterate through events to find the final answer.async for event in runner.run_async(user_id=user_id,session_id=session_id, new_message=content):# You can uncomment the line below to see *all* events during execution# print(f"  [Event] Author: {event.author}, Type:{type(event).__name__}, Final: {event.is_final_response()}, Content:{event.content}")# Key Concept: is_final_response() marks the concluding message for the turn.if event.is_final_response():if event.content and event.content.parts:# Assuming text response in the first partfinal_response_text = event.content.parts[0].textelif event.actions and event.actions.escalate:  # Handle potential errors / escalationsfinal_response_text = f"Agent escalated:{event.error_message or 'No specific message.'}"# Add more checks here if needed (e.g., specific error codes)breakprint(f"<<< Agent Response: {final_response_text}")except Exception as e:print(f"\n⚠调用过程出错: {e}")# --- Step 3: 执行主逻辑 ---
    async def async_main():mcp_toolset = Nonetry:# 创建会话管理器session_service = InMemorySessionService()session = await session_service.create_session(state={}, app_name='mcp_filesystem_app', user_id='user_fs')# 用户输入query = "请帮我查找目前文件夹里都有哪些文件?"print(f"User Query: '{query}'")content = types.Content(role='user', parts=[types.Part(text=query)])root_agent, mcp_toolset = await get_agent_async()runner = Runner(app_name='mcp_filesystem_app',agent=root_agent,session_service=session_service,)print("Running agent...")events_async = runner.run_async(session_id=session.id, user_id=session.user_id, new_message=content)async for event in events_async:print(f"Event received: {event}")# 启动多轮对话await chat_loop(runner, session.user_id, session.id)except Exception as e:print(f"Error during main execution: {e}")raisefinally:# 运行完成后,关闭MCP服务器连接if mcp_toolset:print("Closing MCP server connection...")await mcp_toolset.close()print("Cleanup complete.")if __name__ == '__main__':try:asyncio.run(async_main())except Exception as e:print(f"An error occurred: {e}")
    

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

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

相关文章

高光谱技术的独特优势

高光谱技术凭借其‌纳米级连续光谱采集能力‌和‌图谱合一的探测模式‌&#xff0c;在多个领域展现出不可替代的独特优势&#xff1a;一、光谱维度&#xff1a;精细物质指纹识别‌纳米级连续光谱解析‌ 通过 ‌5-10nm带宽的数百个连续波段‌&#xff08;最高330个通道&#xff…

基于Vue+Element UI集成高德地图的完整实践指南

本次开发使用deepseek 简直如虎添翼得心应手 生成模拟数据、解决报错那真是嘎嘎地 在 Vue Element UI 项目中引入高德地图 具体实现步骤&#xff1a; 高德开放平台&#xff1a;注册账号 → 进入控制台 → 创建应用 → 获取 Web端(JS API)的Key https://lbs.amap.com/ 这里需要…

Day50--图论--98. 所有可达路径(卡码网),797. 所有可能的路径

Day50–图论–98. 所有可达路径&#xff08;卡码网&#xff09;&#xff0c;797. 所有可能的路径 刷今天的内容之前&#xff0c;要先去《代码随想录》网站&#xff0c;先看完&#xff1a;图论理论基础和深度优先搜索理论基础。做完之后可以看题解。有余力&#xff0c;把广度优先…

Python 异常捕获

一、获取未知错误try:# 相关处理逻辑 异常后面输出print(输入信息……) except Exception as e:print(未知错误,e)二、获取已知错误except 错误单词&#xff08;来源于错误信息的第一个单词&#xff09;多个已知错误使用 except XXXXX:try:# 相关处理逻辑 异常后面输出print…

RIOT、RT-Thread 和 FreeRTOS 是三种主流的实时操作系统

RIOT、RT-Thread 和 FreeRTOS 是三种主流的实时操作系统&#xff08;RTOS&#xff09;&#xff0c;专为嵌入式系统和物联网&#xff08;IoT&#xff09;设备设计。它们在架构、功能、生态和应用场景上有显著差异&#xff0c;以下是详细对比&#xff1a;1. 架构与设计理念特性RI…

【FAQ】Win11创建资源不足绕开微软账号登录

Win11安装资源限制 因为 Windows 11 有两项强制检测 VMware 8 默认没提供&#xff1a; TPM 2.0&#xff08;可信平台模块&#xff09;Secure Boot&#xff08;安全启动&#xff09; 一步到位解决办法&#xff08;官方兼容方式&#xff09; 关闭虚拟机电源编辑虚拟机设置 选项 →…

Docker使用----(安装_Windows版)

一、Docker Docker 镜像就像是一个软件包&#xff0c;里面包括了应用程序的代码、运行所需的库和工具、配置文件等等&#xff0c;所有这些都打包在一起&#xff0c;以确保应用程序在不同的计算机上运行时&#xff0c;都能保持一致性。 可以把 Docker 镜像想象成一个软件安装文件…

91、23种经典设计模式

设计模式是软件设计中反复出现的解决方案的模板&#xff0c;用于解决特定问题并提高代码的可维护性、可扩展性和可复用性。23种经典设计模式可分为创建型、结构型和行为型三大类&#xff0c;以下是具体分类及模式概述&#xff1a; 一、创建型模式&#xff08;5种&#xff09; 关…

Illustrator总监级AI魔法:一键让低清logo变矢量高清,彻底告别手动描摹!

在海外从事设计十几年&#xff0c;我敢说&#xff0c;每个设计师都经历过一种“史诗级”的折磨&#xff1a;客户发来一个像素低得感人、边缘模糊不清的JPG格式Logo&#xff0c;然后要求你把它用在巨幅海报或者高清视频上。这意味着什么&#xff1f;意味着我们要打开Illustrator…

各种 dp 刷题下

6.#8518 杰瑞征途 / 洛谷 P4072 征途 题意 Pine 开始了从 SSS 地到 TTT 地的征途。从 SSS 地到 TTT 地的路可以划分成 nnn 段&#xff0c;相邻两段路的分界点设有休息站。Pine 计划用 mmm 天到达 TTT 地。除第 mmm 天外&#xff0c;每一天晚上 Pine 都必须在休息站过夜。所以…

本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕增加利用 Whisper 分段信息,全新 Prompt功能

1. 实现功能 M4-3: 智能后处理 - 停顿感知增强版 (终极版) 本脚本是 M4-3 的重大升级&#xff0c;引入了“停顿感知”能力&#xff1a; 利用 Whisper 分段信息: 将 Whisper 的 segments 间的自然停顿作为强信号 ([P]) 提供给 LLM。全新 Prompt: 设计了专门的 Prompt&#xff0c…

微算法科技(NASDAQ:MLGO)开发经典增强量子优化算法(CBQOA):开创组合优化新时代

近年来&#xff0c;量子计算在组合优化领域的应用日益受到关注&#xff0c;各类量子优化算法层出不穷。然而&#xff0c;由于现阶段量子硬件的局限性&#xff0c;如何充分利用已有的经典计算能力来增强量子优化算法的表现&#xff0c;成为当前研究的重要方向。基于此&#xff0…

功能、延迟、部署、成本全解析:本地化音视频 SDK 对比 云端方案

引言 在构建实时音视频系统时&#xff0c;技术选型往往决定了项目的天花板。开发者面临的第一个关键抉择&#xff0c;就是是选择完全可控的本地化音视频内核&#xff0c;还是依赖云厂商的实时音视频服务。 以大牛直播SDK&#xff08;SmartMediaKit&#xff09;为代表的本地部…

微调入门:为什么微调

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录1 什么时候我们需要微调呢&#xff1f;1.1 微调的…

3、匹配一组字符

在本章里&#xff0c;你将学习如何与字符集合打交道。与可以匹配任意单个字符的.字符&#xff08;参见第2章&#xff09;不同&#xff0c;字符集合能匹配特定的字符和字符区间。3.1 匹配多个字符中的某一个第2章介绍的.​字符&#xff0c;可以匹配任意单个字符。当时在最后一个…

强化学习在量化交易中的禁区:回测表现好实盘亏钱的4个原因

引言 “为什么你的强化学习策略在回测中年化 50%,到了实盘却三个月亏光本金?” 如果你做过量化交易,尤其是尝试用强化学习(Reinforcement Learning, RL),这种场景可能并不陌生: 回测曲线平滑向上,最大回撤可控,胜率稳定 模型参数和架构调到极致,每次迭代都带来更高的…

代码随想录day62图论11

文章目录Floyd 算法精讲A * 算法精讲 &#xff08;A star算法&#xff09;Floyd 算法精讲 题目链接 文章讲解 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, m;cin >> n >> m; // 输入…

【18】OpenCV C++实战篇——【项目实战】OpenCV C++ 精准定位“十字刻度尺”中心坐标,过滤图片中的干扰,精准获取十字交点坐标

文章目录1 问题及分析2 多尺度霍夫直线 与 渐进概率霍夫线段 细节对比2.1 多尺度霍夫直线 HoughLines2.2 渐进概率霍夫线段 HoughLinesP2.3 HoughLines 和 HoughLinesP 所求结果细节对比2.4 为什么 HoughLinesP 直线两端没有呈放射状态呢&#xff1f;直线总是平行吗&#xff1f…

云原生应用的DevOps2(Jenkins渗透场景)

结论 Jenkins历史漏洞 Jenkins未授权访问 登录后命令执行 Jenkins代码仓库信息 Jenkins服务器建立多台服务器信任连接 背景 目前我看到红队人员的现状,不管是什么系统就是拿Shell,拿权限,然后把这台机器当作跳板继续横向其它机器。而Jenkins在内网中是经常能够遇到的,…

Gradle 配置教程:与 Maven 对比详解(含完整迁移指南)

一、基础对比&#xff1a;Gradle vs Maven1.1 核心特性对比维度MavenGradle配置语言XML (冗长)Groovy/Kotlin DSL (简洁灵活)构建速度较慢(全量构建)快2-10倍(增量构建缓存)多模块管理<modules> <parent>settings.gradle project()依赖管理<dependencies>d…