Find out what Jelly can do
browser-schema shows browser operations
such as reading a page, finding a button, or checking a result. It does not change the page.
Jelly gives your AI assistant tools to read pages, click and type, check results, capture evidence, and ask for help. This guide shows which tool to use, then provides the exact inputs and outputs for developers.
What is a tool surface? It is the set of tool names Jelly shows to a connected
AI assistant. The default small surface groups browser actions behind three tools:
browser-schema, browser-call, and browser-events.
The large surface exposes individual actions such as click
and read-page as separate tools. Both use the same Jelly browser engine;
this choice changes how the AI calls tools, not where Chromium runs.
Compare the surfaces below.
An MCP tool is an action an AI assistant can request from Jelly. You do not have to write JSON to use one through a connected AI client. For ordinary browser work, these three tools cover discovery, actions, and live events.
browser-schema shows browser operations
such as reading a page, finding a button, or checking a result. It does not change the page.
browser-call carries out browser operations:
read content, click, type, and explicitly verify what happened.
browser-events lets an agent subscribe
to and inspect retained browser events when a task needs them.
New to Jelly? Follow Getting Started to install and connect it. When ready, try the first working MCP example, or copy the startup prompt to confirm tool discovery from your AI chat. A successful browser action alone does not prove the requested outcome; use a verification operation when the result matters.
Use these links when you know the task but not the tool name. Each tool below has its own technical reference, including required inputs, permissions, possible failures, and examples.
browser-schema — discover operationsopen-browser — open or attach Chromiumbrowser-call — read, click, type, or checkbrowser-events — observe browser eventsclose-browser — close a managed browserscreenshot — capture an imagerecord-browser — capture browser videoverify-artifact — check a captured fileinspect-network — inspect network requestsdownload — manage tracked downloadswait-download — wait for a downloaddownloads — list legacy download filesprofile-import — import a closed browser profilebrowser-task — open a page and run a scoped CLI taskcall-routine — run or resume a guarded workflowhitl — ask a person for inputJelly currently publishes 16 tools through the default MCP configuration. A running Jelly server tells each AI client which tools and parameters are available.
The checked-in [mcp].surface = "small-surface" publishes the three browser tools below plus
thirteen system tools. Each has an authentication requirement: a valid static bearer token or OAuth access token
with the jelly scope. The envelope for each successful call is result.structuredContent =
{ok:true,data:…,error:null,meta:{tool:"…"}}; failures include ok:false, a typed
error.kind, human-readable message, and retryable. The data
field may be parsed CLI text or a structured value depending on the binding; example data below is schematic,
not recorded execution output.
Source of truth: the running server's tools/list schema. Browser semantic
operations are discovered with browser-schema and executed with browser-call. The
large-surface alternative instead publishes individual browser primitives; see the generated internal capability
index, but confirm remote publication through tools/list.
browser-schema
Discover semantic browser operations
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"action": "capabilities", "schema_version": 1,
"operation_count": "number", "categories": "array"}
tools/call parameters
{
"name": "browser-schema",
"arguments": {
"action": "capabilities"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
browser-call
Read pages, interact with controls, and explicitly check results. Raw CDP is an advanced option.
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"calls": "per-call outcomes, ordered"}
tools/call parameters
{
"name": "browser-call",
"arguments": {
"calls": [
{
"call": {
"jelly": "read-page",
"params": {}
}
}
]
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
browser-events
Subscribe/poll/unsubscribe retained Chromium events
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"action": "subscribe", "subscription_id": "opaque
ID", "cursor": "stream cursor"}
tools/call parameters
{
"name": "browser-events",
"arguments": {
"action": "subscribe",
"methods": [
"Target.targetCreated"
]
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
open-browser
Start native Chromium, or connect to the selected remote CDP browser, and optionally open a URL
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "browser start result"}
tools/call parameters
{
"name": "open-browser",
"arguments": {
"url": "https://example.com"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
close-browser
Stop managed native Chromium; remote mode detaches Jelly without stopping external Chromium
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "browser stop result"}
tools/call parameters
{
"name": "close-browser",
"arguments": {}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
browser-task
Open page and perform a scoped CLI operation
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "tool execution result"}
tools/call parameters
{
"name": "browser-task",
"arguments": {
"url": "https://example.com",
"tool": "read-page"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
profile-import
Copy a closed Chromium profile into Jelly
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "import result"}
tools/call parameters
{
"name": "profile-import",
"arguments": {
"source": "/path/to/closed-profile"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
screenshot
Capture viewport or selected page target
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "screenshot metadata"}
tools/call parameters
{
"name": "screenshot",
"arguments": {
"target": "css:body"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
record-browser
Start/stop a browser-only video recording
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "recording state"}
tools/call parameters
{
"name": "record-browser",
"arguments": {
"action": "start",
"mode": "steps"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
download
List, inspect, wait for, explicitly transfer, or cancel Chromium downloads
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "download lifecycle records"}
tools/call parameters
{
"name": "download",
"arguments": {
"action": "list"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
downloads
List files in legacy download directories
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "file listing"}
tools/call parameters
{
"name": "downloads",
"arguments": {}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
verify-artifact
Check an existing screenshot/download artifact
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "verification metadata"}
tools/call parameters
{
"name": "verify-artifact",
"arguments": {
"artifact": "artifact-id-from-screenshot"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
wait-download
Wait for a recently initiated download
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "download result"}
tools/call parameters
{
"name": "wait-download",
"arguments": {
"after_ms": 0
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
inspect-network
Start, stop or inspect CDP request capture
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "network capture result"}
tools/call parameters
{
"name": "inspect-network",
"arguments": {
"action": "show"
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
call-routine
Save, list, inspect, run, or resume named JSON graph workflows. Routines can have descriptions, variables, conditions, loops, and calls to other routines. See a practical routine example →
name and optional string vars; resume with
resume_id; or use action: "list" | "describe" | "save".
Saving requires a JSON graph with its name, description, entry, and nodes.
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "routine result"}
tools/call parameters
{
"name": "call-routine",
"arguments": {
"name": "verified-screenshot",
"vars": {
"url": "https://example.com/",
"target": "css:body"
}
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
hitl
Request human intervention via Telegram
jelly scope (global tool access)
structuredContent with ok, data, error, meta;
example data shape: {"stdout": "delivery result"}
tools/call parameters
{
"name": "hitl",
"arguments": {
"message": "Please review the current page",
"no_screenshot": true
}
}
Replace placeholder IDs and paths with real runtime values before calling this tool. The request uses JSON-RPC
method tools/call.
When the remote CDP backend is configured, tools/list adds optional top-level
browser_id to tool inputs. Select the immutable UUID or an easy name such as
Jelly-Applepie. This chooses a Chromium instance; target still chooses a page
inside that browser. The native backend omits this field. Remote download policies are
remote-only, shared-volume and transfer. Explicit
download action: "transfer" uses a separately configured HTTP(S) file bridge; HTTP transfers are unencrypted and warned about.
Browser connection and sandbox security choices are independent of the MCP client authentication policy.
A surface is the list of MCP tools visible to your AI client. The small surface
(the default) offers three general browser tools plus 13 system tools. The
large surface offers individual browser operations, such as
click and read-page, plus the same system tools.
You do not need to switch surfaces to choose native Chromium, Docker/Podman, or remote CDP.
Query tools/list on the running MCP server for the active catalog and input schemas.
See the MCP reference
for deployment settings and advanced configuration.
When [mcp].surface = "large-surface", the three browser façade tools are replaced by 47
individual browser primitives described below. All 13 system tools above remain published. Since the
current raw CDP configuration, this alternate mode additionally exposes cdp-call, totaling
61 tools. Confirm the active set using the runtime tools/list.
Shared permissions: bearer token or OAuth jelly scope. Shared
result: structuredContent containing ok, data,
error, meta.tool. Common errors: invalid_arguments,
browser_unavailable, plus typed target/condition/script failures as appropriate. Each example below
is a JSON params.arguments object for a tools/call request with
params.name equal to the corresponding primitive name.
On smaller screens, scroll sideways within the table to view all five columns.
| Tool | Description / usage | Named parameters (* required) | Side effects | Example arguments |
|---|---|---|---|---|
clickinput
|
Dispatch a click to a visible element. This confirms the interaction was performed, not the resulting
application state.click <target>
|
target *: target | Modifies page/input state |
{"target": "css:body"}
|
type-textinput
|
Type text into a visible editable element, optionally targeting a specific element.type-text
<text> [target]
|
text *: string, target: target | Modifies page/input state |
{"text": "Example"}
|
fillinput
|
Replace the current contents of a visible editable element and dispatch input/change events.fill
<text> [target]
|
text *: string, target: target | Modifies page/input state |
{"text": "Example"}
|
press-keyinput
|
Dispatch a keyboard key to the currently focused page element.press-key <key>
|
key *: string | Modifies page/input state |
{"key": "name"}
|
selectinput
|
Select an option in a native select element by value or visible option text.select <target>
<value>
|
target *: target, value *: string | Modifies page/input state |
{"target": "css:body", "value": "Example"}
|
checkinput
|
Ensure a checkbox or other checkable element is checked.check <target>
|
target *: target | Modifies page/input state |
{"target": "css:body"}
|
dialoginput
|
Accept or dismiss the active JavaScript dialog, optionally supplying prompt text.dialog
<accept|dismiss> [text]
|
action *: string, text: string | Modifies page/input state |
{"action": "dismiss"}
|
draginput
|
Drag an element to another element or explicit viewport coordinates using pointer events.drag
<source> <target|x:N,y:N>
|
source *: target, destination *: string | Modifies page/input state |
{"source": "css:body", "destination": "css:main"}
|
waitnavigation
|
Wait until text, CSS, visibility, URL, disappearance, or a JavaScript condition is satisfied.wait
<text|css|visible|url|gone|js> <value> [seconds]
|
condition *: string, value *: string, seconds: integer | Navigation/wait; may change page |
{"condition": "visible", "value": "Example"}
|
navigatenavigation
|
Navigate the active tab and report the observed URL/title/readiness. Use verification primitives for
application-state guarantees.navigate <url>
|
url *: string | Navigation/wait; may change page |
{"url": "https://example.com/"}
|
tab-historynavigation
|
Move the active tab backward or forward in its navigation history.tab-history
<back|forward>
|
direction *: string | Navigation/wait; may change page |
{"direction": "back"}
|
wait-forverify
|
Wait with a finite deadline for an explicit page or target condition and return the observed
evidence.wait-for <exists|visible|hidden|text|url|title|image-ready> <value>
[seconds]
|
condition *: string, value *: string, seconds: integer | Read-only assertion or wait |
{"condition": "visible", "value": "Example"}
|
assert-urlverify
|
Require the current page URL to match the expected value before dependent work continues.assert-url
<expected> [exact|contains]
|
expected *: string, match: string | Read-only assertion or wait |
{"expected": "https://example.com/"}
|
assert-titleverify
|
Require the current document title to match the expected value.assert-title <expected>
[exact|contains]
|
expected *: string, match: string | Read-only assertion or wait |
{"expected": "https://example.com/"}
|
assert-visibleverify
|
Require a target to exist and be visibly rendered, returning geometry as evidence.assert-visible
<target>
|
target *: target | Read-only assertion or wait |
{"target": "css:body"}
|
assert-textverify
|
Require a target's current text to match an expected value.assert-text <target>
<text> [exact|contains]
|
target *: target, text *: string, match: string | Read-only assertion or wait |
{"target": "css:body", "text": "Example"}
|
assert-image-readyverify
|
Require a visible image to be complete with nonzero natural dimensions before capture or downstream
use.assert-image-ready <target>
|
target *: target | Read-only assertion or wait |
{"target": "css:body"}
|
snapshot-interactiveinspect
|
Return visible interactive elements with document-scoped refs, optionally bounded and paged by result limit and
offset.snapshot-interactive [limit] [offset]
|
limit: integer, offset: integer | Read-only observation |
{}
|
find-interactiveinspect
|
Search visible interactive elements by semantic name, rank useful matches in the browser, and return a bounded,
pageable result set with document-scoped refs.find-interactive <query> [limit]
[offset]
|
query *: string, limit: integer, offset: integer | Read-only observation |
{"query": "Example"}
|
read-pageinspect
|
Return the active page title, URL, headings, and main readable text.read-page
|
None | Read-only observation |
{}
|
inspect-inputsinspect
|
List visible form controls with type, label, placeholder, name, value, and checked
state.inspect-inputs
|
None | Read-only observation |
{}
|
inspect-elementsinspect
|
Inspect up to 100 visible elements matching a CSS selector with text, attributes, and
geometry.inspect-elements [css]
|
css: string | Read-only observation |
{}
|
element-infoinspect
|
Return detailed content, attributes, state, geometry, and computed style for one
target.element-info <target>
|
target *: target | Read-only observation |
{"target": "css:body"}
|
scrollinspect
|
Scroll the page by direction or bring a target element into the center of the viewport.scroll
[down|up|top|bottom|target]
|
destination: string | Read-only observation |
{}
|
query-selectorinspect
|
Return matching DOM elements for a CSS selector with text, HTML, visibility, and
geometry.query-selector <css>
|
css *: string | Read-only observation |
{"css": "body"}
|
get-elementinspect
|
Return the text, outer HTML, or both for a single target element.get-element <target>
[text|html|both]
|
target *: target, mode: string | Read-only observation |
{"target": "css:body"}
|
accessibility-treeinspect
|
Return a compact view of non-ignored nodes from the page accessibility tree.accessibility-tree
[max]
|
max: integer | Read-only observation |
{}
|
inspect-linksinspect
|
List visible links with normalized visible text and resolved URLs.inspect-links
|
None | Read-only observation |
{}
|
inspect-imagesinspect
|
Inspect images with DOM-backed page-order refs, source, visibility, load completion, natural dimensions, and
rendered dimensions.inspect-images
|
None | Read-only observation |
{}
|
tabstabs
|
List browser page targets by stable logical label, with title, URL, and low-level target ID as
diagnostics.tabs
|
None | May change/close targets |
{}
|
switch-tabtabs
|
Activate and attach to a tab by logical label, with target ID/title/URL matching retained for
compatibility.switch-tab <label|id|title|url>
|
query *: string | May change/close targets |
{"query": "Example"}
|
close-tabtabs
|
Close the active tab and reattach the session to a remaining page target when
available.close-tab
|
None | May change/close targets |
{}
|
open-in-new-tabtabs
|
Open the link or image URL represented by a target in a new active tab.open-in-new-tab
<target>
|
target *: target | May change/close targets |
{"target": "css:body"}
|
uploadfiles
|
Set a local file on a targeted HTML file input using the DOM protocol.upload <target>
<file>
|
target *: target, file *: string | Reads and uploads local file |
{"target": "css:body", "file":
"/path/to/authorized-file.txt"}
|
cookiesstorage
|
List browser cookies applicable to the active page URL or an explicitly supplied URL, including HttpOnly
cookies.cookies [url]
|
url: string | Reads or changes browser storage |
{}
|
set-cookiestorage
|
Set one browser cookie through CDP. The cookie object requires name/value and may include url, domain, path,
secure, httpOnly, sameSite, and expires.set-cookie <cookie-json>
|
cookie *: object | Reads or changes browser storage |
{"cookie": {"name": "example", "value": "redacted",
"url": "https://example.com/"}}
|
delete-cookiestorage
|
Delete cookies matching a selector object. The selector requires name and may include url, domain, and
path.delete-cookie <selector-json>
|
selector *: object | Reads or changes browser storage |
{"selector": {"name": "example", "url":
"https://example.com/"}}
|
clear-cookiesstorage
|
Delete all cookies applicable to the active page URL or an explicitly supplied URL without clearing unrelated
browser cookies.clear-cookies [url]
|
url: string | Reads or changes browser storage |
{}
|
storage-liststorage
|
List key/value entries from localStorage or sessionStorage for the active page origin.storage-list
<local|session>
|
area *: string | Reads or changes browser storage |
{"area": "local"}
|
storage-getstorage
|
Read one localStorage or sessionStorage key for the active page origin.storage-get
<local|session> <key>
|
area *: string, key *: string | Reads or changes browser storage |
{"area": "local", "key": "name"}
|
storage-setstorage
|
Set one localStorage or sessionStorage key for the active page origin.storage-set
<local|session> <key> <value>
|
area *: string, key *: string, value *: string | Reads or changes browser storage |
{"area": "local", "key": "name", "value":
"Example"}
|
storage-removestorage
|
Remove one localStorage or sessionStorage key for the active page origin.storage-remove
<local|session> <key>
|
area *: string, key *: string | Reads or changes browser storage |
{"area": "local", "key": "name"}
|
storage-clearstorage
|
Clear localStorage or sessionStorage for the active page origin.storage-clear
<local|session>
|
area *: string | Reads or changes browser storage |
{"area": "local"}
|
highlightvisual
|
Draw a Jelly-owned non-interactive halo over a visible target without modifying the target element itself. Auto
mode uses rendered text fragments for text-centric elements and a shape halo for controls; content forces
text-fragment geometry; box preserves the rectangular outline. The highlight follows the element until cleared
or navigation replaces the document.highlight <target> [label]
[auto|content|box]
|
target *: target, label: string, mode: string | Adds/removes overlay |
{"target": "css:body"}
|
clear-highlightvisual
|
Remove the active Jelly visual highlight from the current page.clear-highlight
|
None | Adds/removes overlay |
{}
|
evaluate-jsscript
|
Evaluate a JavaScript expression in the active page and return its by-value result.evaluate-js
<expression>
|
expression *: string | Executes page JavaScript |
{"expression": "document.title"}
|
inject-jsscript
|
Execute a JavaScript body now, optionally persisting it across jelly navigations.inject-js
[--persistent] [--file path | <script>]
|
script *: string | Executes page JavaScript |
{"script": "document.title"}
|
Examples show argument types and request structure. Replace targets, URLs and paths
with real runtime values; consult tools/list for exact active input/output schemas and constraints.
cdp-call | privileged raw protocol
calls: required array, 1–64 items. Each item requires scope: "target" | "browser" and
call: {method: "Domain.command", params?: object}; target scope optionally accepts a logical
target. on_error: "stop" | "continue" defaults to stop.
jelly scope; raw CDP enabled by operator.
invalid_arguments, browser_unavailable, cdp_failed.
{"calls":[{"scope":"browser","call":{"method":"Target.getTargets","params":{}}}]}