WebMCP tools and demos with Moli
These demos open public WebMCP sites in Moli, discover their native tools over CDP, invoke them, and check both the tool responses and the page state. No model account or API key is required: the scripts supply the tool arguments directly.
Operate any WebMCP site
webmcp.py accepts a site URL and uses the site's native tool catalog. Build Moli
with cargo build --release -p moli, then list a site's tools and full schemas:
uv run moli-playground/webmcp/webmcp.py \
https://googlechromelabs.github.io/webmcp-tools/demos/pizza-maker/ list
Call a tool with JSON arguments:
uv run moli-playground/webmcp/webmcp.py \
https://googlechromelabs.github.io/webmcp-tools/demos/pizza-maker/ \
call set_pizza_size --input '{"size":"Large"}'
--input @arguments.json reads a file; --input - reads JSON from stdin. Input
must be a JSON object. Tool responses go to stdout as JSON, including the native
status, output, and any execution error. A failed one-shot call exits with status
- A site with no registered tools produces an empty list.
Each one-shot command opens a new page. To make several calls on the same page, use the interactive shell:
uv run moli-playground/webmcp/webmcp.py \
https://googlechromelabs.github.io/webmcp-tools/demos/pizza-maker/ shell
Inside the shell:
tools
schema set_pizza_size
call set_pizza_size {"size":"Large"}
wait <invocationId>
call add_topping {"topping":"🍍","size":"Large","count":3}
wait <invocationId>
quit
Use the invocation ID printed by each call. result ID shows its current
status, wait ID waits for completion, and cancel ID cancels a pending call.
The shell keeps receiving tool additions, removals, and responses while waiting
for your next command. Commands may also be piped into the shell. Pending calls
started by this session are cancelled when it exits.
For declarative forms that need confirmation, run call NAME JSON, inspect the
prepared form in your attached page, then use confirm ID and wait ID.
Confirmation targets the form identified by the native tool's node, including
forms in child frames. For a one-shot call, --confirm explicitly submits the
form after filling. Without it, a manual form call reports that confirmation is
required before starting an invocation.
The catalog includes tools in child frames. If a name occurs in several frames,
select --frame-id ID or use frame ID in the shell. frame main selects the
main frame; frame all returns to the complete catalog. Frame IDs belong to the
current page, so use the shell or attach to that page when selecting a child.
To reuse an authenticated or already prepared page in an existing release Moli server:
uv run moli-playground/webmcp/webmcp.py - shell \
--cdp-endpoint http://127.0.0.1:9222 --target-id TID-1
The URL - preserves the current page without navigating. --target-id requires
--cdp-endpoint; the script leaves that page and server open on exit. The target
IDs can be obtained from the server's /json/list endpoint.
The CLI waits two seconds after page load to collect initial registrations;
increase --wait-for-tools for sites that register tools later. It also supports
the release binary, proxy, and timeout options listed below. Sites must expose
native WebMCP tools; a remote MCP endpoint or static inventory alone is not a
browser tool registration.
Run the preset demos
From the repository root, build a release Moli binary with native WebMCP support and run all three demos:
cargo build --release -p moli
uv run moli-playground/webmcp/webmcp_cdp_demo.py
The script starts moli serve with a temporary profile and an available local
port, then closes it after the run. It uses target/release/moli by default and
rejects binary paths containing a debug directory. uv installs the script's
Python dependency automatically.
Run a single scenario:
uv run moli-playground/webmcp/webmcp_cdp_demo.py --demo booking
uv run moli-playground/webmcp/webmcp_cdp_demo.py --demo bistro
uv run moli-playground/webmcp/webmcp_cdp_demo.py --demo pizza
| Demo | Tool sequence | What it checks |
|---|---|---|
booking |
getAvailability → bookSlot → cancelBooking |
Choose an available slot, read its confirmation ID from the structured result, verify the visible confirmation, then cancel and check that the widget resets. |
bistro |
book_table_le_petit_bistro → regular submit button |
Native declarative form filling, :tool-form-active, submitter focus, pending result before confirmation, and the response supplied through SubmitEvent.respondWith(). |
pizza |
manage_pizza → set_pizza_size → set_pizza_style → add_topping × 2 |
Sequential imperative calls produce a large BBQ pizza with three pineapple and five bacon toppings in the page. |
The bistro uses the site's default form, which waits for confirmation. The demo first checks the prepared form, then clicks its normal submit button to simulate the visitor confirming. Dates are computed at runtime; the booking scenario uses the availability returned by the site.
Progress goes to stderr. The JSON report on stdout includes the discovered tool
schemas, invocation IDs, WebMCP.toolResponded events, and the final page state.
Any failed scenario makes the process exit with status 1.
uv run moli-playground/webmcp/webmcp_cdp_demo.py \
--output /tmp/moli-webmcp-results.json
Explore other sites
List tools without invoking them:
uv run moli-playground/webmcp/webmcp_cdp_demo.py --demo pizza --list-tools
uv run moli-playground/webmcp/webmcp_cdp_demo.py --list-tools \
--url https://microsoftedge.github.io/webmcp-labs/pizza-order/
The URL inspector reports tools registered in the page's main frame. It waits for at least one native tool and fails if the site exposes none within the timeout. It does not infer tools from a static manifest.
Useful options:
--moli-bin /path/to/release/moliselects a release binary explicitly.--cdp-endpoint http://127.0.0.1:9222reuses an existing release Moli server; the script opens and closes its own tabs and leaves the server running.--http-proxy http://127.0.0.1:7890configures a server started by the script.--timeout 90increases command, event, and HTTP timeouts in seconds.--startup-timeout 30gives a newly started server more time to become ready.
External WebMCP usage
Research and Moli verification performed on 2026-10-05. The runtime checks
below used target/release/moli, built with cargo build --release -p moli. The
Google Chrome Labs directory
was a starting point; the links below point to the integrations and their own
documentation or source.
| Integration | Published use | Verification in this playground |
|---|---|---|
| Google Chrome Labs booking · source | Availability queries, reservations, and cancellation. | booking passed all three native calls and widget checks. |
| Le Petit Bistro · source | Restaurant reservation using HTML form tool attributes. | bistro passed native filling, confirmation, and response checks. |
| Google Chrome Labs pizza maker · source | Tools update pizza size, style, layers, and toppings. | pizza discovered seven tools and passed five native calls and page checks. |
| Microsoft Edge Contoso Pizza · source | Menu browsing and cart management; the available tools change with order state. | Native discovery verified: the initial page exposes browse and create-order. Other order states were not exercised. |
| BestPrice · tool inventory · source | A shopping comparison site with page tools for product search, listing filters, offers, and price history. | Its published WebMCP documentation and inventory were reviewed; not tested in Moli here. |
| Open for Agents · demo | WordPress and WooCommerce content/product tools, plus form preparation for visitors to confirm. | Its integration documentation was reviewed; not tested in Moli here. |
The three runnable scenarios are public sample apps. BestPrice and Open for Agents show how the same API is being integrated into shopping and CMS workflows. Some providers also publish remote MCP endpoints; those are separate from the browser's WebMCP tool registry.
Native execution path
The runner enables the WebMCP CDP domain, consumes WebMCP.toolsAdded and
WebMCP.toolsRemoved, calls WebMCP.invokeTool, and waits for
WebMCP.toolResponded. It also checks that document.modelContext is an instance
of the browser's native ModelContext.
The bistro and pizza sites ship their own compatibility polyfill, which returns
early when native document.modelContext exists. The runner supplies no
polyfill and invokes tools through Moli's registry. Runtime.evaluate reads the
page state and performs the bistro's ordinary confirmation click.
The CLI and demos share webmcp_client.py, including release server startup, CDP event handling, and invocation tracking. Run the offline CLI integration checks with a release binary already built:
uv run --with websockets python3 -m unittest discover \
-s moli-playground/webmcp -p test_webmcp.py -v
The checks cover shared page state, duplicate names across frames, dynamic tool registration/removal, cancellation, exact form confirmation with two pending forms, execution errors, and preserving an attached page.
These demos need access to the external pages and their dependencies, including
GitHub Pages and the bistro's DOMPurify module on esm.sh. A network error or a
changed tool/schema/page structure is reported as a failure. They are manual
playground examples rather than offline CI fixtures.