Jelly / Developer documentation

See Jelly in action

From a single browser tool to a complete checked workflow. Start with a simple MCP request, then see how Jelly routines connect several steps and verify the result.

What kind of example do you need?

An MCP tool performs a particular operation, such as reading the current page. A routine links operations into a reusable workflow with checks, retries, and optional human approval. You can call both from an AI client connected to Jelly.

START SMALL

Discover browser tools

See how an AI client asks Jelly what browser operations it supports, without opening Chromium.

View tool discovery →

BROWSER ACTION

Open and read a page

Open an example website and request its current content through MCP.

View page reading →

MULTI-STEP WORKFLOW

Verify and capture a page

Use an existing routine to open a page, check that it is right, and verify a screenshot.

View routine examples →

Before running commands: set up Jelly using Getting Started. The commands below act on your actual local server and browser; they are not a simulated demo.

Example 1: Ask Jelly what it can do

Objective: Confirm authenticated MCP access and list semantic capability categories. Setup: Start Jelly and load JELLY_MCP_TOKEN from the local .env file. No Chromium process is needed for this stateless tool.

source ./scripts/lib/config.sh
jelly_load_env
curl --fail --silent --show-error http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $JELLY_MCP_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"browser-schema","arguments":{"action":"capabilities"}}}'

What you should see: A successful JSON-RPC response that lists browser capability categories. Your running Jelly version determines the actual result.

Show the detailed example response (source-derived, not a live run)

Source-derived output excerpt: The counts and category descriptions below are derived from the checked-in Rust primitive registry; this is not a recorded live MCP response. The transport's additional result.content field is omitted to keep the example readable.

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": {
      "ok": true,
      "data": {
        "schema_version": 1,
        "action": "capabilities",
        "operation_count": 47,
        "categories": [
          {
            "name": "input",
            "description": "Interact with page controls through clicks, typing, keys, selection, checks, dialogs, and drag-and-drop.",
            "operation_count": 8
          },
          {
            "name": "navigation",
            "description": "Navigate documents, wait for browser conditions, and move through page history.",
            "operation_count": 3
          },
          {
            "name": "inspect",
            "description": "Observe page content, elements, controls, links, images, layout, and accessibility state.",
            "operation_count": 12
          },
          {
            "name": "verify",
            "description": "Establish explicit browser-state predicates and wait for bounded conditions before dependent actions run.",
            "operation_count": 6
          },
          {
            "name": "tabs",
            "description": "List, open, switch, and close browser tabs while preserving the active session.",
            "operation_count": 4
          },
          {
            "name": "files",
            "description": "Move local files into browser-controlled file inputs.",
            "operation_count": 1
          },
          {
            "name": "script",
            "description": "Evaluate or inject JavaScript as an explicit browser-page escape hatch.",
            "operation_count": 2
          },
          {
            "name": "visual",
            "description": "Add or remove non-interactive visual annotations from browser-rendered content.",
            "operation_count": 2
          },
          {
            "name": "storage",
            "description": "Inspect and mutate browser cookies plus active-origin localStorage and sessionStorage without page JavaScript.",
            "operation_count": 9
          }
        ]
      },
      "error": null,
      "meta": {
        "tool": "browser-schema"
      }
    },
    "isError": false
  }
}

Note: The 47-operation inventory above matches this checkout; a rebuilt server may publish a different catalog. Inspect the actual JSON-RPC result instead of relying on a static count. A failed authentication produces HTTP 401.

Example 2: Open a page and read it

Objective: Read content from a running Chromium page. Setup: After the server and token are configured, start the browser using the system MCP tool. First load the token in your terminal as shown in Example 1. Opening a page changes the shared browser's active page:

curl --fail --silent --show-error http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $JELLY_MCP_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"open-browser","arguments":{"url":"https://example.com"}}}'

Then call browser-call with a single ordered semantic operation:

curl --fail --silent --show-error http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $JELLY_MCP_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"browser-call","arguments":{"calls":[{"call":{"jelly":"read-page","params":{}}}]}}}'

Expected result: A JSON-RPC result containing structuredContent.ok: true and per-call data if Chromium opened and the page was read. The exact page text and JSON payload depend on Chromium and the network. Results vary with page state and network conditions; inspect the actual response and use browser-schema to verify operation arguments.

The browser session is shared. Only call close-browser when you intend to stop it for every connected client. A failed browser launch returns a structured error (such as browser_unavailable).

Example 3: Run a routine that checks its work

What is a routine? Once an AI has verified a repeatable workflow, Jelly can save it as a named, described JSON graph. Instead of rediscovering the steps next time, call the saved routine with new variables. It can branch on conditions, loop with budgets, verify results, call other routines, or pause for human input.

Jelly already includes verified-screenshot.json, so you do not need to write a workflow file for your first test. Here is what it does:

  1. Open the requested website in Chromium.
  2. Verify that the URL matches and the target is visible, waiting when appropriate.
  3. Capture a screenshot and verify the resulting artifact.
  4. Finish successfully only when the checks pass; otherwise report failure.

Try it: In a dedicated Jelly checkout with Chromium available, run:

cargo run --quiet --bin agent-run -- \
  call-routine verified-screenshot \
  url=https://example.com/ \
  target=css:body

Expected outcome: The routine reports verified screenshot captured and registers the screenshot artifact. If the URL or target verification fails, it does not call the screenshot proof of success. The trailing slash in https://example.com/ matters because the routine checks for an exact URL. It opens and changes a real browser session; do not run it during another user's workflow.

Call the same routine through an MCP client (JSON example)

An AI client can call the MCP system tool call-routine. After loading JELLY_MCP_TOKEN as in Example 1, send this authenticated request:

curl --fail --silent --show-error http://127.0.0.1:8787/mcp \
  -H "Authorization: Bearer $JELLY_MCP_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"call-routine","arguments":{"name":"verified-screenshot","vars":{"url":"https://example.com/","target":"css:body"}}}}'

The MCP tool returns a structured response with the routine result. Inspect the actual result; a valid request is not proof that a browser operation succeeded.

Save a workflow for next time

Jelly's call-routine MCP tool accepts action: "save" and a generated JSON graph with a name, description, steps, and error paths. Saving only validates and stores the graph; it does not execute it. The agent can later list or describe saved routines before calling one by name. Existing routines can be chained together with variables. See how to generate and save a routine →

What else can routines do?

FILES AND EVIDENCE

Verify a download

The bundled verified-download routine checks the page and download trigger, performs the click, waits for the download, and verifies the file artifact.

HUMAN APPROVAL AND RECOVERY

Pause, resume, and retry

Graph routines can branch on failures, retry bounded steps, or pause for a human. A suspended routine returns a resume ID, which can be used to continue its saved workflow.

See the download routine command (template, requires a real download page)
cargo run --quiet --bin agent-run -- \
  call-routine verified-download \
  url=https://your-download-site.example/downloads \
  target=css:a.download

This command is a template, not a runnable public example. Replace the URL and selector with a real page containing a download link. It fails if the download or artifact verification fails.

Want to build your own workflow? Read the Routines guide for the actual JSON graph format, branching rules, timeouts, and human-in-the-loop suspension/resumption. See the call-routine API reference for exact MCP parameters.

Example 4: Watch Jelly operate a browser

Jelly doesn't just automate the browser. It shows its work, capturing and captioning every move as it happens. The recording below illustrates real browser interaction; it is not a recorded execution of the screenshot or download routines above.

Limitations: Real sites may require authentication, and actions can have side effects. Do not submit purchases or change accounts without consent. See the Tools reference for parameters and the Routines guide for multi-step workflow definitions.