Teach the Agent to use ZeroToken MCP for browser automation, trajectory recording, and script replay. Designed to let OpenClaw consume as few Tokens as possible when executing scheduled/repeated tasks。
ZeroToken project homepage:https://github.com/AMOS144/zerotoken
When to use / when not to use
- Suitable for use:
- Tasks that require browser automation via OpenClaw + ZeroToken MCP and will be repeated / executed on a schedule in the future.
- When you already have a complete browser operation trajectory and want to convert it into a low-Token-consumption script for reuse.
- Not suitable for use:
- Scenarios where you only want to perform a one-off operation with no reuse needs (just use ZeroToken MCP directly).
- Tasks where the page strongly depends on human decision-making, and a large number of steps require
fuzzy_pointintervention, making it difficult to provide fallback in unattended operation.
Prerequisites
- The current environment can already access via MCP a server named
zerotoken(or an equivalent MCP server id). - Before performing browser operations, you need to call
browser_initfirst; after completion, you may optionally callbrowser_close。
Preparation before using OpenClaw (HTTP mode)
When using ZeroToken via OpenClaw / MCPorter , because each call creates a new process, the browser state is lost. You need to switch to Streamable HTTP transport mode, with the service running persistently:
- Start the HTTP service manually(running persistently in the background):
zerotoken-mcp-http, orzerotoken-mcp --transport streamable-http- Default port 8000, can be overridden with
--portor the environment variableZEROTOKEN_HTTP_PORT.
- OpenClaw configuration: In
openclaw.json'smcpServers.zerotoken, use a URL instead of command:
The specific field names are subject to the OpenClaw documentation (may be{ "mcpServers": { "zerotoken": { "url": "http://localhost:8000/mcp" } } }streamable-httporurl)。
Handling when MCP is not configured / ZeroToken is not installed
When calls to ZeroToken-related MCP tools fail and symptoms similar to the following appear:
- Cannot find an MCP server named
zerotoken; browser_init/trajectory_startand other tools report "tool not found", "MCP server unavailable", or import-related errors;
The Agent should handle them in the following order:
- Clearly inform the user:ZeroToken MCP is not yet installed or enabled in the current environment, so the browser automation script capability is temporarily unavailable.
- Ask the user which platform they are currently using (e.g. "Cursor / OpenClaw / other MCP-supporting clients"), and guide the user to install ZeroToken and browser dependencies:
- OpenClaw + MCPorter:
mcporter install zerotoken --target openclaw --configure。Important: OpenClaw needs to use HTTP mode; first run in the backgroundzerotoken-mcp-http, then inopenclaw.jsonconfiguremcpServers.zerotokenas{"url": "http://localhost:8000/mcp"}(see "Preparation before using OpenClaw" above). - If the platform has an MCP Marketplace / plugin marketplace:
Prompt the user to search for and enablezerotokenMCP。 - If it is a local Python environment (e.g. command line / development machine):
Prompt the user to execute in sequence:- Install the package:
pip install zerotoken - Install Playwright browser dependencies (otherwise the browser tools will report errors):
- Normal environment:
playwright install chromium - If using uv:
uv run playwright install chromium --with-deps
- Normal environment:
- Start MCP Server:OpenClaw Run in the background
zerotoken-mcp-http;IDE such as Cursor Runzerotoken-mcp(or automatically launched by the client). - In the client, register this MCP server as the MCP with id
zerotoken; OpenClaw requires configuring the URL inopenclaw.json(see "OpenClaw Preparation Before Use").
- Install the package:
- OpenClaw + MCPorter:
- After the user confirms that ZeroToken has been installed and enabled, the Agent again starts from
browser_initto execute the ZeroToken-related steps.
MCP Tools and Workflow
Tool List (Aligned with MCP)
- browser:
browser_init(optionalstealth: trueanti-scraping),browser_close、browser_open、browser_click、browser_input、browser_get_text、browser_get_html、browser_screenshot、browser_wait_for、browser_extract_data - trajectory:
trajectory_start、trajectory_complete、trajectory_get、trajectory_list、trajectory_load、trajectory_delete、trajectory_to_script(convert trace to script and save to database) - script:
script_save、script_list、script_load、script_deleterun_script: execute script replay without LLM- Start mode:
{ "task_id": "...", "vars"?: {...} } - Resume mode (advanced usage):
{ "session_id": "...", "resolution": {...} }(resumed by the upper-level orchestrator after pausing at a DFU/ambiguous point)
- Start mode:
run_script_by_job_id: execute scheduled task in one step,{ "binding_key": "job_id", "vars"?: {...} }, internally looks up the binding and executes
- session:
session_list、session_get(session_id): query recording/playback session details, used for debug, audit, and scheduled task review
Scripts, traces, and sessions are all stored by the MCP backend in the SQLite database and accessed through the above tools, without relying on local file paths.
Optional parameters:include_screenshot: false reduce response size;auto_save: true / adaptive: true used for adaptive element locating.
Quick Reference
| Tool / action | Typical use |
|---|---|
| browser_init | Initialize browser session (optional headless/stealth) |
| browser_open | Open login page or any target page |
| browser_click | Click buttons, links, tabs, etc. |
| browser_input | Enter username, password, search keywords, etc. in input fields |
| browser_get_text/get_html | Read text or the entire HTML block for subsequent parsing |
| browser_wait_for | Wait for a piece of text to appear/disappear, to avoid the page not being fully loaded |
| browser_screenshot | Screenshot for archiving or debugging |
| browser_extract_data | Extract data from lists/tables |
| trajectory_start/complete | Record a complete browser operation trace |
Typical workflow
- Recording:
trajectory_start(task_id, goal)→browser_init→browser_open/browser_click/browser_inputetc. →trajectory_complete(export_for_ai: true) - Reuse:
trajectory_listlook up task_id →trajectory_load(task_id, format)get trace - Management:
trajectory_delete(task_id)delete; browser tools can passinclude_screenshot: false - Error: on failure returns
success: false、code、retryable, can be based onretryableto decide whether to retry
When to generate a script
Only in the following casesgenerate a reusable script from the trace (to avoid unnecessarily increasing Tokens):
- Repeated task: the user explicitly says it will be executed multiple times (e.g. "run every day from now on", "scheduled execution", "repeated task"), or cron/context indicates it is a scheduled/periodic task.
- Explicit user request: the user says "generate a reusable script", "save as a script for next time", "export as a script", etc.
Do not proactively generate: when reuse is not mentioned and scheduling/repetition is not mentioned, only record and save the trace. If the user later wants a script, generate it then.
How scheduled tasks find the corresponding script (based on job_id binding)
When When OpenClaw triggers this Skill via a scheduled task , the event parameters will carry that task's job_id. ZeroToken uses job_id as the binding key (binding_key), and maintains the "job_id ↔ script" relationship in the script_bindings table of the MCP database.
The Agent must follow these conventions:
- Prefer using
run_script_by_job_id(binding_key=job_id, vars?)to execute in one step: MCP internally looks up the binding, merges default_vars, and executes the script. - If step-by-step control is needed, you can call
script_binding_get(binding_key=job_id), thenrun_script(task_id, vars=merged_vars)。 - If
run_script_by_job_idorscript_binding_get(job_id)returns "not found":- Prompt the user that "the current job_id is not yet bound to a ZeroToken script";
- Do not casually try other scripts or automatically create new scripts.
- For scenarios without
job_idor not marked as scheduled tasks:- Treat it as a "one-off task", only use
browser_*+trajectory_*to complete the current requirement, and do not actively look up/execute scripts.
- Treat it as a "one-off task", only use
Developers should, on the ZeroToken side or in OpenClaw's integration layer, use script_binding_set(binding_key=job_id, script_task_id=..., default_vars?, description?) to preemptively bind the scheduled task job_id explicitly to the script task_id . This Skill only queries the binding via job_id ,and does not make additional inferences about the mapping relationship。
Configure a scheduled task (full process)
When the Agent receives a scheduled task configuration request with job_id (e.g., the user says "set it to run daily" or "set this task as scheduled"), and OpenClaw has passed in job_id , the following end-to-end process must be completed:
- Determine task_id: the task_id specified by the user, or of the most recently recorded trajectory (e.g.,
trajectory_listtake the latest). - Check trajectory:
trajectory_load(task_id)Check whether the trajectory exists; if not, prompt the user to record it first. - Generate script:
script_load(task_id)Check whether the script exists; if not, calltrajectory_to_script(task_id, stealth?)to generate and save it based on the trajectory. - Bind:
script_binding_set(binding_key=job_id, script_task_id=task_id, default_vars?, description?)Bind the job_id to the script.
Important:task_id It runs through trajectory → script → binding, and the three must be consistent. The task_id used during recording is the script's task_id, and is also the binding's script_task_id。
If script_binding_set returns SCRIPT_NOT_FOUND, it means the script does not exist, and you should first trajectory_to_script(task_id) and then bind.
Anti-scraping response (sites easily blocked by cloud shields/anti-scraping)
If the target site (such as Bilibili, Xiaohongshu, etc.) is easily detected as automation and blocked, you need to:
- During recording:
browser_initpassstealth: trueto reduce the probability of being identified. - When generating the script:
trajectory_to_script(task_id, stealth=true)make the generated script'sbrowser_initincludestealth: true。 - During execution:
run_scriptwill execute according to thebrowser_initparameter in the script; if the script containsstealth: true, anti-detection is automatically enabled.
stealth mode will enable: startup parameter spoofing, navigator fingerprint spoofing, Sec-CH-UA headers, WebGL fingerprint spoofing, etc.
Recovery when scheduled task execution fails
- SCRIPT_BINDING_NOT_FOUND: Prompt the user that "the current job_id is not yet bound to a ZeroToken script", and the configuration process must be completed first.
- SCRIPT_NOT_FOUND(binding exists but the script was deleted): if it returns the
hintfield, you can follow the prompt to executetrajectory_to_script(script_task_id)Regenerate the script (while the trace still exists), then retryrun_script_by_job_id。
Script format and execution method
Format (stored in the MCP database)
The script is read from and written to via script_save / script_load ; a structure example:
{
"task_id": "login_daily",
"goal": "每日登录并拉取报表",
"steps": [
{ "action": "browser_init", "params": { "headless": true, "stealth": true } },
{ "action": "trajectory_start", "params": { "task_id": "login_daily", "goal": "每日登录并拉取报表" } },
{ "action": "browser_open", "params": { "url": "https://example.com/login" } },
{ "action": "browser_input", "params": { "selector": "#user", "text": "{{username}}" } },
{ "action": "browser_click", "params": { "selector": "#submit" },
"fuzzy_point": { "reason": "验证码需识别", "hint": "可调 browser_extract_data 或等待人工输入" } },
{ "action": "browser_get_text", "params": { "selector": ".report" } }
]
}
steps: an ordered array; each step'sactioncorresponds to an MCP tool name, andparamsis that tool's input parameters.- Optional
fuzzy_point: records the semantic information for that step that "requires AI/human intervention" (reason、hint),itself will not cause ScriptEngine to pause automatically; only when a matching DFU / execution point is configured for that step willrun_scriptreturn when execution reaches that stepstatus="paused"。 - Optional parameterization:
paramscan use{{varname}}in it, replaced before execution by the Agent or configuration (such as environment variables, user input), or when paused at an ExecutionPoint/DFU the upper layer generatesresolution.varsmerged into the runtime variable environment.For scripts containing{{varname}}, the corresponding vars must be provided before execution(run_scriptofvarsorrun_script_by_job_idofvars/binding ofdefault_vars), otherwise the placeholder will remain as a literal, which may result in invalid input.
Execute script (only in scheduled / recurring task scenarios)
Only in the following two cases should you look up and execute a script:
- The context/cron clearly indicates a "scheduled / periodic / repeated execution" task (such as daily comments, hourly report scraping).
- The user explicitly says "execute ZeroToken script <task_id>", "run the script for <task_id>", etc.
In these cases:
- Call
script_load(task_id)to read the script from the MCP database; if there is none, calltrajectory_to_script(task_id)to generate and save it based on the trace (otherwise do not create a script on your own). - Call
run_script(task_id, vars?)to have the ScriptEngine inside MCP automatically execute the script instepsorder, with no LLM needed; the execution process is written to the session; the return is in the form{"success": ..., "status": "success|paused|failed", "session_id": ...}。 - If it returns
status="paused"(for example, hitting a DFU / execution point / failure retry limit):- The upper-layer Agent reads
pause_event(including step_index, dfu_id, prompt text, and the vars that need to be generated), makes a decision or generates vars; - then call
run_script(session_id=..., resolution={...})to resume execution, and ScriptEngine continues executing the subsequent steps in order.
- The upper-layer Agent reads
Non-scheduled/one-off tasks:Prefer to use only browser_ + trajectory_ to record and complete the current task, and do not proactively look up/execute scripts.**
A script is a "data-driven sequence of MCP calls",stored in the MCP database and automatically replayed by ScriptEngine, with low token consumption, and each execution can be tracked through the session.
Ambiguous points / DFU execution conventions
- *When an Agent is present (manually calling browser_ )**: when encountering an OperationRecord / step with
fuzzy_point, you can treatreason、hintas a hint, and based on the current page decide whether to additionally callbrowser_extract_data、browser_inputetc., then continue. - When using
run_script(ScriptEngine automatic replay): whether to pause is determined by the DFU/execution point rules (dfu_*configuration + trigger matching), not byfuzzy_pointalone. If a certain step has bothfuzzy_pointIf a DFU is hit again, ScriptEngine will return at that stepstatus="paused"+pause_event, and the upper-layer Agent decidesresolutionbefore resuming. - Unattended: It is not recommended to rely on a large number of steps requiring strong human judgment; for scripts that contain ambiguous points but have no DFU configured, in pure
run_scriptmode they will run straight through according to the script, and post-hoc auditing via session results + logs may be needed.
Generate script (flow) from trajectory
Recommended: Directly call trajectory_to_script(task_id, script_task_id?, prepend_init?, stealth?). MCP will load the trajectory from the database, convert it into a script and save it, and return task_id. If the target site is easily blocked by anti-crawling measures, pass stealth=true so that in the generated script browser_init includes stealth: true。
If manual control is needed, refer to the following flow:
-
Input:
trajectory_load(task_id, format="json")orformat="ai_prompt"; if necessary, first usetrajectory_listto select the task_id. -
action mapping: In the trajectory,
operations[].actionis an internal name; when generating the script it must be mapped to the MCP tool name; during execution, call it by the MCP tool name.Trajectory action Script/MCP action open browser_open click browser_click input browser_input get_text browser_get_text get_html browser_get_html screenshot browser_screenshot wait_for browser_wait_for extract_data browser_extract_data The trajectory does not include
browser_init、trajectory_start; when generating the script, add these two steps at the beginning of steps (if recording/playback is needed). -
Output: Call
script_save(task_id, goal, steps)to write to the MCP database; in steps, action uses the mapped MCP name, params are consistent with the trajectory, andselector_candidates、fuzzy_pointis carried over from the trajectory.
Save location and reuse lookup
- Scripts and trajectories: Both are stored by the MCP backend in the database (SQLite), and do not depend on local file paths.
- Lookup: When executing/reusing a task, use
trajectory_listorscript_listto get the task_id, and usescript_load(task_id)to retrieve the script; if there is none, prompt 'This task has no script yet. Generate one from the trajectory?' and directly calltrajectory_to_script(task_id)to generate and save it. - Session: Each
run_scriptor recording produces a session; usesession_list、session_get(session_id)to view it.
Installation
Place this Skill into one of OpenClaw's skills directories:
- Workspace:
./skills/zerotoken-openclaw/(current project only) - Local shared:
~/.openclaw/skills/zerotoken-openclaw/ - Or via ClawHub:
clawhub install zerotoken-openclaw(if published)
Example installation from this repository: clone, then copy skills/zerotoken-openclaw/ to one of the above paths.
Common pitfalls
- OpenClaw: Did not start
zerotoken-mcp-httporopenclaw.jsonin the background and still use command instead of url, causing a new process to be created on each call and browser state to be lost. - Forgot to call
browser_initfirst and directly usedbrowser_open/browser_click, causing the first call to fail or behave abnormally. - Did not use
export_for_ai: truewhen recording the trajectory, so extra processing of trajectory data is needed when later generating the script. task_idis inconsistent between trajectory and script, causingscript_load(task_id)to fail to find the corresponding script.- Unattended scenarios still rely on scripts containing a large number of
fuzzy_point, and are prone to getting stuck at ambiguous-point steps; such tasks should be evaluated in advance for whether human fallback is needed.