Skip to content
Back to skills

Jev Ultrafast Mcp

ASecurity

Hand a browser task to the jev-ultrafast-mcp server instead of driving the page yourself. Use whenever a task involves a web page or a browser: filling in or submitting a form, signing in, a daily check-in, clicking through a flow, extracting something from a page, or proving a page reached a given state. Also use when the user names a URL together with an action, or says "打开这个网页", "帮我填一下", "签到", "在浏览器里点", "browser", "fill this form", "log in to", "check in on", "scrape", or "click through".

  • 14 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
ai-agentsrustgoshelldebuggingapi

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 24, 2026

npx -y skills add jiawei686/jev-ultrafast-mcp --skill jev-ultrafast-mcp --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Jev Ultrafast Mcp?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Jev Ultrafast Mcp
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jiawei686-jev-ultrafast-mcp/badge)](https://www.skillsdirectory.com/skills/jiawei686-jev-ultrafast-mcp)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: jev-ultrafast-mcp
description: >
  Hand a browser task to the jev-ultrafast-mcp server instead of driving the page
  yourself. Use whenever a task involves a web page or a browser: filling in or
  submitting a form, signing in, a daily check-in, clicking through a flow,
  extracting something from a page, or proving a page reached a given state. Also
  use when the user names a URL together with an action, or says "打开这个网页",
  "帮我填一下", "签到", "在浏览器里点", "browser", "fill this form", "log in to",
  "check in on", "scrape", or "click through".
agent_created: true
---

# Browser work goes to `browser_goal`, in one call

A browser task is handed over **whole**. The loop runs server-side, driven by a
decision model, so the page never enters your context and the task costs one
turn instead of one per click.

```
browser_goal(
  goal="…",                                             # what "done" means, in words
  url="https://…",                                      # omit to continue on the current page
  verify=[{"type": "text_contains", "text": "…"}],      # how the page proves it worked
)
```

`url` + `goal` + `verify` is a complete handoff. **Do not** open the page and
walk it yourself first — that is the thing this server exists to replace.

## Always pass `verify`

`status:` is the model's own summary; `verify` is checked by code afterwards, and
when the two disagree the assertion wins. This is not a rare edge: the ordinary
shape of a successful goal is that the last action *removes* what it acted on —
click a check-in button and the button is gone — so the model, finding nothing
left to do, reports `BLOCKED` on a goal that in fact succeeded. Without `verify`
you cannot tell that apart from a real failure.

Pick checks that are visible on the page afterwards: `text_contains`,
`element_gone`, `url_contains`, `count_at_least`.

Pick a string that exists **only after** the action. A string that is also in the
navigation or the header (a menu label, the site name) will pass before anything
happened, and a string you half-remember will fail on a goal that worked. When
`verify` fails, re-read the element table and check your string first — a wrong
assertion is far more common than a broken engine.

`text_contains` matches the page's **prose**, not the element table. A combobox's
selected value, a button's label, a tab's name exist only in the table — asserting
on them with `text_contains` fails on a page that is exactly right. Assert on
things that appear in the text: a price, a result count, a heading. So "the ticket
type is now One way" is not a `text_contains` check; "SGD 133" is.

## Reading a page is not a task

`browser_open`, `browser_observe` and `browser_assert` are direct, deterministic,
free and need no key. Use them when the user only wants to know what a page says,
or when you need to see why a goal failed. Routing a look through the model
spends money to answer a question the element table already answers.

## When to fall back to the manual loop

Exactly two cases:

1. `browser_goal` answers `turbo_unavailable:` — no model key is configured. Then
   `browser_open` → read the element table → `browser_act` → `browser_assert`.
2. You only want to look (see above).

## Recurring work: record it once, then replay for free

`browser_macro` records the path a goal discovered and replays it **with no model
calls**. Replay re-resolves each step by role + name against a fresh observation
and refuses to act when the best match is weak or ambiguous (`threshold`, default
`0.7`), so it fails loudly instead of clicking the wrong thing.

A chore that repeats *identically* is the wrong shape for `browser_goal` forever:
pay the model once, `record_stop` it, then `run` the macro on later days. `params`
fills `{{placeholders}}` in text and URLs, which is what lets one macro serve many
days or many inputs. `inspect` shows the recorded steps before you trust them.

**Replay only fits a flow whose steps are the same every time.** Judge a candidate
by whether the *labels it clicks* are stable, not by whether the task is
repetitive. A daily quiz whose question and options are new every morning is the
wrong shape and belongs on `browser_goal` — the resolver refuses rather than
guesses, so a macro there fails safely and uselessly. A check-in form whose buttons
are always in the same place replays; a quiz whose answers change does not.

## Before handing over: is there a browser at all?

`browser_doctor` reports `connection` — `idle`, `attached` or `dropped`. **`idle`
is the normal state, not a fault**: the server connects lazily, so a browser that
has not been needed yet reads `connected: false, connection: idle`. Only `dropped`
means a socket existed and died. Read `connected: false` as "nothing is listening
on the CDP URL" only when something should be listening: in `attach` mode the
server deliberately starts nothing (its own hint says "nothing is started for
you"), so `JEVMCP_CDP_URL=http://127.0.0.1:9222` can point at empty air.

Launch one yourself:

```
nohup "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --remote-debugging-port=9222 \
  --user-data-dir="$HOME/.jev-ultrafast-mcp/chrome-profile" \
  --no-first-run --no-default-browser-check about:blank &
```

- **Headed, never headless** — a headless browser cannot clear Cloudflare and will
  sit on "Just a moment…" forever.
- **Never the default profile** — Chrome 136+ refuses to open a debugging port on
  it. A dedicated `--user-data-dir` is what makes this legal.
- The login you need lives in that profile directory, so signing in once there
  makes every later handoff work.
- Do **not** type the user's password for them. If a goal sits behind a login, have
  the user sign in in that window; then hand the task over.

Two traps when supplying that browser:

- **A 404 from `/json/version` does not mean nothing is listening.** Chrome 144+'s
  `chrome://inspect/#remote-debugging` server is WebSocket-only and answers 404 to
  every `/json/*` path. The port and the browser WebSocket path are in
  `DevToolsActivePort` inside the browser's data directory, and the server reads
  them from there — so a browser started by that toggle (including the user's own
  Chrome, which is where their logins are) works fine. If the data directory is
  unusual, set `JEVMCP_ATTACH_PROFILE_DIR`.
- **One port, one browser.** Two Chromes cannot share 9222: whichever binds IPv4
  answers, and if that is the wrong one you get 404s while the good instance sits
  on `[::1]`. If a launch seems to have silently failed, check
  `lsof -nP -iTCP:9222 -sTCP:LISTEN` for *two* rows before relaunching. Also note
  `open -na "Google Chrome" --args …` can drop the arguments and start the default
  profile — verify the profile from the process's own open files rather than
  trusting the command you typed.

## `attach` costs a click per connection; `launch` costs one login

On Chrome 144+ the `chrome://inspect/#remote-debugging` server shows an
**"Allow remote debugging?" dialog for every incoming connection** — not once per
launch. Attach mode therefore asks the user to approve *every* connection, and a
reconnect **is** a connection, so anything recurring pays a click each time.

`launch` mode with a non-default `--user-data-dir` needs neither the toggle nor
any dialog (measured: launch, connect, `Browser.getVersion` in 4.6s, zero
prompts). The price is that a fresh profile is signed out once. For a recurring
job that is the better trade — sign in in that profile a single time, and every
later run is prompt-free.

Attach to the user's own Chrome only when their existing logins are the point
*and* the run is a one-off.

## Reading a failure

Two signatures that look like engine bugs but are not:

- **`status: blocked`, `steps: 0`.** The model could not find anything to act on.
  Check, in order: (1) is your `verify` string actually on the page? (2) is the
  target **in the element table**? `observe` reports `omitted N low-priority` —
  anything not in the table is invisible to the model, and a target it cannot see
  can only produce `blocked`. Both of these are correct behaviour, not failures.
  A large `omitted` count used to make this non-deterministic — the ranking put
  viewport position above role, so the same goal could reach its target once and
  report `blocked` at step 0 the next time. That is fixed (role now outranks
  position, in both `observer.js` and `policy.reachable_first`), so a repeated
  `blocked` at step 0 is a statement about your goal or your `verify`, not about
  the clock.
  The clock is no longer a candidate at all: after opening a `url` the server
  waits for the page to **stop fetching** as well as for its element table to
  stop changing before it asks the model anything (`JEVMCP_SETTLE_TIMEOUT`, 4s
  by default). An app that has not fetched its bundle yet is a shell, and a shell
  holds perfectly still — so "the table stopped changing" alone used to settle on
  a page with no controls on it and hand back `blocked` at step 0 twice on a page
  that rendered a second later. If a `blocked` at step 0 still survives that,
  raise `JEVMCP_SETTLE_TIMEOUT` before you rewrite the goal.
- **`status: stopped: no progress`.** The page stopped changing for the limit
  `browser.py` defines, so the run ended rather than spending the rest of
  `max_steps` on `WAIT`s. This is the usual shape of a goal that has *already
  succeeded* — the last action removed the thing it acted on — so read `verified`
  before you read `status`: a passing assertion upgrades this to `done`. If
  `verified` is absent or failing, the goal genuinely stalled and needs a
  different goal string, not a retry.
- **`turbo_unavailable: … TYPE_TEXT …`.** The model *did* answer — it returned a plan
  that types into a field, and the **policy layer** refused it. The optional text
  helper only affects writing a value into an input; a click-only task needs no key.
  Do not report this as "the model is unavailable".

  Which dead end it is decides the fix, so read the sentence rather than the code:
  - **Jev's own API** (`JEV_PROVIDER=typesafe`, the default) answers typed questions
    and never writes prose, so it has no chat route for the helper to inherit. Either
    give the helper its own chat provider (`TEXT_MODEL_API_KEY`, plus `TEXT_MODEL`),
    or move the decision model to `JEV_PROVIDER=openrouter` and name a chat model
    there with `TEXT_MODEL`.
  - **OpenRouter** (`JEV_PROVIDER=openrouter`) does serve chat, so with
    `OPENROUTER_API_KEY` set the helper inherits the key *and* the URL, and the only
    thing still missing is `TEXT_MODEL` — `deepseek-chat` is not an OpenRouter slug.
    A message asking for `TEXT_MODEL_API_KEY` while on OpenRouter therefore means one
    of two things: no key at all, or `TEXT_MODEL_BASE_URL` set without its key, which
    is read as the explicit route and will not borrow the decision model's key.
  - Either way **the key and the URL come from the same provider.** Borrowing a key
    across providers earns a 401 that names the company you did not call, which is a
    worse failure than the refusal it replaced. `browser_doctor` reports the resolved
    provider and whether the helper has a route.

  Workaround while no route is configured: **put the parameters in the URL**
  and let the model only wait and read. Many sites accept them, including
  natural-language queries — a flight search becomes
  `…/travel/flights?q=One way flights from SIN to PQC on 2026-09-26`, and then no
  typing is needed at all. Adding `hl=en` (or the site's locale parameter) also
  makes the page easier to read and to assert on.

Judge a handoff by `verified: PASS` **and** the final URL actually having changed —
not by `status`.

**`status: unconfirmed: …` means the model reported `done` and `verify` did not confirm it.** The
assertion wins, so treat it as unfinished — but check your own string first, because a wrong
`verify` produces the same line. Measured on a real daily check-in: the model clicked the submit
button, reported `done` twice, and moved no points either time. Note also that `done` can arrive at
`steps: 0` with the element you named not even on the page — a model that finds its target absent
says `done` about as readily as it says `blocked`, which is the whole reason `verify` is not
optional.

## Operational gotchas that waste a run

- **The page must be in a foreground tab.** A backgrounded tab is throttled by
  Chrome, and a bot check (Cloudflare's "Just a moment…") then never clears — it
  will sit there for the full timeout while the Ray ID changes every attempt.
  Set `JEVMCP_FOREGROUND=1` in the server's env.
- **The server reads its config once, at import.** After editing the MCP config
  you must restart the client (and in WorkBuddy, click **Trust** again if you
  added or removed an env *key name* — values alone do not change the approval).
- **A dropped socket is self-healing, and no longer needs a restart.** The manager
  checks liveness before each call and, on a dead socket, drops it *together with
  the sessions bound to it* (a target id exists only on the socket that minted it)
  and opens a fresh one. `doctor` shows `connection: dropped` for that case instead
  of a stale `connected: true`. If `transport closed … keepalive ping timeout`
  nevertheless stays permanent, the server predates that fix — restart it.
- **Login state lives in the browser profile**, not in the server. A task behind
  a login only works while that profile is signed in.

## Reporting

The run reports its own bill (`turbo: N decisions · N tokens · …`). Quote the
`verified: PASS/FAIL` line and the assertion details rather than the model's
summary — and if `verify` failed, say so plainly instead of reporting success.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…