Skip to main content
Glama

Jev Browser

CI License: MIT

Fast and very cheap browser use using TypeSafe's Jev model.

Give jev-browser a task and a URL.

It drives a real headless browser through an MCP server, CLI, or library. TypeSafe's Jev model picks one action per step from the page's clickable, typeable, and selectable elements, and scores how likely it is that the goal is met or the run is stuck. Code owns the loop: budgets, recovery, stop gates. You get the final page, a step trace with confidences, console errors, and a screenshot.

Things it has done on real sites, not demos:

  • Navigated Wikipedia from the Coffee article to Espresso in about 4 seconds, for $0.0016.

  • Filled a contact form and stopped without submitting it.

  • Pulled the price off a live pricing page.

  • Returned a full guide page as markdown.

  • Produced an accessibility-tree breakdown of a WordPress site.

This is early software. Expect rough edges on harder sites. Issues and pull requests are welcome; see CONTRIBUTING.md.

Install

Requires Node.js 20 or newer, a TypeSafe API key from console.typesafe.ai/settings/keys, and optionally a key for a typing provider (see the typing model). Playwright's Chromium downloads automatically on install; set JEV_BROWSER_SKIP_BROWSER_DOWNLOAD=1 to opt out.

Let an agent install it for you

Paste this into your coding agent:

Install the Jev Browser MCP server for me. The package is @jkudish/jev-browser on npm and the server
command is `npx -y @jkudish/jev-browser`; register it as an MCP server with your client. Check whether
TYPESAFE_API_KEY is already set in the server environment; if not, walk me through setting it up without
pasting the key into the chat (I can create one at console.typesafe.ai/settings/keys). When it's
registered, ask if I'd like to run a first navigation task, and when we do, show me the step trace and cost.
Full instructions: https://github.com/jkudish/jev-browser#readme

From npm:

npx -y @jkudish/jev-browser --help

Amp

amp mcp add jev-browser -- npx -y @jkudish/jev-browser

Claude Code

claude mcp add jev-browser -- npx -y @jkudish/jev-browser

Codex (~/.codex/config.toml)

[mcp_servers.jev-browser]
command = "npx"
args = ["-y", "@jkudish/jev-browser"]

OpenCode (opencode.json)

{
  "mcp": {
    "jev-browser": {
      "type": "local",
      "command": ["npx", "-y", "@jkudish/jev-browser"],
      "environment": { "TYPESAFE_API_KEY": "ts_..." }
    }
  }
}

Any other MCP client

{
  "mcpServers": {
    "jev-browser": {
      "command": "npx",
      "args": ["-y", "@jkudish/jev-browser"],
      "env": { "TYPESAFE_API_KEY": "ts_..." }
    }
  }
}

Some MCP clients filter the environment before spawning servers, which silently drops TYPESAFE_API_KEY. If the server reports a missing key, pass it explicitly as shown above.

Related MCP server: Web Bridge

The tool

Every run makes paid TypeSafe API calls, typically a fraction of a cent, plus one small LLM call per typed field when a typing provider is configured. The example below is a real run.

// arguments
{
  "task": "Search Wikipedia for the espresso-based drink called Ristretto and stop when you are on that article",
  "start_url": "https://en.wikipedia.org/wiki/Main_Page"
}
// live result, abridged
{
  "status": "done",
  "final_url": "https://en.wikipedia.org/wiki/Ristretto",
  "elapsed_ms": 5894,
  "steps": [
    { "step": 1, "proposed_action": "click_e2", "executed_action": "click_e2", "detail": "a \"Search Wikipedia [f]\" -> /wiki/Special:Search", "confidence": 1.0 },
    { "step": 2, "proposed_action": "type_e1", "executed_action": "type_e1", "detail": "typed \"Ristretto\" via openrouter", "confidence": 0.99 },
    { "step": 3, "proposed_action": "done", "executed_action": null, "detail": "done proposed; not executed", "confidence": 1.0 }
  ],
  "usage": { "jev_calls": 3, "input_tokens": 45810, "est_cost_usd": 0.0021 }
}

Parameters: max_steps (default 24), max_seconds (default 180), allow_typing (default true), format (text, markdown, html, aria), max_chars (override the cap), screenshot (final, default, or none).

What you get back

The final page, in the format you ask for. Every payload reports truncated and true_length, and max_chars overrides any default.

Format

Default cap

Best for

text

8,000 chars

Feeding the page to Jev or an LLM next; quick reads

markdown

16,000 chars

Readable artifacts and notes; carries navigation chrome

html

1 MB

Parsing the page yourself with your own selectors

aria

16,000 chars

The accessibility tree as YAML; what screen readers and agents see

A final screenshot. A viewport JPEG that renders inline in MCP clients, or lands as a file with the CLI's --screenshot path.jpg. Pass screenshot: "none" to skip it.

A debug trace you can audit. One record per step: the proposed action versus the action actually executed, why a recovery fired, action errors, the Choice confidence, the top option's probability, and the goal and stuck probabilities for that step. Stop statuses say which gate fired. Alongside the trace: console errors, page errors, and failed network requests captured per step and tagged with the page they came from, up to 200 events, plus Jev call counts, token usage, and estimated cost. If the final payload or screenshot could not be extracted, the run still returns and lists the problem under extraction_problems.

How it decides

Each step makes one primary Jev call with three questions over the same state: an action Choice over the page's interactive elements plus scroll/back/done, a goal Noul, and a stuck Noul (fan-out pattern). The state includes a short excerpt of the page's visible text, so the goal judgment can see content, not just URLs and links. A select action adds one second-stage Choice for its option. Elements come from the DOM directly, not the accessibility tree, because accessibility trees under-report inputs; the agent found DuckDuckGo's search box only after this switch. Actions: click, type, select a native dropdown, scroll, back, done.

Stop conditions, in code, checked before executing the step's proposed action: the agent chooses done, goal probability > 0.85, stuck probability > 0.85, the step budget, or the time budget. A repeated action with no effect switches to the next-best option from the Choice distribution. There is deliberately no low-confidence override: split probability across several similar elements is usually several acceptable alternatives, not uncertainty.

Statuses: done (agent chose to stop), goal_achieved (the goal watcher fired), stuck, max_steps, timeout, error. done and goal_achieved are two independent judgments; agreement between them is what a trustworthy finish looks like, and the trace shows both at every step.

The typing model

Jev never generates text. It returns typed decisions only: which option, with what probabilities. So when a task needs a string, typing a search query or filling a field, that string comes from a small model you choose. This is the only place a second model is involved, and it runs at most once or twice per task, about 48 tokens per call.

Configuration is automatic when possible. The server picks the first provider whose key it recognizes, in this order:

Provider

Recognized by

Default model

OpenAI

OPENAI_API_KEY starting with sk-

gpt-5.6-luna

OpenRouter

OPENROUTER_API_KEY starting with sk-or-

openai/gpt-5.6-luna

Anthropic

ANTHROPIC_API_KEY starting with sk-ant-

claude-haiku-4.5

Google

GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY starting with AIza

gemini-2.5-flash

Overrides:

  • JEV_BROWSER_TYPE_MODEL picks any model the resolved provider offers, for example openrouter:anthropic/claude-haiku-4.5 style ids.

  • JEV_BROWSER_TYPE_PROVIDER forces one of openai, openrouter, anthropic, google, skipping auto-detection.

  • JEV_BROWSER_TYPE_BASE_URL (plus JEV_BROWSER_TYPE_API_KEY if it needs one) points at any OpenAI-compatible endpoint: Ollama, LM Studio, vLLM, a gateway. This wins over provider detection.

Local example, no cloud key at all:

JEV_BROWSER_TYPE_BASE_URL=http://localhost:11434/v1 JEV_BROWSER_TYPE_MODEL=qwen2.5:7b \
  npx -y @jkudish/jev-browser run "Search Wikipedia for Ristretto and stop on the article" https://en.wikipedia.org/wiki/Main_Page

With no provider at all, typing falls back to a keyword heuristic built from the task text. It is labeled honestly in the trace (via keyword-heuristic), and it is meaningfully worse: in testing its queries buried a target article eight results pages deep. Give it a real model if your tasks type anything.

Limits

  • Up to 240 elements per step; Jev's Choice supports 255 options. Beyond that the list is truncated and the state says so, which can hide the needed element on very dense pages.

  • The markdown format converts the whole body, so it carries navigation chrome and can include inline script text; a readability pass is a candidate improvement, not a committed one.

  • Password and file inputs are never offered. Hover-revealed menus, keyboard actions (Escape, Enter on unstaged fields), multi-field form sequencing, shadow DOM, and iframes are out of scope for v0.1.

  • Thresholds (0.85 goal, 0.85 stuck, budgets) are starting points measured on Wikipedia and DuckDuckGo tasks. Tune them for your sites.

  • Jev is calibrated, not infallible. Treat the trace as evidence, not proof.

Configuration

Env var

Default

Purpose

TYPESAFE_API_KEY

none

TypeSafe direct. Default provider when set.

OPENROUTER_API_KEY

none

Powers both the Jev judgments (when TYPESAFE_API_KEY is absent) and, optionally, the typing model. One key runs everything.

JEV_PROVIDER

auto

Force typesafe or openrouter for the Jev calls instead of auto-detection.

JEV_BROWSER_MODEL

jev-latest

Pin a Jev version, or typesafe/jev-1.13 on OpenRouter.

JEV_BROWSER_TYPE_*

see above

Typing provider, model, and endpoint.

JEV_BROWSER_HEADED

unset

Set to 1 to watch the browser.

JEV_BROWSER_SKIP_BROWSER_DOWNLOAD

unset

Set to 1 to skip the Chromium postinstall.

OpenRouter

With only an OPENROUTER_API_KEY, both the Jev judgments and (with no other typing provider) the typing model run through OpenRouter: one key powers the whole package. The Jev endpoint there is alpha and adds a hop, and it serves pinned versions rather than a latest alias, so jev-latest maps to typesafe/jev-1.13. Direct TypeSafe remains the recommended default when you have both keys.

Also in the family

Need the judgments without the browser? Jev MCP exposes the same model as three tools your agent can call anywhere: verify claims against evidence, screen content before it enters context, and rank candidates by meaning. The npm package is @jkudish/jev-mcp.

Sponsoring

If you find Jev Browser useful, consider becoming a sponsor or donating.

Development

npm install
npm run build
npm test            # unit tests, offline
npm run test:e2e    # live navigation tests; requires TYPESAFE_API_KEY

See CONTRIBUTING.md. To report a vulnerability, see SECURITY.md.

License

MIT

Available Tools

1 tool
jev_navigateNavigate a browser with JevA

Give a task and a start URL; a Jev-driven agent navigates a real headless browser until the goal is met, the stuck gate fires, or a budget (steps/seconds) is exhausted. Returns the final page in a chosen format (text, markdown, html, or an aria snapshot), the full step trace with confidences, console/page/network errors captured along the way, token usage with estimated cost, and a final screenshot.

ParametersJSON Schema
NameRequiredDescriptionDefault
taskYesWhat the agent should accomplish, in natural language.
formatNoFinal page payload format: text (default, 8k chars), markdown (16k, via turndown), html (1MB, for app-side parsing), aria (16k, Playwright aria snapshot YAML).
max_charsNoOverride the format's default character cap.
max_stepsNoHard step cap. Default 24.
start_urlYesWhere to start.
screenshotNoFinal viewport JPEG. Default 'final'.
max_secondsNoWall-clock cap in seconds. Default 180.
allow_typingNoWhether the agent may type into fields (uses the configured small model, or a keyword fallback). Default true.

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It reveals stopping conditions (goal met, stuck gate, budget exhaustion), and lists returns (final page, step trace, errors, token usage, screenshot). However, it does not mention that the agent may interact with the page (e.g., typing, clicking) as indicated by the allow_typing parameter, which is a side effect. It also doesn't explicitly state that this is a potentially long-running or costly operation, though it mentions budgets and token usage. This partial disclosure merits a 3.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single long sentence but is packed with essential information: it front-loads the core purpose and then enumerates return values. It is not verbose and every clause adds value, though the sentence is somewhat run-on. Slightly better formatting could improve readability, but it is appropriately concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 8 parameters, no output schema, and no annotations, the description covers the key behavioral aspects: stopping conditions, return payloads, and error capturing. It does not detail the structure of the step trace or token usage report, but the schema covers parameter details. Overall, it gives enough context for an agent to understand what will happen and what it will receive, though a bit more on side effects would push it to 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents all 8 parameters, including formats, defaults, and constraints. The description adds no extra semantic value beyond what the schema provides, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'a Jev-driven agent navigates a real headless browser until the goal is met...' It specifies the verb (navigate), the resource (real headless browser), and the stopping conditions, making it unambiguous what the tool does. Since there are no sibling tools, differentiation is not required, but the description is specific enough to stand alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: 'Give a task and a start URL' clearly indicates the intended invocation. It does not explicitly state when not to use it or list alternatives, but with no sibling tools, this is acceptable. The context of browser automation is evident from the description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.2.0
    • First observedjev_navigate

TDQS

A3.9/5.0

Scored across 1 tool

Disambiguation5/5

With only a single tool, there is no possibility of confusion between different tools. The tool's purpose is clear and distinct, and an agent can easily select it for any browser navigation task.

Naming Consistency5/5

There is only one tool name, 'jev_navigate', which follows a clean verb_noun pattern. Since there are no other tools to compare against, naming is inherently consistent.

Tool Count3/5

A single tool is on the thin side for a browser server, but the tool is comprehensive, handling navigation, tracing, error capture, and screenshot generation. It is borderline but acceptable for a focused high-level automation agent.

Completeness3/5

The tool covers the core navigation workflow and returns extensive diagnostic data, but it lacks granular browser operations like clicking, typing, or extracting specific elements. Agents requiring fine-grained control would need to rely entirely on this one high-level action, which is a notable gap.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    MCP server + Chrome extension that drive the user's real, logged-in Chrome over a local WebSocket. 59 token-efficient web-dev tools: compact element refs instead of screenshots, server-side table filtering, visual regression, accessibility/SEO/security audits, network mocking. Also runs on ChromeOS/Crostini.
    59
    206 npm
    3
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Browser automation MCP server that uses a real browser to give agents eyes and hands—open pages, click, fill, screenshot, and run scripts via accessibility-tree snapshots.
    22
    30 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP clients to call TypeSafe's JEV classifier and receive structured, typed judgments with probabilities for binary, choice, and scoring questions.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables natural-language interaction with TypeSafe's Jev decision API, supporting mixed question calls, batch evaluation, model listing, and confidence or composite-score gates over stdio.
    3
    MIT