CLI reference

The exray command line — drive exray directly, without an agent.

How it relates to MCP: for everyday scraping you just talk to your agent (see Quickstart). The CLI covers what agents can't or shouldn't do: issuing tokens, enabling result pages, toggling bindings, and scripting registration and publishing in CI.

The design rule is CLI-first: every configuration, debugging and run action is available from the command line. The dashboard is read-only.

Install and log in

The CLI currently ships with the repository (not yet published to npm). From inside the repo:

pnpm --filter @exray/cli exec tsx src/index.ts <command>

Log in once; config is stored at ~/.exray/config.json:

exray login --url https://mcp.exray.dev --token exr_<id>_<secret>
exray whoami

Every command accepts --config <path> to point at a different config file — use it in CI or when switching environments, instead of repeatedly overwriting the default.

Commands

CommandPurposeScope needed
login / whoamiSave / inspect current config
scrape <url>Scrape one pagetools.execute
extract <url> --schema ...Pull structured data out of a pagetools.execute
crawl <url> / results <job-id>Chained crawl (async) and fetching resultstools.execute
define <kind> <name> --fileRegister a fetcher / extractor / handlertools.define
publish <kind> <name>Publish (draft → published)tools.publish
site …Result-page subdomain: enable / disable / revokeadmin
bindings get|setAgent kv / db / storage switchesadmin
token list|create|revokeToken managementadmin
project list|create|deleteProject managementadmin
jobs list|watch|show|outputExecution recordstools.read
budget / audit listUsage / audit trailtools.read
call <tool> <args-json>Escape hatch: call any tool directlydepends on tool

A complete chain

From a local TypeScript file to a publicly reachable result page:

exray define handler mysite --file ./site.ts
exray publish handler mysite      # tells you what the result page still needs
exray site enable                 # enable the subdomain
exray publish handler mysite      # publish again — now it says it's live

Publishing a handler prints what the result page still needs. Publishing successfully does not mean the page is reachable: a username, an enabled subdomain and a short-enough slug all have to line up. The server works out which one is missing, and the CLI tells you directly.

Things that trip people up

define takes only the three code assets: fetcher, extractor, handler. A crawl definition is configuration rather than source, so it goes through exray call define_crawl '<json>'.

Freshly registered assets are draft and cannot run. They only become executable after publish.

token create requires an explicit --scope — there is no default. That's deliberate: defaulting to some set of "common" scopes hands out credentials with more power than intended, and the plaintext is shown only once, so it's hard to audit afterwards.

Omitting the project slug only auto-selects when you have exactly one project. With more than one, the CLI lists them and asks. Guessing wrong would mean enabling a subdomain on the wrong project.

--schema accepts inline JSON or a file path, decided by whether it parses as a JSON object:

exray extract https://example.com --schema '{"title":"string"}'
exray extract https://example.com --schema ./schema.json

jobs watch is not a log stream. It polls job status on an interval and prints only rows that changed. exray currently has no log-streaming endpoint — ctx.log output from agent code lands in job records, not in a subscribable stream. That's also why there is no exray tail: a command that doesn't do what its name promises is worse than no command.

Exit codes

  • 0 — success
  • 1 — the operation failed: rejected by the server, or an argument didn't validate (unknown scope, a --kv value that isn't on/off, and so on)
  • 2 — not logged in yet, or the args passed to call weren't valid JSON

Scripts can branch on these instead of grepping output text.