AdsPower
AdsPower

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

By AdsPower||10 Views

本文转载自 51CTO 博客作者「大鹏AI教育」的原创文章《Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了》,原文链接:https://blog.51cto.com/u_12805695/14594573

本文仅作技术学习与自动化方案参考,版权归原作者所有,转载请以原文授权要求为准。


我是张大鹏,专注 AI 应用开发和出海电商自动化多年。

最近折腾了一个很有意思的东西:用 Flask + MCP 协议,打通 AdsPower 指纹浏览器的自动化控制

说白了,就是想做一个可视化界面,让运营人员点点鼠标,就能控制浏览器去执行各种自动化操作——登录账号、发帖子、抓数据、填写表单……

为什么非要用 Flask?而不是直接用 Python 脚本或者 RPA 工具?

因为我们的核心系统是金加兔——一个基于 Flask 的运营管理系统。所有的浏览器操作最终都要集成到这个系统里,成为一个完整的多账号矩阵管理平台。

这篇文章,就是我把这个方案跑通的完整记录。

一、问题:为什么纯 HTTP API 不够用?

在开始之前,先说说我踩过的坑。

很多人知道 AdsPower 提供了 HTTP API,通过 curl 或者 requests 就能调用。确实,HTTP API 可以完成很多操作:

  • ✅ 创建/删除浏览器配置
  • ✅ 启动/关闭浏览器
  • ✅ 修改指纹参数
  • ✅ 获取 Cookie

但是,HTTP API 有一个致命的局限——它只能做"浏览器管理",无法做"页面自动化操作"。

什么意思?我给你对比一下:
Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

举个例子,你想让浏览器自动登录 Instagram:

  1. 用 HTTP API 打开浏览器 ✅
  2. 然后呢?HTTP API 没有提供"点击登录按钮"、"填写用户名密码"这种操作

所以,纯 HTTP API 方案,只能让你管理浏览器,但无法让浏览器帮你干活。


二、方案设计:Flask + MCP 架构

怎么解决这个问题?答案是 MCP 协议

MCP(Model Context Protocol)是 Anthropic 提出的 AI 工具调用标准协议。它不仅仅是一个协议,它背后有一套完整的生态——包括各种工具的 MCP Server 实现。

AdsPower 官方恰好提供了 MCP Server,支持通过 CDP(Chrome DevTools Protocol)控制浏览器。

所以,完整的架构是这样的:

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

┌─────────────────────────────────────────────────────────────────┐
│                        金加兔 (前端)                             │
│              HTML + JavaScript (Bootstrap)                      │
│                                                                 │
│   用户点击「打开Instagram」→ JavaScript fetch()                  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Flask 应用层                                │
│                                                                 │
│   @app.route("/api/browser/open")                               │
│       │                                                          │
│       ▼                                                          │
│   mcp_client.py (MCP Python SDK)                               │
│       │                                                          │
│       ▼                                                          │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  MCP Client (stdio) ────→ MCP Server (npx)              │   │
│   │         ↑                        ↓                       │   │
│   │         └────────────────────────┘                      │   │
│   │                    ↕ JSON-RPC                            │   │
│   └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                  AdsPower MCP Server                            │
│           local-api-mcp-typescript (Node.js)                    │
│                                                                 │
│   42 个工具:open-browser, navigate, click-element,              │
│   fill-input, screenshot, wait-for-selector...                  │
│                                                                 │
│   CDP WebSocket ──→ AdsPower Browser (带指纹的 Chrome)          │
└─────────────────────────────────────────────────────────────────┘

这套方案的关键点:

  1. Flask 负责接收前端请求,把操作指令转发给 MCP Client
  2. MCP Client 通过 stdio 与 MCP Server 通信,调用各种浏览器工具
  3. MCP Server 通过 CDP 控制 AdsPower 浏览器,完成实际页面操作


三、核心实现:代码怎么写?

下面进入实战环节。我会分成几个关键模块来讲:

3.1 安装依赖

# 安装 MCP Python SDK
uv add mcp

# 确保 npx 可用(用于运行 MCP Server)
# Windows 用户确认 Node.js 已安装


3.2 MCP 客户端封装

首先,我们封装一个 MCP 客户端,负责与 AdsPower MCP Server 通信:

# application/mcp_client.py
"""
AdsPower MCP 客户端封装
"""

import subprocess
from typing import Optional
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


class AdsPowerMCPClient:
    """AdsPower MCP 客户端"""
    
    def __init__(self, api_key: str, port: int = 50325):
        self.api_key = api_key
        self.port = port
        self.session: Optional[ClientSession] = None
        self._connected = False
    
    async def connect(self):
        """连接到 AdsPower MCP Server"""
        server_params = StdioServerParameters(
            command="npx",
            args=["-y", "local-api-mcp-typescript"],
            env={
                "PORT": str(self.port),
                "API_KEY": self.api_key
            }
        )
        
        async with stdio_client(server_params) as (read, write):
            self.session = ClientSession(read, write)
            await self.session.initialize()
            self._connected = True
            print(f"✅ MCP Client 已连接 (AdsPower API)")
    
    async def call_tool(self, tool_name: str, arguments: dict) -> dict:
        """
        调用 MCP 工具
        
        Args:
            tool_name: 工具名称 (如 'open-browser')
            arguments: 参数字典
        
        Returns:
            MCP 响应结果
        """
        if not self.session:
            raise RuntimeError("MCP Client 未连接,请先调用 connect()")
        
        result = await self.session.call_tool(
            tool=tool_name,
            arguments=arguments
        )
        return result
    
    async def close(self):
        """关闭连接"""
        if self.session:
            await self.session.close()
            self._connected = False


# 全局单例
_mcp_client: Optional[AdsPowerMCPClient] = None


def get_mcp_client() -> AdsPowerMCPClient:
    """获取 MCP 客户端单例"""
    global _mcp_client
    if _mcp_client is None:
        from application import config
        _mcp_client = AdsPowerMCPClient(
            api_key=config.ADSPOWER_API_KEY,
            port=config.ADSPOWER_PORT
        )
    return _mcp_client


3.3 浏览器操作服务

然后,封装一层业务逻辑,把底层工具调用变成业务操作:

# application/ads_browser.py
"""
AdsPower 浏览器操作业务逻辑
"""

import asyncio
from typing import Optional, List
from application.mcp_client import get_mcp_client


class AdsBrowserService:
    """浏览器操作服务"""
    
    def __init__(self):
        self.mcp = get_mcp_client()
    
    async def open_browser(self, profile_id: str) -> dict:
        """
        打开浏览器
        
        Args:
            profile_id: AdsPower 配置文件 ID
        
        Returns:
            包含 ws_endpoint 等信息
        """
        return await self.mcp.call_tool(
            "open-browser",
            {"user_id": profile_id}
        )
    
    async def close_browser(self, profile_id: str) -> dict:
        """关闭浏览器"""
        return await self.mcp.call_tool(
            "close-browser",
            {"user_id": profile_id}
        )
    
    async def navigate(self, url: str) -> dict:
        """导航到 URL"""
        return await self.mcp.call_tool("navigate", {"url": url})
    
    async def click_element(self, selector: str) -> dict:
        """点击元素"""
        return await self.mcp.call_tool("click-element", {"selector": selector})
    
    async def fill_input(self, selector: str, text: str) -> dict:
        """填写输入框"""
        return await self.mcp.call_tool("fill-input", {
            "selector": selector,
            "text": text
        })
    
    async def screenshot(self) -> dict:
        """截图"""
        return await self.mcp.call_tool("screenshot", {})
    
    async def wait_for_selector(self, selector: str, timeout: int = 30000) -> dict:
        """等待元素出现"""
        return await self.mcp.call_tool("wait-for-selector", {
            "selector": selector,
            "timeout": timeout
        })
    
    async def execute_workflow(self, profile_id: str, actions: List[dict]) -> List[dict]:
        """
        执行自动化工作流
        
        Args:
            profile_id: 配置文件 ID
            actions: 操作序列,如 [
                {"type": "navigate", "url": "https://instagram.com"},
                {"type": "wait-for-selector", "selector": "input[name='username']"},
                {"type": "fill-input", "selector": "input[name='username']", "text": "myaccount"},
                {"type": "click-element", "selector": "button[type='submit']"}
            ]
        
        Returns:
            每一步的结果列表
        """
        results = []
        
        # 1. 打开浏览器
        open_result = await self.open_browser(profile_id)
        results.append({"action": "open-browser", "result": open_result})
        
        # 2. 连接自动化
        ws_url = open_result.get("data", {}).get("ws")
        if ws_url:
            await self.mcp.call_tool("connect-browser-with-ws", {"ws_url": ws_url})
        
        # 3. 执行操作序列
        for action in actions:
            action_type = action.get("type")
            action_args = {k: v for k, v in action.items() if k != "type"}
            
            result = await self.mcp.call_tool(action_type, action_args)
            results.append({"action": action_type, "result": result})
            
            await asyncio.sleep(0.5)  # 每步之间短暂等待
        
        return results


3.4 Flask API 路由

最后,暴露 REST API 给前端调用:

# application/views.py 新增路由

from flask import Blueprint, jsonify, request
import asyncio

browser_bp = Blueprint('browser', __name__, url_prefix='/api/browser')
_browser_service = None


def get_browser_service():
    global _browser_service
    if _browser_service is None:
        from application.ads_browser import AdsBrowserService
        _browser_service = AdsBrowserService()
    return _browser_service


@browser_bp.route('/open', methods=['POST'])
async def open_browser():
    """打开浏览器"""
    data = request.get_json()
    profile_id = data.get('profile_id')
    
    if not profile_id:
        return jsonify({"error": "缺少 profile_id"}), 400
    
    service = get_browser_service()
    
    try:
        if not service.mcp._connected:
            await service.mcp.connect()
        
        result = await service.open_browser(profile_id)
        return jsonify({"success": True, "data": result})
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


@browser_bp.route('/workflow', methods=['POST'])
async def execute_workflow():
    """
    执行自动化工作流
    
    POST Body:
    {
        "profile_id": "abc123",
        "actions": [
            {"type": "navigate", "url": "https://instagram.com"},
            {"type": "wait-for-selector", "selector": "input[name='username']"},
            {"type": "fill-input", "selector": "input[name='username']", "text": "myaccount"},
            {"type": "fill-input", "selector": "input[name='password']", "text": "mypassword"},
            {"type": "click-element", "selector": "button[type='submit']"}
        ]
    }
    """
    data = request.get_json()
    profile_id = data.get('profile_id')
    actions = data.get('actions', [])
    
    service = get_browser_service()
    
    try:
        if not service.mcp._connected:
            await service.mcp.connect()
        
        results = await service.execute_workflow(profile_id, actions)
        return jsonify({"success": True, "results": results})
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


@browser_bp.route('/screenshot', methods=['POST'])
async def take_screenshot():
    """截图"""
    service = get_browser_service()
    
    try:
        result = await service.screenshot()
        return jsonify({"success": True, "data": result})
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


四、可视化界面:让运营人员也能用

代码写完了,总不能让运营人员去看 JSON 吧?所以还得做一个可视化界面。

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

界面功能包括:

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

运营人员只需要:

  1. 输入 profile_id,点击"打开浏览器"
  2. 输入网址,点击"导航"
  3. 输入选择器,点击"点击"或"填写"
  4. 随时截图查看当前页面

全程可视化,无需写代码。


五、踩坑记录:这些问题你可能会遇到

坑1:MCP Server 启动失败

问题:npx -y local-api-mcp-typescript 执行半天没反应

原因:Node.js 没装或者版本不对

解决:

# 检查 Node.js 版本
node -v  # 需要 18+

# 如果没装,去 https://nodejs.org 下载安装


坑2:MCP 连接超时

问题:报错 MCP Client not connected

原因:没等连接建立完成就调用工具

解决:

# 确保先连接
if not service.mcp._connected:
    await service.mcp.connect()

# 然后再调用工具
result = await service.open_browser(profile_id)


坑3:AdsPower API Key 配置错误

问题:返回 {"code": 1002, "msg": "API Key无效"}

解决:去 AdsPower 客户端设置 → API设置 → 开启 API → 复制 Key


坑4:Windows 下 stdio 通信问题

问题:Mac/Linux 正常,Windows 报错

解决:Windows 下用 cmd /c npx 包装:

server_params = StdioServerParameters(
    command="cmd",
    args=["/c", "npx", "-y", "local-api-mcp-typescript"],
    env={...}
)


六、这套方案意味着什么?

首先,它打通了"管理"和"自动化"的任督二脉。

之前用 HTTP API,你只能管理浏览器——创建配置、启动、关闭。但现在配合 MCP,你不仅能管理,还能真正操控浏览器干活。

其次,它让 AI Agent 和人工操作有了统一的界面。

不管是 AI 自动执行还是人工操作,最终都通过同一套 MCP 工具。AI 可以调用,运营人员也可以通过可视化界面调用。

第三,它是可编程的。

工作流可以用 JSON 定义,可以存储到数据库,可以动态修改。这意味着你可以:

  • 预设多个工作流(登录发帖、采集数据、批量回复)
  • 让 AI 根据情况选择执行哪个工作流
  • 动态组合操作步骤


七、实战效果

用这个方案,我们实现了以下自动化能力:

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了


总结

这篇文章介绍了如何通过 Flask + MCP 架构,打通 AdsPower 指纹浏览器的自动化控制。

核心要点:

  • MCP 协议是连接 AI 和浏览器工具的桥梁
  • AdsPower 官方 MCP Server 提供了 42 个浏览器控制工具
  • Flask 作为 API 层,接收前端请求,调用 MCP Client
  • 可视化界面让运营人员也能轻松使用

这个方案已经应用在我们的 金加兔 多账号矩阵管理系统中,效果不错。


作者信息

👤 张大鹏,专注 AI 应用开发和出海电商自动化多年

📚 更多实战文章,欢迎关注我的 51CTO 博客

💬 有问题欢迎留言交流


参考资料

AdsPower

与AdsPower一起,开启多账号管理新篇章

Flask + MCP 协议打通 AdsPower 指纹浏览器自动化,这个方案太丝滑了

人们还读过

  • 用AI Agent控制浏览器:MCP协议让指纹浏览器成为Agent的工具用AI Agent控制浏览器:MCP协议让指纹浏览器成为Agent�%9

    用AI Agent控制浏览器:MCP协议让指纹浏览器成为Agent的工具

    本文深入解析AI Agent如何通过AdsPower指纹浏览器的MCP协议实现浏览器自动化控制以及多账号隔离与自动化操作,涵盖Selenium实战、MCP Server接入方式及真实项目应用场景,帮助你构建可规模化的AI自动化系统。

  • 用AI Agent控制指纹浏览器实现Instagram全自动注册(附源码)用AI Agent控制指纹浏览器实现Instagram全自动注册(附源码)

    用AI Agent控制指纹浏览器实现Instagram全自动注册(附源码)

    本文转载自 51CTO 博客,介绍如何结合 AI Agent、AdsPower 指纹浏览器与浏览器自动化技术,实现 Instagram 注册流程的环境隔离、状态管理与自动化控制。

  • 采集浏览器AdsPower:让大规模任务跑得更稳更快采集浏览器AdsPower:让大规模任务跑得更稳更快

    采集浏览器AdsPower:让大规模任务跑得更稳更快

    AdsPower 采集浏览器将浏览器环境抽象为可调度资源,支持大规模动态页面采集、多地区数据抓取和 AI Agent 自动调用 API,提升任务稳定性和扩展能力。

  • AI Agent 自动注册 Facebook 全流程实测:真正卡住的是这一步AI Agent 自动注册 Facebook 全流程实测:真正卡住的是这一步

    AI Agent 自动注册 Facebook 全流程实测:真正卡住的是这一步

    这次 AdsPower 做了一次自动化测试:用 AI Agent + Puppeteer,在指纹浏览器环境中完整跑了一遍 Facebook 注册流程。填写表单、邮箱验证、安全检查都可以自动完成,但最后还是卡在了视频刷脸验证。

  • AI Agent 能自己登录 Google 吗?我们用 OpenClaw + AdsPower 做了一次测试AI Agent 能自己登录 Google 吗?我们用 OpenClaw + AdsPower 做了一次测试

    AI Agent 能自己登录 Google 吗?我们用 OpenClaw + AdsPower 做了一次测试

    通过一次实际测试,演示如何在 Linux 服务器上使用 AI Agent(OpenClaw)调用 AdsPower 浏览器环境,实现自动登录 Google。文章详细介绍浏览器自动化架构、API 调用流程以及稳定运行的关键。