# Ora Ax

> Score any site's agent readiness from your terminal or CI. The open-source CLI for ora.

- **Type:** MCP server
- **Install:** `agentstack add mcp-ora-ax`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [ora](https://agentstack.voostack.com/s/ora)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ora](https://github.com/ora)
- **Source:** https://github.com/ora/ax
- **Website:** https://ora.ai/docs#cli

## Install

```sh
agentstack add mcp-ora-ax
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

ax

Score any site's agent readiness from your terminal or CI — and watch real AI agents navigate it.The open-source CLI for ora.

  
  
  
  
  

```
npx ax audit https://stripe.com
```

**No account, no API key.** Everything below works out of the box — the one exception is [`journey`](#for-ora-partners), which drives ora's partner platform.

  

Five commands:

- **`audit `** — run ora's hosted agent-readiness audit against a site: live progress, then a layered report of what passed, what's broken, and ora's ranked list of the highest-impact fixes (or `--json` for the raw contract payload). No account or API key needed. Gate CI with `--min-score`.
- **`webmcp-audit `** — audit a page's `document.modelContext` tools in a real browser. Works on any http(s) URL, localhost included, so you can check a surface before you publish it. Measures the page the way ora's capture worker does and has ora score it; nothing is stored, published, or ranked.
- **`deep-journey `** — run a real AI agent at a site on one of ora's curated tasks through the public journey API: no key, no workspace. A partner API key unlocks free-text tasks (`--task`) and a larger allowance.
- **`journey ""`** — send a real AI agent (claude-code, codex, …) at a site and watch its navigation live as a boxed node-graph, then get the scored insight, tokens, and cost. Partner-only: needs an `ORA_API_KEY` (see [For ora partners](#for-ora-partners)).
- **`skill [name]`** — list, print, or install ora's agent skills, digest-verified from the public registry.

## audit

```
ax audit  [--min-score n] [--max-age s] [--force] [--tunnel-cmd c] [--api-key k] [--json] [--show-passing] [--show-skipped]
```

```
  stripe.com  78/100 B+
  Stripe offers strong developer resource discoverability, but lacks an OpenAPI specification.

  Discovery   ██████░░░░ 6/9 passed · 1 skipped
    ✗ Issues (2)
    ┌───┬──────────────┬───────────────────────────┬──────────────────────────────┐
    │   │ Check        │ What's wrong              │ How to fix                   │
    ├───┼──────────────┼───────────────────────────┼──────────────────────────────┤
    │ ✗ │ sitemap.md   │ status 404                │ Publish /sitemap.md listing… │
    ├───┼──────────────┼───────────────────────────┼──────────────────────────────┤
    │ ⚠ │ robots.txt   │ partially restricted      │ Allow AI crawlers in robots… │
    └───┴──────────────┴───────────────────────────┴──────────────────────────────┘

  Top fixes (ranked by ora)
  1. sitemap-md   ≈ +4 pts
  2. robots-txt   ≈ +1.2 pts

  cached result (43 min old) · pass --force for a fresh scan
  Full report: https://ora.ai/stripe.com
```

| Flag | Effect |
|---|---|
| `--min-score ` | Exit `1` when the score is below `n` (0-100) — the CI gate |
| `--max-age ` | Accept a cached result up to `s` seconds old (server default 6h, clamped to 1-24h) |
| `--force` | Bypass the cache and rescan — spends the stricter 6/day force budget |
| `--tunnel-cmd ` | Expose a local target through your own tunnel command and audit the public URL it prints (also read from `ORA_TUNNEL_CMD`) |
| `--api-key ` | ora-issued scan API key — lifts every scan rate limit (also read from `ORA_SCAN_API_KEY`) |
| `--json` | The raw ora audit payload on stdout, exactly as the API served it |
| `--show-passing` | List every passing check, not just the per-layer summary bar |
| `--show-skipped` | Include not-applicable/pending checks with their reason |

The **Top fixes** list is ranked by ora server-side (non-bonus fixes first, then estimated score uplift) — the CLI renders it verbatim. All `≈ +N pts` figures are estimates. Check *tiers* (required / recommended / emerging) are advisory display metadata and never determine the score.

### CI gate

```yaml
- name: Agent-readiness gate
  run: npx ax audit https://your-site.com --min-score 70
```

Exit codes are the contract:

| Code | Meaning |
|---|---|
| `0` | success (and score ≥ `--min-score` when given) |
| `1` | score below `--min-score` |
| `2` | usage error — bad flags, malformed URL, local target without a tunnel |
| `3` | API unreachable, timeout, or rate limit exhausted |

Budget notes: ora allows 30 scans + 6 `--force` scans per rolling 24h per IP (plus a 10/min burst limit). Results served from the freshness cache cost nothing, so a CI job that audits on every push stays well inside the budget — tune the window with `--max-age`, and reserve `--force` for verifying a fix you just deployed. High-volume callers can present an ora-issued scan API key (`--api-key` or `ORA_SCAN_API_KEY`), which exempts them from all of these limits; keys are issued manually by ora (no self-serve signup), and an unrecognized key silently falls back to the keyless limits rather than erroring. An auth-gated MCP target reports `mcpAuthRequired` and scores 0 as "could not evaluate"; `--min-score` deliberately skips the gate rather than failing on it.

### Auditing localhost (`--tunnel-cmd`)

A local dev server only exists on your machine, so ora can't reach it. The simplest option is to audit a publicly reachable deployment of the same code (e.g. a preview URL). To audit localhost itself, bring your own tunnel: pass `--tunnel-cmd` (or set `ORA_TUNNEL_CMD`) with a command that exposes the local server and prints its public `https://` URL. The CLI runs it, audits the URL it prints, and tears the tunnel down when done.

```
ax audit localhost:3000 --tunnel-cmd 'ngrok http 3000 --log stdout'
```

- **The CLI ships no tunnel vendor and never downloads executables at runtime** — any tunnel tool you already have works, as long as it prints its public URL to stdout or stderr.
- The result is stored as **ephemeral**: excluded from ora's rankings and deleted after a few days.
- Off-site checks (registry listings, brand search) usually fail for a throwaway tunnel hostname — the report says so. Use tunnel audits to iterate on your on-site surface, not to compare scores.
- Free tiers of some tunnel vendors serve an interstitial warning page to browser-like requests, which can distort what the scanner sees — prefer a vendor/plan that serves your origin directly.

## webmcp-audit

```
ax webmcp-audit  [--chrome-endpoint e] [--min-score n] [--api-key k] [--json] [--show-passing]
```

```bash
ax webmcp-audit http://localhost:3000
```

The dev-loop counterpart to the audit at [webmcp.ora.ai](https://webmcp.ora.ai): check the
`document.modelContext` tools your page registers *before* you ship it, and get the same answer
you will get once it is public.

Any `http(s)` URL works — a dev server, a staging host, or a site you do not own. A page with no
WebMCP surface is not an error: it comes back `absent` with the checks that cannot apply marked
`Not applicable`, which is a perfectly good way to see what the audit looks like before you have
written any tools.

**It uses a Chrome you already have.** WebMCP tools only exist inside a live page, so the audit
opens yours in a real browser. It finds your installed Chrome, starts a headless one on a throwaway
profile, and stops it when the audit finishes — nothing to set up, and this package never downloads
or bundles a browser. Set `CHROME_PATH` if yours lives somewhere unusual.

To drive a browser you started yourself, pass `--chrome-endpoint` (a `ws://` URL, an http origin,
or `host:port`) and start it with `--remote-debugging-port`. The command never attaches to a
browser you did not name — including anything already on port 9222 — because silently borrowing a
Chrome with the WebMCP flags on would score your page higher here than it scores on ora.

**Do not enable the WebMCP flags on a Chrome you point it at.** The audit asks whether a real
browser gives an agent WebMCP on your page. A Chrome started with `--enable-features=WebMCPTesting`
answers yes for every site, so a page can come back `active` here and `testing-only` on ora. The
report tells you when the browser answered for the page; where that actually moved a check, ora
annotates that check itself. Keep a flag-enabled Chrome for
[`@ora-ai/webmcp-verify`](https://www.npmjs.com/package/@ora-ai/webmcp-verify), which needs the API
present in order to call your tools.

**What it measures, and where.** The capture is local: three passes over your entry page, the same
passes and the same probe code ora's worker runs, plus a viewport screenshot at ora's 1280×720. As
ora does, it loads the page with images, media and webfonts refused — stylesheets still apply — so
the screenshot the grader sees is the one ora would have taken. That capture is
posted to ora, which runs the 16 checks, two model hops and the tool-selection simulation, and
streams back a score. The CLI scores nothing itself (design decision #1) — grade, findings,
category scores and the simulation are all rendered as ora sent them.

**Availability is a gate, not a score.** Before anything is graded, ora decides whether an
in-browser agent can use the page at all. A page that cannot comes back `not agent-ready` with the
reasons why, and no score or grade — the reasons are the answer.

Past that gate the score is four pillars — `shared-experience` (30), `task-completion` (25),
`tool-quality` (25), `trust` (20). It is **not** the 0–100 agent-readiness score from `ax audit`:
different inputs, different rubric, never comparable.

A pillar can read 0 because it earned nothing or because nothing in it could be measured; the
report marks the second case rather than leaving you to guess.

**Two check statuses mean "no score" and are not the same thing.** `Not applicable` means the check
had nothing to measure and your page is not charged for it. `Not measured` means it applied and
could not be measured — that counts against evidence coverage, and below the coverage gate ora
withholds the letter grade while still reporting the score. A withheld grade beside a real score is
normal, not an error.

**What leaves your machine.** Scoring happens on ora's side, so the capture is uploaded: the page
URL, every tool your page registers (names, descriptions, JSON Schemas, annotations), the WebMCP
evidence found in your page's own scripts, and **a 1280×720 screenshot of the page**. Point it at a
logged-in or seeded dev environment and that screenshot shows whatever was on screen. Your source
code is never read and never sent.

**Nothing is stored.** A local audit is scored and returned and then forgotten. It never reaches
the leaderboard, the badge, or your public scorecard — to appear there, publish and run the audit
on webmcp.ora.ai. Pass `--json` and pipe it to a file if you want to see exactly what was sent
back; the capture itself is what the report's header describes.

Anonymous use is rate-limited to 10/min and 20 per 24h per IP; an ora API key
(`--api-key` / `ORA_API_KEY`) lifts that.

### CI gate

```yaml
- run: npx ax webmcp-audit http://localhost:3000 --min-score 70
```

Any CI image with Chrome installed works; nothing to launch first.

Exit codes match `audit`: `0` ok · `1` below `--min-score` · `2` usage (including no debuggable
Chrome) · `3` API. The gate reads the score, not the grade — a withheld grade would otherwise let
everything through.

## deep-journey

```
ax deep-journey  [--intent id | --task text] [--agent id] [--api-key k] [--no-stream] [--json]
```

```
ax deep-journey stripe.com --intent pricing
ax deep-journey zapier.com --task "Find how to build a Slack → Sheets zap"   # needs a partner key
```

Runs a real AI agent at a site through ora's **public** journey API — no key, no workspace needed for curated tasks. The agent's trajectory streams live as progress lines; the terminal output is ora's verdict, the billable step count, and the generated insight:

```
  ✓ task satisfied  stripe.com
  14 steps · 6 turns · 41.2s

  The agent found the pricing page in two hops via llms.txt and correctly
  summarised the standard and custom tiers.
    - llms.txt was load-bearing: it linked /pricing directly
    - no web search was needed; every path came from on-site links

  For the 4-layer readiness audit, run: ax audit stripe.com
```

Anonymous callers run curated intents (`pricing`, `signup`, `api-docs`, `integrate`, `support`, …) — list them with `GET https://ora.ai/api/journey/intents`, and the accepted agents with `GET https://ora.ai/api/journey/agents`. The public caps are 100 runs per rolling 24h per target and 200 runs per 24h per IP (plus a 20/min burst limit); a target at its cap answers with the most recent stored run (`rate_limited: true`) instead of an error, so repeat CI invocations are cheap. Verdict and step count come from ora's contract as-is — the CLI never re-judges a run.

**Keyed tier:** an ora-issued partner API key (`--api-key`, or `ORA_PARTNER_API_KEY` / `ORA_SCAN_API_KEY` in the environment) unlocks `--task` — a free-text task of 4–300 characters that replaces the curated intent — and moves the caller to an allowance of 1000 runs per rolling 24h per key with no per-target cap and no burst guard. Keys are issued manually by ora (no self-serve signup). A wrong or unrecognized key with a *curated* intent silently degrades to the anonymous tier; `--task` without a recognized key is an error.

If the live stream goes quiet (no frames for 120s) the CLI does not abandon the run — it switches to polling the run detail until the server reports a terminal state.

| Flag | Effect |
|---|---|
| `--intent ` | Curated task id (server default when omitted) |
| `--task ` | Free-text task — needs a partner API key; mutually exclusive with `--intent` |
| `--api-key ` | ora partner API key; also read from `ORA_PARTNER_API_KEY` (then `ORA_SCAN_API_KEY`) |
| `--agent ` | Agent from the public roster (default: ora's pick) |
| `--no-stream` | Poll for the result instead of streaming the trajectory |
| `--json` | Print the terminal run detail (verdict, step_count, result) as JSON |

deep-journey exit codes: `0` run succeeded (any verdict) · `1` run failed · `2` usage error · `3` API unreachable / rate-limited.

This differs from `ax journey` (below), which drives the authenticated platform with free-text goals and renders the full trajectory graph; `deep-journey` is the zero-setup public path.

## skill

```
ax skill                                # list the registry
ax skill agent-ready-website            # print a SKILL.md
ax skill agent-ready-website --install  # write .claude/skills//SKILL.md
ax skill --json                         # the raw registry index
```

Skills come from ora's public registry (`https://ora.ai/.well-known/agent-skills/`) and every byte is verified against the registry's sha256 digest before it is printed or installed. Skill content is never bundled into this package. `--dir ` overrides the install directory, and `--json` prints the registry index as JSON instead of the formatted list.

## Library use

The same contract-typed client the CLI uses is importable:

```ts
import { audit } from "ax";

const { result } = await audit("stripe.com");
console.log(result.score, result.grade, result.topFixes);
```

`result` is the raw versioned audit payload (`AuditScanResult` / `AuditScoreResult`, generated from ora's OpenAPI spec). `fetchSkill` / `fetchSkillIndex` expose the digest-verified skill registry.

The public journey client is exported too — the same no-key path as `ax deep-journey`:

```ts
import { deepJourney, fetchJourneyAgents } from "ax";

const { agents, defaultId } = await fetchJourneyAgents();
const agent = agents.find((a) => a.id === defaultId)!;
const { detail } = await deepJourney("stripe.com", {
	intentId: "pricing",
	harness: agent.harness,
	model: agent.model,
});
console.log(detail.verdict, detail.step_count, detail.result?.insight.summary);
```

`detail` is the contract's `JourneyRunDetail`; `fetchJourneyIntents` lists the curated intents. The same public caps apply — a capped target resolves with the most recent stored run (`cached: true` on the outcome), not an error.

## For ora partners

Everything above runs without an account. The commands and fl

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ora](https://github.com/ora)
- **Source:** [ora/ax](https://github.com/ora/ax)
- **License:** MIT
- **Homepage:** https://ora.ai/docs#cli

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-ora-ax
- Seller: https://agentstack.voostack.com/s/ora
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
