【原创】使用langchain与MCP 与 Chrome DevTools 打造可调用浏览器工具的 Chat Agent

本文介绍如何搭建基于Chrome开发者工具多客户端协议(MCP)的智能对话代理。通过整合chrome-devtools-mcp和LangChain框架,实现了自动注册MCP工具、支持Ollama/OpenAI双模型后端、异步非阻塞运行的Chat Agent。文章详细说明了环境配置方法,包括Chrome调试模式启动命令和Node.js环境准备,并提供了可直接运行的Python完整代码。该代理支持网页操作指令如打开网页、截图和网络请求分析等功能,通过LangGraph构建状态图实现对话流程管理。代码展示了模型绑定、工具自动发现和异步交互的实现方式,为开发者提供了开箱即用的MCP集成方案。


效果


简介 ✨

本文示例展示了一个稳定的 MCP Chat Agent:

  • 自动注册并绑定 MCP 工具(无需手动查找工具)
  • 支持Ollama / OpenAI两种模型
  • 异步运行,不会阻塞主线程

下面是使用前的准备和代码说明。


环境与准备 🔧

  1. 启动 Chrome(带远程调试端口):
    macOS
/Applications/Google\Chrome.app/Contents/MacOS/Google\Chrome --remote-debugging-port=9222--user-data-dir=/tmp/chrome-profile-stable

Linux

/usr/bin/google-chrome --remote-debugging-port=9222--user-data-dir=/tmp/chrome-profile-stable

Windows

"C:\Program Files\Google\Chrome\Application\chrome.exe"--remote-debugging-port=9222--user-data-dir="%TEMP%\chrome-profile-stable"

要安装node环境

npx -y chrome-devtools-mcp@latest --browser-url=http://127.0.0.1:9222

请确保 Chrome 已用--remote-debugging-port=9222启动,且npx -y chrome-devtools-mcp@latest能单独运行。

  1. Python 环境需要安装对应依赖(示例中使用的包有langchain_ollama,langchain_openai,langchain_mcp_adapters,langgraph等)。

完整代码(可直接保存并运行)

下面是new_chat_agent.py的完整代码:

#!/usr/bin/env python3""" 最终稳定版 MCP Chat Agent - 自动注册 MCP 工具(无需手动找) - 支持 Ollama / OpenAI 二选一 - 不会阻塞 / 不会 silent """importasynciofromtypingimportAnnotated,TypedDictfromlangchain_ollamaimportChatOllamafromlangchain_openaiimportChatOpenAIfromlangchain_mcp_adapters.clientimportMultiServerMCPClientfromlanggraph.graphimportStateGraph,STARTfromlanggraph.prebuiltimportToolNode,tools_conditionfromlanggraph.checkpoint.memoryimportMemorySaverfromlanggraph.graph.messageimportadd_messages# ================== 配置 ==================OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"OPENAI_API_BASE="https://dashscope.aliyuncs.com/compatible-mode/v1"classState(TypedDict):messages:Annotated[list,add_messages]classMCPAgent:def__init__(self,backend:str="ollama"):print("🚀 初始化 MCPAgent",flush=True)# -------- 模型选择 --------ifbackend=="ollama":self.llm=ChatOllama(model="qwen2.5:7b",temperature=0.7,)print("🔹 使用 Ollama",flush=True)else:self.llm=ChatOpenAI(model="qwen3-30b-a3b-instruct-2507",temperature=0.7,api_key=OPENAI_API_KEY,base_url=OPENAI_API_BASE,)print("🔹 使用 OpenAI API",flush=True)# -------- MCP 工具(关键)--------print("🔄 连接 chrome-devtools-mcp(不会阻塞)",flush=True)client=MultiServerMCPClient({"chrome":{"transport":"stdio","command":"npx","args":["-y","chrome-devtools-mcp@latest","--browser-url=http://127.0.0.1:9222",],}})# ⚠️ get_tools 是唯一需要等的地方self.tools=asyncio.run(client.get_tools())ifnotself.tools:raiseRuntimeError("❌ MCP 工具为空,请确认 Chrome 是否启动")print(f"✅ 已自动注册{len(self.tools)}个 MCP 工具",flush=True)# ⭐ 核心:直接 bind_tools,不要自己管工具self.llm=self.llm.bind_tools(self.tools)# -------- LangGraph --------self.graph=self._build_graph()self.history=[]def_agent(self,state:State):return{"messages":[self.llm.invoke(state["messages"])]}def_build_graph(self):g=StateGraph(State)g.add_node("agent",self._agent)g.add_node("tools",ToolNode(self.tools))g.add_edge(START,"agent")g.add_conditional_edges("agent",tools_condition)g.add_edge("tools","agent")returng.compile(checkpointer=MemorySaver())asyncdefrun(self):print("\n🤖 MCP Chat Agent 已启动",flush=True)print("示例:",flush=True)print(" 打开 https://www.baidu.com",flush=True)print(" 截图当前页面",flush=True)print(" 列出 network 里的 JSON 请求\n",flush=True)whileTrue:user=input("你: ").strip()ifuserin("exit","quit"):breakself.history.append(("user",user))asyncforeventinself.graph.astream_events({"messages":self.history},config={"configurable":{"thread_id":"default"}},version="v2",):ifevent["event"]=="on_chat_model_stream":chunk=event["data"]["chunk"]ifchunk.content:print(chunk.content,end="",flush=True)elifevent["event"]=="on_tool_start":print(f"\n🛠️ 调用工具:{event['name']}",flush=True)elifevent["event"]=="on_tool_end":print("\n✅ 工具执行完成",flush=True)print()# ================== 启动 ==================if__name__=="__main__":try:choice=input("选择模型(1=Ollama,2=OpenAI):").strip()backend="ollama"ifchoice!="2"else"openai"agent=MCPAgent(backend=backend)asyncio.run(agent.run())exceptExceptionase:print(f"\n❌ 启动失败:{e}",flush=True)print("\n排查顺序:",flush=True)print("1. Chrome 是否用 --remote-debugging-port=9222 启动",flush=True)print("2. npx -y chrome-devtools-mcp@latest 是否能单独运行",flush=True)print("3. node / npm 是否正常",flush=True)

关键点解析 💡

  • 自动注册 MCP 工具:通过MultiServerMCPClient(...).get_tools()自动发现并注册 chrome-devtools-mcp 提供的工具集合。
  • 绑定工具到 LLM:使用self.llm.bind_tools(self.tools),让 LLM 可以直接以工具调用的方式操控浏览器。
  • LangGraph 驱动:使用StateGraphToolNode管理对话和工具调用的流程,并以MemorySaver做检查点。
  • 运行模式:交互式命令行会持续接收用户输入,并以事件流打印模型输出与工具调用状态。

使用示例 🧪

  1. 启动 Chrome(见上文命令)。
  2. 运行脚本:
python new_chat_agent.py

  1. 根据提示选择模型(1=Ollama,2=OpenAI),然后在命令行输入如:
打开 https://www.baidu.com 截图当前页面 列出 network 里的 JSON 请求

Agent 会根据工具能力返回结果并在终端打印执行过程。

参考:
https://github.com/ChromeDevTools/chrome-devtools-mcp


如果本文对你有帮助,欢迎点赞 + 关注,你的关注是我持续更新的最大动力 🙏

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

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

相关文章

22.C++进阶:⼆叉搜索树|手撕二叉搜索树

⼆叉搜索树的概念 ⼆叉搜索树⼜称⼆叉排序树,它或者是⼀棵空树,或者是具有以下性质的⼆叉树: 若它的左⼦树不为空,则左⼦树上所有结点的值都⼩于等于根结点的值若它的右⼦树不为空,则右⼦树上所有结点的值都⼤于等于根结点的值它的…

搞定JAX高效并行训练

💓 博客主页:借口的CSDN主页 ⏩ 文章专栏:《热点资讯》 搞定JAX高效并行训练:从理论到实战的深度探索目录搞定JAX高效并行训练:从理论到实战的深度探索 引言:为何JAX并行训练是AI工程的分水岭 一、JAX并行训…

Spring家族生态深度剖析:从厨房新手到餐饮帝国的演进史

文章目录一、Spring的诞生:从"厨房杂活"到"控制反转"二、Spring Boot:约定优于配置的"快餐车革命"三、Spring Cloud:从快餐车到餐饮帝国的进化四、Spring的现代化演进:响应式与云原生五、实战场景&…

写了5年C++才发现:new背后藏着两个函数,placement new让我能控制其中一个

new。 C程序员每天都在用,int* p new int(42);这行代码简单直接,分配内存、构造对象一步到位,但你有没有想过,这一行代码背后到底发生了什么? 很多人以为new是一个操作。错了。new是两个操作,第一个操作分…

8继承多态

3为什么需要继承,继承的意义是什么 ![[Pasted image 20251210212105.png]] 所以想说明什么 ![[Pasted image 20251210212458.png]] public class Dog { public String name; public int age; public void eat() { System.out.println(this.name"正在吃饭&q…

Spring Boot的约定优于配置:智能管家的“隐形”艺术

文章目录一、什么是约定优于配置?智能管家的设计哲学二、Spring Boot如何实现约定?自动配置的魔法引擎2.1 SpringBootApplication的三层秘密2.2 自动配置的执行流程:Spring Boot的“思考”过程2.3 条件化装配:智能管家的“分寸感”…

大家一直催更的Agent学习路线来喽!

大家好!这周出差了两天,稍微有点忙,所以Agent学习路线出得稍微晚了一点,希望这份学习路线能够帮助大家更好地理解和实现Agent技术,在学习和应用中有所收获 Agent的技术原理 1、技术发展路线:API->LLM-&…

Oracle 19c入门学习教程,从入门到精通,Oracle体系结构 —— 知识点详解(2)

Oracle体系结构 一、需求理解 基于Oracle 19c第2章“Oracle体系结构”的核心内容(涵盖逻辑/物理存储结构、服务器结构、数据字典等),整理一份包含Oracle安装过程、体系结构相关核心语法知识点及使用方法的教程,每个知识点配套带…

守护能源与数据的安全防线:从UL 2075标准解析储能及数据中心氢探技术的演进

守护能源与数据的安全防线:从UL 2075标准解析储能及数据中心氢探技术的演进一、UL 2075:为高风险场景设立的专业门槛UL 2075标准通过以下核心测试保障设备可靠性: $$ \text{稳定性} f(\text{温度}, \text{湿度}, \text{电压}) $$# 极端环境测…

C++类型判断

一、编译期类型判断(静态类型检查)这类判断在编译阶段完成,零运行时开销,主要用于模板编程、类型萃取等场景。1. typeid 运算符(基础)typeid 可以获取类型信息,返回 std::type_info 对象&#x…

Python 内置 venv 虚拟环境工具完全指南(附 uv 工具无缝升级教程)

Python venv 虚拟环境基础操作创建虚拟环境命令格式如下,需指定目标目录路径:python -m venv /path/to/your/env激活虚拟环境的脚本路径因操作系统而异:Windows: \path\to\env\Scripts\activateUnix/macOS: source /path/to/env/bin/activate…

2026机器视觉同轴光源品牌甄选指南:解锁高精度检测的照明密钥

在智能制造与工业自动化飞速发展的今天,机器视觉系统已成为现代工业的“智慧之眼”。而同轴光源作为这一“眼睛”的核心照明系统,其性能直接决定了视觉检测的精度与可靠性。面对2026年工业检测对精度、效率和稳定性提出的更高要求,选择一款真…

如何使用`typeid`判断指针或引用所指对象的实际类型?

核心前提:typeid判断实际类型的条件typeid能否识别指针 / 引用指向的实际类型,唯一的关键是:被判断的类是否是多态类(包含至少一个虚函数,通常是虚析构函数)。非多态类:typeid只能识别编译期的声…

C++ RAII封装结构体成员变量自动加锁性能开销分析

在C中通过RAII(Resource Acquisition Is Initialization)机制封装结构体成员变量的自动加锁/解锁操作,其性能开销需从锁机制成本、编译器优化空间、运行时场景适配三个维度进行系统性分析: 一、RAII加锁封装的核心机制 以典型实现…

凤希AI提出FXPA2P:下一代点对点AI服务架构-2026年1月14日

思考与发现在今日对产品技术细节进行打磨与升级的同时,一个更为宏观和前瞻性的构想逐渐清晰。基于对当前AI应用依赖中心化云服务所暴露的成本、效率与隐私问题的深刻洞察,我们正式提出 FXPA2P 这一商业概念与技术实施模式。FXPA2P,即 FengXi …

智能指针的生命周期控制

在C中,函数内创建的智能指针通过参数返回时,其生命周期管理遵循资源所有权转移和引用计数的智能指针语义,具体行为取决于智能指针类型(如std::unique_ptr、std::shared_ptr)和传递方式(返回值/输出参数&…

AI原生应用开发:相似度匹配的模型压缩技巧

AI原生应用开发:相似度匹配的模型压缩技巧 关键词:相似度匹配、模型压缩、AI原生应用、知识蒸馏、模型量化、参数剪枝、轻量级模型 摘要:在AI原生应用(如智能推荐、跨模态搜索、对话系统语义理解)中,相似度匹配模型是核心组件。但这类模型常因参数量大、计算复杂度高,难…

6款AI论文降重神器实操教程:AI率从72%降至13%

一、AI论文降重工具快速对比:哪款最适合你? 作为学生或科研人员,你是否曾遇到以下痛点: 用ChatGPT写的论文AI检测率高达70%,被导师打回重写?降重时逐句改写,耗时又容易破坏逻辑?找…

Python + uiautomator2 手机自动化控制教程

安装 uiautomator2 库通过 pip 安装 uiautomator2 库,确保 Python 环境已配置。pip install uiautomator2初始化设备连接使用设备的 IP 地址或序列号连接手机,确保手机已开启 USB 调试模式。import uiautomator2 as u2 d u2.connect("192.168.1.10…

Python 学生管理系统实战:从基础功能到数据持久化(附完整源码)

学生管理系统基础功能实现学生管理系统的核心功能包括添加、删除、修改和查询学生信息。使用Python内置数据结构如字典和列表可以快速实现这些基础功能。students []def add_student():name input("输入学生姓名: ")age int(input("输入学生年龄: "))st…