MAS MCP 服务器
面向 Claude Code、Cursor、Codex 和任何 MCP 客户端的安卓 MCP 服务器
41 个工具,给你的 AI 客户端装上安卓上的眼睛和手:它能查看的截图、OCR 和模板匹配、点击、滑动和输入、宏运行,以及一个能从一句话生成宏的智能体。就用你已经在用的客户端,驱动 Windows 或 Mac 上的 BlueStacks、LDPlayer、MuMu、MEmu 或任何兼容 adb 的模拟器、插到电脑上的手机,或者全天在线的安卓云手机。
托管服务器,把你的 MAS 密钥放在请求头里;然后在应用开着时用 URL 添加本地服务器。
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp --header "X-API-Key: $MAS_API_KEY" claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp 托管服务器写在 ~/.codex/config.toml 里,密钥放在环境变量中;本地服务器用 URL 添加。
[mcp_servers.mas-cloud]
url = "https://api.automationmacro.com/mcp"
bearer_token_env_var = "MAS_API_KEY" codex mcp add mas-local --url http://127.0.0.1:3846/mcp 在 Grok 的 MCP 设置里添加一个远程 MCP 服务器,填入端点和带密钥的请求头;本地服务器是同样的条目,换成回环地址且不需要请求头。
{ "mcpServers": { "mas-cloud": { "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } } } } { "mcpServers": { "mas-local": { "url": "http://127.0.0.1:3846/mcp" } } } Hermes 使用标准的 mcpServers 结构:端点加上带密钥的请求头,本地服务器则用 URL。
{ "mcpServers": { "mas-cloud": { "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } } } } { "mcpServers": { "mas-local": { "url": "http://127.0.0.1:3846/mcp" } } } Cursor、OpenCode、Gemini CLI 以及任何接受带请求头的 HTTP 服务器的客户端。第二段代码是给 Claude Desktop 的,它会启动应用作为通往本地服务器的桥接。
{
"mcpServers": {
"mas-cloud": { "type": "http", "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } },
"mas-local": { "type": "http", "url": "http://127.0.0.1:3846/mcp" }
}
} { "mcpServers": { "mas-local": { "command": "<path to MacroAutomationStudio>", "args": ["--mcp"] } } } 它是什么
MAS 安卓 MCP 服务器做什么
MCP 是 AI 客户端调用外部工具的协议。这个服务器把一台安卓设备变成这些工具。你的客户端请求截图,得到一张它能查看的图片;询问屏幕上写了什么,得到带置信度和边框的 OCR 行;发送一张模板,得到它的位置;点击、滑动、输入和按键;打开和关闭应用。这是每个安卓 MCP 服务器都会做的部分,在模拟器、插上数据线的手机或云手机上的工作方式完全相同。
MAS 服务器还做设备服务器做不到的部分。它读取并运行你库里的宏,让 MAS Agent 探索一个应用并交回一个做好的 Python 宏,还暴露智能体学到的应用地图,以及作为 MCP 资源提供的完整 SDK 参考,让你的客户端能按规范写宏代码。这使它在设备层是一个安卓自动化 MCP 服务器,在其上的各层(宏、智能体、地图)是一个移动自动化 MCP 服务器。它不是 Android Studio 插件,也不是编程助手。它驱动设备。
托管服务器
全部 41 个工具,在你的云手机上
一个远程 HTTP 端点。租用云手机、驱动它、在服务器端运行宏、用智能体生成新宏、读取应用地图。什么都不用安装,你的电脑可以关机。
本地服务器,就在应用里
38 个工具,在你的电脑上
桌面应用本身就是服务器。在“集成(MCP)”里把它打开,把客户端指向那个回环地址即可。它驱动 adb 能看到的任何东西:Windows 或 macOS 上的 BlueStacks、LDPlayer、MuMu、MEmu,或者开启了 USB 调试的手机;它还把你的宏库、图片库、智能体生成、开发循环和定时任务一并带上。
模拟器
控制安卓模拟器:Windows 或 Mac 上的 BlueStacks、LDPlayer、MuMu、MEmu
本地服务器是一个面向你桌上已有模拟器的安卓模拟器 MCP 服务器。在应用的“集成(MCP)”里把它打开,把客户端指向 http://127.0.0.1:3846/mcp。每个设备工具都接受一个 device 参数,可以是 list_devices 给出的 id、adb 序列号,或者只写端口号;只运行着一台模拟器时可以省略它。应用自带 adb,所以这就是大多数人在找的 MCP 安卓模拟器配置:一个开关、一个 URL,搞定。
- BlueStacks
- LDPlayer
- MuMu
- MEmu
- Windows
- macOS
游戏是让基于无障碍树的服务器失效的场景:没有树可读。两个服务器都基于像素工作,所以模型可以像操作设置界面一样通关一个游戏界面。
云手机
安卓云手机,什么都不用安装
托管服务器连接的是 MAS 为你运行的全天在线设备。lease_device 打开一个控制会话,返回每个设备工具都需要的租约 id;设置 auto_start,它会先启动已停止的设备。租约在每次调用时续期,闲置 10 分钟后过期,所以被遗忘的客户端不可能永远占着设备。run_macro 在设备上服务器端执行,author_macro 让 MAS Agent 在上面工作,两者都可以在你电脑关机时进行。
设备工具不按调用收费;它们作用于你账户拥有的云手机,每台 $80/月,含月度积分额度。查看云手机。
你自己的手机
给你桌上那部手机的安卓 ADB MCP 服务器
开启 USB 调试,插上手机,本地服务器就会把它和你的模拟器列在一起。每个屏幕、输入和视觉工具都能在它上面用:模型可以通过 MCP 控制安卓手机,就像控制模拟器一样,用你已经在用的客户端,手机上什么都不用装。
视觉
模型能看到的截图、OCR 和模板匹配
screenshot把屏幕作为图片内容返回,所以模型直接查看它,而不是从一棵树里猜。本地服务器默认把长边缩放到 1280 px 并报告缩放比例。read_text对整个屏幕或一个区域运行 OCR,返回每一行以及置信度和边框,所以“点击‘领取’这个词”是一个坐标,而不是一个希望。find_image用 OpenCV 匹配你发送的模板,阈值由你控制,返回得分和要点击的中心点。
工具
全部 41 个工具
每个工具的名称及其参数。“本地和托管”工具在两个界面上都存在;少数不是两边都有的,会标出它属于哪一边。
Device control
Pick a device and drive it: the same taps, swipes and keys a person would use.
- Call this first. What the server is, whether the account can run anything (subscription, AI credits), the devices it can reach, and hints, including that local emulators are only reachable through the desktop app's local server. The same body as the mas://status resource; needs no scope.
get_status本地和托管 - List the devices the server can reach, with their state. On the hosted server that is your cloud devices and quota; on the local server, the emulators the app sees over adb (id, serial, port, whether a macro is using one).
list_devices本地和托管 - Open a control session on one of your cloud devices and get the lease_id every device tool needs. auto_start boots a stopped device first. A lease renews on every call and expires after ten idle minutes; one lease per device, and a device that is running a macro cannot be leased.
lease_device(device_id, auto_start) 托管 - End the control session. The device keeps running.
release_device(lease_id) 托管 - Tap the screen at device coordinates.
tap(x, y) 本地和托管 - Swipe between two points for scrolling and flicks, with a chosen duration (default 300 ms).
swipe(x1, y1, x2, y2, duration_ms) 本地和托管 - Press and hold at a point for duration_ms (default 800, 100 to 5000): context menus, drag handles, app icons.
long_press(x, y, duration_ms) 本地和托管 - Touch down, move to a second point over duration_ms (default 600, 100 to 5000) and release: slow enough for sliders and drag-and-drop, unlike a flick swipe.
drag(x1, y1, x2, y2, duration_ms) 本地和托管 - Type text into the focused input field.
type_text(text) 本地和托管 - Press BACK, HOME, ENTER, TAB, DEL or any KEYCODE_ name.
press_key(key) 本地和托管 - Launch an app by package name.
open_app(package) 本地和托管 - Force-stop an app by package name.
close_app(package) 本地和托管 - Report the package in the foreground.
current_app本地和托管 - Return the screen size in pixels, the coordinate space for tap and swipe.
screen_size本地和托管 - Pause for animations and loading screens: up to 10 seconds per call on the hosted server, up to 60 seconds locally. Prefer wait_for when you know what you are waiting for.
wait(ms) 本地和托管
Screen understanding
Let the model see the screen and locate things on it without guessing coordinates: pixels, OCR, template matching and the accessibility tree.
- Capture the screen and return it as an image the model looks at directly. Pass max_width (200 to 2000) for a smaller image; the reply then reports the scale, and tap coordinates stay in device pixels (device_x = image_x / scale). The local server limits the long side to 1280 px by default and always reports the scale.
screenshot(max_width) 本地和托管 - OCR the whole screen or one region into text lines. The hosted server returns a confidence and a bounding box per line; the local server returns the lines and the scanned box.
read_text(region {x1, y1, x2, y2}) 本地和托管 - Locate a template on screen with OpenCV matching and return the score and tap coordinates. The template is inline (template_base64) or an image_id from your image library, so a crop made once with crop_image is found every time.
find_image(template_base64 | image_id, threshold) 本地和托管 - The Android accessibility hierarchy as compact text, one visible element per line with its class, id, text, description, bounds and flags. Cheaper and more exact than a screenshot for buttons, fields and labels; games and canvas views expose little.
get_ui_tree(max_nodes) 本地和托管 - Find UI elements by resource id, text, content description and/or class (selectors combine). Returns the match at index with its bounds and tap centre, plus up to 20 matches. contains=true (default) matches substrings.
find_element(id, text, desc, class, contains, index) 本地和托管 - Poll the screen until one target appears or timeout_ms (default 15000, max 60000) passes: a library image (image_id) or inline template, on-screen text (OCR), or a UI element selector. Returns where it was found and the elapsed time. Use it instead of wait plus screenshot loops.
wait_for(image_id | template_base64 | text | element {id, text, desc, class}, threshold, timeout_ms, interval_ms) 本地和托管
Macros and runs
Your macro library, readable and runnable from the client. Hosted runs execute server-side on a cloud device; local runs are the editor's Run button on your emulator.
- List your saved macros with name, id and type (code, or legacy for a retired block macro).
list_macros(page, page_size) 本地和托管 - Read a code macro's project: the entry script and the file listing by default, or one file you name.
get_macro_code(macro_id, file) 本地和托管 - Start a saved code macro with optional argument overrides and return a run_id at once. Hosted: server-side on a cloud device of yours (it starts if stopped). Local: on the named emulator, which stays busy for the other device tools until the run ends.
run_macro(macro_id, device_id, args) 本地和托管 - The state of a hosted run, from launching through running to finished or failed, with its message and timings.
get_run(run_id) 托管 - The state of a local run (running, stopping, completed, failed, stopped), its timestamps and the exit code once it ended. The local name for get_run.
get_run_status(run_id) 本地 - Stop a running macro.
stop_run(run_id) 本地和托管 - The trailing stdout and stderr lines of a run, newest last, while it runs or after. Hosted runs come from run_macro, validate_macro or a schedule.
get_run_log(run_id, max_lines) 本地和托管
Image library
Your Image Library, the same one the app shows: crop a control once, then find it by id from any tool or macro.
- List your library images, newest first, optionally within one folder or matching a name substring; each with id, name, folder, pixel size and byte size.
list_images(folder, query, limit, page) 本地和托管 - Fetch one library image by id: the picture itself, to confirm it is the template you mean, plus its name, folder and size.
get_image(image_id) 本地和托管 - Crop a rectangle of the device's current screen into the library as a PNG template and return its new image_id with a small preview. The region is clamped to the screen; at least 8 by 8 pixels must remain; a name already used in the folder gets a numeric suffix.
crop_image(region {x, y, width, height}, name, folder) 本地和托管
Agent authoring
Hand a goal to MAS Agent and get a finished macro back, from any client.
- Ask MAS Agent to build a macro from a plain-language goal: it explores the app on the device, captures what it needs, writes and validates the macro. macro_id improves one of your macros instead, parent_session_id continues an earlier session, pipeline picks how the code is produced (build, review, author, author_fast). Async and minutes long; returns a session_id. Hosted authoring always uses the metered cloud model; local authoring uses the provider the app has selected (provider overrides it).
author_macro(prompt, device_id, model, macro_id, parent_session_id, pipeline) 本地和托管 - Progress of an authoring session: state, summary, the macro id once it exists, and any question the agent is waiting on. Hosted sessions also return the transcript events after your cursor.
get_agent_session(session_id, after_seq) 本地和托管 - Answer the agent's pending question so it can continue. Hosted: qid plus an answers object keyed by question header; local: one answer string (an option label or free text).
answer_agent_session(session_id, qid, answers) 本地和托管 - Stop a session early. Work done so far is saved.
stop_agent_session(session_id) 本地和托管
Developer loop
Write a macro yourself, in the house style: scaffold the project, install it as a code macro, prove it with one run.
- Generate the house project skeleton for a new code macro: src/app.py wiring, one src/activities/<name>.py stub per activity, common_logic.py, the scheduler library, task.yaml, ui.xml, requirements.txt and README.md. Pure: nothing is saved; returns {files: {path: content}} for you to fill in.
scaffold_macro(name, activities, description, app_package) 本地和托管 - Create a code macro from project files, or replace the code of one of yours when macro_id is given, through the same create and code-sync path the app uses. files is {path: content}, 2 MB total; the code is syntax-checked on intake. The local server also takes project_dir, a folder on your PC.
install_macro(name, files, macro_id, description) 本地和托管 - Run a macro once and wait for the verdict: passed, exit code and the log tail. Hosted: one run on a cloud device, default 300 s; a run still going at the timeout is stopped. Local: the engine's validation job on your emulator, which also checks task.yaml; pass macro_id or project_dir, and runs (1 to 5) for the graduation ladder.
validate_macro(macro_id, device_id, timeout_s, args) 本地和托管
App maps
What the agent has learned about an app, readable by your client.
- The learned menu map of an app: its screens and the proven routes between them.
get_map(package, profile) 托管
Scheduling
The same scheduler the app's Schedule card uses. Hosted jobs run on a cloud device with your PC off; local jobs fire while the app is open.
- Schedule a code macro to run without you: once at `at` (RFC 3339) or recurring with every = daily, weekly (with weekdays) or monthly, in an IANA timezone. No hourly recurrence: a macro that repeats within the day recurs itself. Missed occurrences are skipped; the job pauses after three consecutive failures. Returns job_id and next_run_at.
schedule_macro(macro_id, device_id, at, every, timezone, name, weekdays) 本地和托管 - Your scheduled jobs, cloud and local, with status, next and last run, failures and the auto-pause reason. Filter by status or target.
list_schedules(status, target, page) 本地和托管 - Delete a scheduled job for good; a run still going on a cloud device is stopped first. Use the app to skip one occurrence or pause a job.
cancel_schedule(job_id) 本地和托管
资源
服务器发布的文档,让客户端不用离开对话就能写宏代码。
mas://statusRead first: the server, the account (subscription, AI credits), the devices it reaches, connected clients on the local server, and where local emulators live (the desktop app).mas://docs/sdk-referenceThe complete reference of the pre-installed mas SDK macros are written against: device control, vision, elements, app management, storage, types and exceptions.mas://docs/house-libraryThe house library MAS Agent builds macros with: the scheduler skeleton, the activity runner and the runtime-UI template that scaffold_macro ships verbatim.
设置
一分钟接入
托管服务器每次请求都要带上你的密钥:在应用的“集成(MCP)”或 API 密钥里创建一个,勾选你要的权限范围,然后放在 X-API-Key 或 Authorization 请求头里发送。偏好短期凭据的客户端可以用密钥换取有效期 1 小时的访问令牌,采用交互式登录的客户端则会拿到自己的令牌。本地服务器完全不需要密钥。
curl -s -X POST https://api.automationmacro.com/api/mcp/oauth/token -d grant_type=client_credentials -d client_secret=$MAS_API_KEY Claude Code
托管服务器,把密钥放在请求头里;然后在应用开着时用 URL 添加本地服务器:
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp --header "X-API-Key: $MAS_API_KEY"
claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp Cursor
在 .cursor/mcp.json 里,把两个服务器都写成 HTTP 条目:
{
"mcpServers": {
"mas-cloud": {
"url": "https://api.automationmacro.com/mcp",
"headers": { "X-API-Key": "<your key>" }
},
"mas-local": { "url": "http://127.0.0.1:3846/mcp" }
}
} Codex CLI
在 ~/.codex/config.toml 里,密钥放在环境变量中;本地服务器用 codex mcp add mas-local --url:
[mcp_servers.mas-cloud]
url = "https://api.automationmacro.com/mcp"
bearer_token_env_var = "MAS_API_KEY" Hermes、OpenCode、Gemini CLI 和其他客户端
任何接受带请求头的 HTTP 服务器的客户端都可以。Claude Desktop 是启动命令而不是调用 URL,所以它用应用本身作为通往本地服务器的桥接;应用里会显示填好安装路径的配置块。
{
"mcpServers": {
"mas-cloud": { "type": "http", "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } },
"mas-local": { "type": "http", "url": "http://127.0.0.1:3846/mcp" }
}
} 验证:让你的客户端列出设备,然后要一张截图。端点 https://api.automationmacro.com/mcp,协议 2025-06-18,发现文档在 /.well-known 下。
智能体,作为工具
author_macro:从 AI 探索到做好的 Python 宏
大多数安卓 MCP 服务器止步于设备。这一个把智能体交给你。author_macro 接收一个用普通语言描述的目标和一台云手机,启动一个 MAS Agent 会话:探索应用,从实时屏幕截取需要的模板图片和文字区域,编译出确定性的 Python 宏,并通过回放验证。get_agent_session 返回带游标的记录以及智能体提出的任何问题;answer_agent_session 回答它。做好的宏进入你的库,id 记录在会话里,随时可以 run_macro,之后每次运行都是零 AI 积分。查看 MAS Agent。
QA
安卓应用测试和 QA 工作流
把客户端指向模拟器或云手机上的测试版本,用 tap、type_text 和 press_key 驱动流程,用 read_text 或 find_image 逐屏断言。用 author_macro 走一遍流程,它就变成一个可以定时运行的可重复检查。它像用户一样通过屏幕测试应用;它不是单元测试框架。
安全
远程服务器、HTTP 传输、带权限范围的密钥,以及一个只回应你这台电脑的本地服务器
托管服务器是单一端点上基于 HTTPS 的无状态 JSON-RPC。密钥在应用里创建,只显示一次,可以带过期日期,一键撤销;由它换取的令牌有效期 1 小时,并随密钥一起失效。每个密钥只携带你授予的权限范围:
-
devices:controllease a cloud device, see its screen, tap, type, manage apps and the image library -
macros:runlist and read macros; start, check, validate and stop runs; read run logs; manage schedules -
macros:authorstart, follow, answer and stop an agent authoring session; scaffold and install macro code -
maps:readread the learned map of an app
本地服务器监听回环地址,只回应你自己这台电脑:来自其他主机的请求,或来自其他来源的网页,都会被拒绝。它在应用开着的时候运行,你在哪里打开它,就在哪里关掉它。
安卓 MCP 服务器常见问题
什么是安卓 MCP 服务器?
MCP(Model Context Protocol)是 Claude Code、Cursor 和 Codex 等 AI 客户端调用外部工具的方式。安卓 MCP 服务器把一台安卓设备作为工具暴露出来:截图、读取上面的文字、点击、滑动、输入、打开应用。MAS 服务器暴露 41 个工具,并加上单纯的设备服务器做不到的事:运行已保存的宏、让 MAS Agent 生成一个、读取它学到的应用地图。
如何把 Claude Code 连接到安卓模拟器?
对于你自己的模拟器,在应用的“集成(MCP)”里打开本地服务器,然后注册它的 URL:claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp。它能驱动 adb 看到的任何设备。对于云手机,用 claude mcp add --transport http 添加托管服务器,然后要么在 Claude Code 里通过 /mcp 登录,要么把你的密钥作为请求头传入。两段代码都在本页。
支持 BlueStacks、LDPlayer、MuMu、MEmu 吗?
支持。本地服务器和 adb devices 列出的任何东西通信,这覆盖了 Windows 或 macOS 上的 BlueStacks、LDPlayer、MuMu、MEmu 以及其他兼容 adb 的模拟器。它不绑定任何一个模拟器品牌。
Cursor 或 Codex 能通过 MCP 控制安卓模拟器吗?
能。Cursor 在 mcp.json 里把两个服务器都作为 HTTP 条目:托管的那个把密钥放在请求头里,本地的那个用它的回环地址。Codex CLI 用 codex mcp add 和来自环境变量的密钥添加托管服务器,用 --url 添加本地服务器。两边出现的是同一套工具名。
还有哪些 MCP 客户端可以用?
任何能通过 HTTP 调用 MCP 服务器的客户端:Claude Code、Cursor、Codex、Hermes、OpenCode、Gemini CLI 等。Claude Desktop 和 claude.ai 把托管服务器添加为自定义连接器并让你登录;至于本地服务器,Claude Desktop 会启动应用本身,因为它启动的是命令,而不是调用 URL。
需要安装 ADB 或 Android Studio 吗?
本地服务器通过 adb 驱动模拟器,而桌面应用自带一份 adb,所以除了应用之外什么都不用装;不需要 Android Studio。托管服务器则完全不用安装任何东西:云手机在服务器端驱动,你的客户端只是调用工具。
模型真的能看到屏幕吗?
能。screenshot 把屏幕作为图片返回,模型直接查看。read_text 运行 OCR,返回每一行以及置信度和边框;find_image 匹配你发送的模板,返回得分和点击坐标。不需要无障碍树,所以它在游戏上也能用。
可以控制插到电脑上的实体安卓手机吗?
可以,通过本地服务器。开启 USB 调试,插上手机,它就会像任何模拟器一样出现在 list_devices 里。屏幕、输入和视觉工具的工作方式完全一样。
它是远程 MCP 服务器还是本地运行?
都有。托管服务器是一个远程 HTTP 端点 https://api.automationmacro.com/mcp,为你的云手机提供全部 41 个工具。本地服务器就是桌面应用本身,地址是 http://127.0.0.1:3846/mcp,为模拟器和插上数据线的手机提供 38 个工具:同样的设备、视觉、宏、图片库、生成、开发循环和定时任务工具,只少了设备租约和应用地图。区别在于工作在哪里运行。
身份验证如何工作?
托管服务器每次请求都接收你在应用里创建的密钥,带着你勾选的权限范围,放在 X-API-Key 或 Authorization: Bearer 请求头里。实现了 MCP 客户端凭据扩展的客户端,可以在 https://api.automationmacro.com/api/mcp/oauth/token 用它换取一小时有效的令牌;采用交互式登录的客户端会拿到自己的令牌;撤销密钥就会让它们全部失效。发现文档发布在 /.well-known 下。本地服务器不需要密钥。
author_macro 返回什么?需要多久?
它在云手机上启动一个 MAS Agent 会话,并立即返回会话 id。智能体会探索应用几分钟;get_agent_session 以游标方式流式返回记录,并显示它提出的任何问题,你用 answer_agent_session 回答。完成后,宏 id 在会话里,宏在你的库里,随时可以 run_macro。生成消耗 AI 积分;运行做好的宏零积分。查看 MAS Agent。
免费吗?云手机多少钱?
本地服务器是桌面应用的一部分,不额外收费;它需要应用开着并且已登录。托管服务器是你 MAS 账户的一部分;它的设备工具作用于你拥有的云手机,每台 $80/月,含月度积分额度,设备工具不按调用收费。运行做好的宏零积分;智能体生成时按工作量消耗积分。查看价格。
可以在云手机上 24 小时运行而不开电脑吗?
可以。lease_device 在云手机上打开控制会话,还能启动已停止的设备;run_macro 在服务器端执行。你的电脑不需要一直开着,租约在每次调用时续期,闲置 10 分钟后过期。查看云手机。
可以用它做安卓应用测试和 QA 吗?
可以。把客户端指向测试版本,用 tap、type 和 press_key 驱动流程,用 read_text 或 find_image 逐屏断言,让 author_macro 把你走过一遍的流程变成可重复的检查。它像用户一样通过屏幕自动操作应用;它不是单元测试框架。