ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用 Python 写一个 MCP 客户端:三十行代码连接 invisible_playwright_mcp 并调用浏览器工具

用 Python 写一个 MCP 客户端:三十行代码连接 invisible_playwright_mcp 并调用浏览器工具 人工智能AI Agent浏览器控制GUI 自动化MCP 服务【免费下载链接】invisible_playwright_mcpPlaywright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.项目地址https://gitcode.com/GitHub_Trending/jo/invisible_playwright_mcp点击查看免费下载MCPModel Context Protocol多数人是从使用端认识的Claude Code、编辑器、聊天应用里的那个配置块。本文用三十行 Python 证明另一件事——客户端只是一个与服务器用 JSON-RPC 对话、并决定如何处理应答的进程它不一定要包含任何模型。读完本文你将能自己写一个无模型的 MCP 客户端用它验证 invisible_playwright_mcp 的 stdio 服务器是否工作、测量服务器每轮转发的工具成本并理解握手版本号背后的一个经典陷阱。MCP 客户端到底是什么官方文档把 MCP 讲得很复杂但拆到协议层面只有一句话客户端是发起连接、列举服务器能力、并调用这些能力的一方。这句话里没有模型二字你的客户端里也不需要有一个模型——这正是它最有价值的用途一个没有模型的客户端是检验一台 MCP 服务器是否真正工作的最快途径。当编辑器里工具列表为空、Agent 报错工具不存在时先用它把服务器单独拉起来问一遍问题归属立刻清楚。在 invisible_playwright_mcp 这个项目里客户端通过 stdio 启动python -m invisible_playwright_mcp入口在 src/invisible_playwright_mcp/main.py转发给 src/invisible_playwright_mcp/cli.py服务器以名为stealth的 FastMCP 实例暴露两个反检测浏览器main与support的全部操作见 src/invisible_playwright_mcp/mcp/server.py。完整代码三十行的客户端import asyncio import os import sys from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): params StdioServerParameters( commandsys.executable, args[-m, invisible_playwright_mcp], env{**os.environ, PYTHONPATH: src}, ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: init await session.initialize() print(server:, init.serverInfo.name, init.serverInfo.version) tools (await session.list_tools()).tools print(tools:, len(tools)) for t in tools[:3]: print( , t.name) out await session.call_tool(browser_list, {}) print(browser_list -, out.content[0].text[:200]) asyncio.run(main())针对本项目服务器运行文档记录的实测输出运行于 2026-09-14打印结果如下server: stealth 0.54.0 tools: 16 browser_open browser_close browser_list browser_list - {focus: , browsers: [], note: the main browser is not open. Call browser_open to open it.}注意最后一行的措辞它把本项目的open-first 规则必须先调用browser_open完整地装进了一条应答里——一个刚启动的服务器还没有持有任何浏览器所以browser_list无浏览器可列、也没有人正在其中工作。先调用browser_open再问一次。这条规则的定义位于 src/invisible_playwright_mcp/mcp/init.py常量NOT_OPEN而work.py是它的执行者除browser_open外没有任何工具会启动浏览器一个浏览器未打开的工具会以这句话作答而不是静默工作。这段代码只有四个关键点逐一拆解。stdio_client负责启动服务器你连接的不是一个已经在运行的进程。StdioServerParameters给出的是一整条命令行SDK 负责把它 spawn 成子进程、把子进程的 stdin/stdout 管道交到你的(read, write)句柄上并在async with块退出时杀掉它。这就是 stdio 服务器易于开发的原因也是桌面客户端粘贴一个配置块时的同一套机制。对从源码 checkout 运行的情况env{**os.environ, PYTHONPATH: src}保证子进程解析到本仓库自己的src/。这一点项目的测试基础设施专门处理过子进程有自己独立的sys.path而pyproject.toml里的pythonpath [src]只影响 pytest 进程本身、到不了子进程见 tests/mcp_server/_stdio_helpers.py 中把本仓库src/前置到PYTHONPATH的实现。initialize是一次握手不是走过场在握手完成之前协议不允许任何其他调用。握手的应答里你能读到协议版本以及服务器声明自己能做什么。SDK 版本要求本项目声明在 pyproject.tomlmcp1.8,2因为main()从 1.8.0 起才提供 streamable HTTP 传输。list_tools与模型宿主调用的是同一个接口返回的正是模型每轮对话都会消耗到上下文里的那份工具清单。所以客户端同时也是诚实地测量服务器成本的手段本项目在 docs/how-many-mcp-tools-is-too-many.md 里做了这个算术——16 个工具、8040 字符描述每轮约 3141 个 token其中 schema 占三分之一。call_tool收名字和 dict还你内容对于浏览器服务器返回内容可能是文本、快照或图片。这里有一个读法上的建议读文本而不是看对象形状。上面browser_list的应答是包在字符串里的 JSON这是本服务器的一个选择而非协议规则——它在 src/invisible_playwright_mcp/mcp/actions.py 的json_capped里实现原因写得很直白项目自带的界面也是这些工具的普通客户端之一没有特权路径所以有哪些浏览器开着这个问题必须用程序能读的形状来回答。当前pyproject.toml声明版本为 0.70.0工具总数为 16九个工具曾被移除、一个新增见 docs/how-many-mcp-tools-is-too-many.md。输出里的那个意外serverInfo 的版本陷阱文档记录的实测输出中有一个反直觉的事实init.serverInfo.version报告的是1.28.0——那是当时安装的mcpSDK 的版本而不是服务器包的版本两者根本不在一个编号体系上。这不是 bug但它是陷阱不要用serverInfo判断你正在与哪个版本的服务器对话除非该服务器明确设置过它。如果确实需要按服务器版本做分支应该通过一个能回答该问题的工具去问服务器本身。本项目把这个问题彻底修掉了而且修法值得读源码。在 src/invisible_playwright_mcp/mcp/server.py 中有一行带着大量注释的代码mcp._mcp_server.version __version__注释解释了原因FastMCP不接受version参数底层Server没有显式版本时就会回退到importlib.metadata.version(mcp)——于是这个包的所有构建都在握手时把自己报成 SDK 的版本号。设置这一行是补缺口而非触碰私有成员字段本就属于底层 Server 且在那里是公开的。更深一层这个项目的版本号本身经过专门设计记录在 src/invisible_playwright_mcp/_version.py普通安装版本取安装记录wheel 的 metadata 与代码出自同一次构建数字是对的可编辑安装pip install -emetadata 只写一次而代码会继续变动_version.py通过 PEP 610 的direct_url.json找到源树、读取pyproject.toml中声明的版本并追加 PEP 440 本地段editable使它永远不会被误读成已发布版本。握手层的正确性由测试锁定tests/mcp_server/test_stdio_e2e.py 中的test_the_handshake_says_which_build_this_is断言握手报告的版本等于本包的__version__、且不等于 SDK 版本还进一步区分了安装记录与源树声明两个读数——这正是那种三十行客户端三十秒就能发现、读一周文档也发现不了的问题的正式形态。这三十行代码能干什么判定问题在服务器还是在客户端。当编辑器里工具不显示时这个脚本回答唯一重要的问题服务器到底能不能工作如果在这里能列出工具、在编辑器里不行那问题出在注册配置而非服务器本身。docs/playwright-mcp-in-github-copilot.md 讲注册那一侧的事。在没有模型的情况下测试你自己的服务器。模型是个糟糕的测试夹具它会绕过坏掉的工具而不是报告它于是一句误导性的应答变成一次错误操作而不是一条失败的测试。docs/how-to-build-an-mcp-server.md 详细分析了这种失败模式。脚本化一台你未编写的服务器。没有任何规定说客户端必须交互式。只要服务器暴露了你想要的工具这段代码就是整个集成——比如放进定时任务里跑。什么时候才需要把模型加进来加模型不是换一个程序。流程不变调用list_tools把每个工具转换成你的模型提供商所期望的形状把模型选中的调用通过call_tool传过去把结果作为一条消息喂回给模型。这个循环就是全部的Agent部分。亲手写一次这个循环是看清MCP 是一种发现与传输约定、而不是智能层的最清晰方式。至于是否真的需要这个循环docs/model-context-protocol-alternatives.md 讨论了协议形状不适合你当前场景时的选择。从三十行扩展到完整接入把上面的脚本跑通后还有几条与本仓库直接相关的进阶路径。走完一次真实浏览流程。open-first 规则意味着第一个工具调用应当是browser_open无参数时带回合话此前的那个人之后才轮得到browser_navigate、browser_snapshot、browser_click等工具。服务器把完整的操作顺序写进了每轮对话都会发送的instructions里src/invisible_playwright_mcp/mcp/server.py并给出四级操作阶梯具名工具与选择器 → 坐标点击 → 截图目视 → 只读的browser_evaluate。它还声明了main与support两个浏览器的职责边界main是工作发生的地方support是不该碰主身份的场景如临时邮箱的帮手。连接远程HTTP服务器。把stdio_client换成 streamable HTTP 客户端并给出 URL 即可握手之后的一切按规范保持一致。本项目的服务器侧通过环境变量切换传输方式STEALTHFOX_MCP_TRANSPORThttp走 streamable HTTP默认监听127.0.0.1:8766STEALTHFOX_MCP_HOST/STEALTHFOX_MCP_PORT可覆盖见 src/invisible_playwright_mcp/mcp/server.py 的main()。docs/local-vs-remote-mcp-server.md 解释了除传输外的其他差异。注意工具返回值可能被截断。browser_read_text默认在 6000 字符处截断并在末尾标记切点browser_snapshot在超限时按文档顺序截断元素列表并报告omitted_elementsbrowser_list走json_capped超限时返回一个总是合法的截断信封。这些行为都在 src/invisible_playwright_mcp/mcp/actions.py 中有实现与实测说明——写客户端时把这些边界当作文档的一部分读。常见问题速答什么是 MCP 客户端连接服务器、列举其能力并调用的一方。你的编辑器是一个三十行脚本也是一个。写客户端需要 LLM 吗不需要把模型拿掉正是它适合测试的原因。MCP 客户端与 MCP 服务器有什么区别客户端发起连接并调用工具服务器提供工具在 stdio 场景下客户端还负责启动服务器进程。如何改连远程 MCP 服务器把stdio_client换成 streamable HTTP 客户端并传入 URL握手之后的一切按规范完全相同。可参考上面扩展到完整接入一节中本项目的 HTTP 传输配置。为什么工具不显示运行本文的脚本。如果这里能列出工具问题在客户端的配置而不是服务器。延伸阅读docs/how-to-build-an-mcp-server.md从搭建者视角看服务器的四个关键决策docs/mcp-tools-resources-and-prompts.md工具、资源与提示词三种原语的区别docs/mcp-server.md本文脚本所连接的这台服务器本身的说明docs/how-many-mcp-tools-is-too-many.md工具数量与每轮 token 成本的算术tests/mcp_server/test_stdio_e2e.py真实拉起子进程走完整握手与工具列举的端到端测试可作为本文脚本的测试版参考。协议传输层的细节stdio 帧格式、各语言绑定语义一致性的保证以 MCP 官方规范为准ClientSession、stdio_client与StdioServerParameters的具体行为以你环境中安装的mcpPython SDK 版本为准。本文脚本对任何 MCP 服务器都适用只是把它指向了本项目的服务器——而关于serverInfo的那一段恰恰是亲手跑一次才能学到的东西。赞分享人工智能AI Agent浏览器控制GUI 自动化MCP 服务【免费下载链接】invisible_playwright_mcpPlaywright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.项目地址https://gitcode.com/GitHub_Trending/jo/invisible_playwright_mcp点击查看免费下载相关推荐NocoDB 如何接入 MCP 客户端创建 MCP Token 并调用数据工具NocoDB 如何接入 MCP 客户端创建 MCP Token 并调用数据工具 如果你的 NocoDB 实例里已经有一个 Base数据库想让 Clau数据库低代码后端前端python-sdk 客户端实战用 Client 连接并驱动任意 MCP 服务器python sdk 客户端实战用 Client 连接并驱动任意 MCP 服务器 导读 本篇文章围绕 MCP Python SDKpython sdk的顶人工智能MCP 服务MCP ClientsMCP Python SDK 快速上手用 20 行代码构建你的第一个 MCP 服务器与客户端MCP Python SDK 快速上手用 20 行代码构建你的第一个 MCP 服务器与客户端 本指南以官方 Python SDK 的入口文档为核心介绍 Mo人工智能MCP 服务MCP Clients上一篇如何用LxRunOffline高效管理WSL离线安装与迁移的终极解决方案下一篇斐讯T1盒子刷Armbian吃灰设备变身7×24小时在线的家庭服务器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表