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 whoamiEvery 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
| Command | Purpose | Scope needed |
|---|---|---|
login / whoami | Save / inspect current config | — |
scrape <url> | Scrape one page | tools.execute |
extract <url> --schema ... | Pull structured data out of a page | tools.execute |
crawl <url> / results <job-id> | Chained crawl (async) and fetching results | tools.execute |
define <kind> <name> --file | Register a fetcher / extractor / handler | tools.define |
publish <kind> <name> | Publish (draft → published) | tools.publish |
site … | Result-page subdomain: enable / disable / revoke | admin |
bindings get|set | Agent kv / db / storage switches | admin |
token list|create|revoke | Token management | admin |
project list|create|delete | Project management | admin |
jobs list|watch|show|output | Execution records | tools.read |
budget / audit list | Usage / audit trail | tools.read |
call <tool> <args-json> | Escape hatch: call any tool directly | depends 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 livePublishing 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.jsonjobs 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— success1— the operation failed: rejected by the server, or an argument didn't validate (unknown scope, a--kvvalue that isn't on/off, and so on)2— not logged in yet, or theargspassed tocallweren't valid JSON
Scripts can branch on these instead of grepping output text.