【原创】使用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
bash 复制代码
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable

Linux

bash 复制代码
/usr/bin/google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable

Windows

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

要安装node环境

bash 复制代码
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 的完整代码:

python 复制代码
#!/usr/bin/env python3
"""
最终稳定版 MCP Chat Agent
- 自动注册 MCP 工具(无需手动找)
- 支持 Ollama / OpenAI 二选一
- 不会阻塞 / 不会 silent
"""

import asyncio
from typing import Annotated, TypedDict

from langchain_ollama import ChatOllama
from langchain_openai import ChatOpenAI
from langchain_mcp_adapters.client import MultiServerMCPClient

from langgraph.graph import StateGraph, START
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.message import add_messages


# ================== 配置 ==================
OPENAI_API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
OPENAI_API_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"


class State(TypedDict):
    messages: Annotated[list, add_messages]


class MCPAgent:
    def __init__(self, backend: str = "ollama"):
        print("🚀 初始化 MCPAgent", flush=True)

        # -------- 模型选择 --------
        if backend == "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())

        if not self.tools:
            raise RuntimeError("❌ 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")
        return g.compile(checkpointer=MemorySaver())

    async def run(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)

        while True:
            user = input("你: ").strip()
            if user in ("exit", "quit"):
                break

            self.history.append(("user", user))

            async for event in self.graph.astream_events(
                {"messages": self.history},
                config={"configurable": {"thread_id": "default"}},
                version="v2",
            ):
                if event["event"] == "on_chat_model_stream":
                    chunk = event["data"]["chunk"]
                    if chunk.content:
                        print(chunk.content, end="", flush=True)

                elif event["event"] == "on_tool_start":
                    print(f"\n🛠️ 调用工具:{event['name']}", flush=True)

                elif event["event"] == "on_tool_end":
                    print("\n✅ 工具执行完成", flush=True)

            print()


# ================== 启动 ==================
if __name__ == "__main__":
    try:
        choice = input("选择模型(1=Ollama,2=OpenAI):").strip()
        backend = "ollama" if choice != "2" else "openai"

        agent = MCPAgent(backend=backend)
        asyncio.run(agent.run())

    except Exception as e:
        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. 运行脚本:
bash 复制代码
python new_chat_agent.py
  1. 根据提示选择模型(1=Ollama,2=OpenAI),然后在命令行输入如:

    打开 https://www.baidu.com
    截图当前页面
    列出 network 里的 JSON 请求

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

参考:

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


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

相关推荐
OpenTiny社区2 小时前
OpenTiny 2025年度贡献者榜单正式公布~
前端·javascript·vue.js
OEC小胖胖2 小时前
08|Commit 阶段:副作用如何被组织、执行与约束
前端·react.js·前端框架·react·开源库
奋斗的小青年!!2 小时前
Flutter跨平台开发OpenHarmony应用:个人中心实现
开发语言·前端·flutter·harmonyos·鸿蒙
kkce2 小时前
域名CDN检测意义
服务器·前端·网络
ZoeLandia2 小时前
Qiankun 生命周期与数据通信实战
前端·微前端·qiankun
LawrenceLan2 小时前
Flutter 零基础入门(十五):继承、多态与面向对象三大特性
开发语言·前端·flutter·dart
二川bro2 小时前
详细解析 cesiumViewer.render() 和 requestAnimationFrame(render)
前端
前端付豪2 小时前
必知Node应用性能提升及API test 接口测试
前端·react.js·node.js
王同学 学出来3 小时前
vue+nodejs项目在服务器实现docker部署
服务器·前端·vue.js·docker·node.js