Skip to content

Setting up cora-mcp

CORA’s plugin starts cora-mcp for you, as Installing the plugin describes. This page adds it to an agent by hand, as an MCP entry that runs npx --yes --prefer-offline=false --fetch-retries=0 --fetch-timeout=3000 @vispero/cora-mcp@<version>: the command the plugin’s entry runs. npx asks the registry for the version and its dependencies, even where your npm config sets prefer-offline, and starts them from npm’s cache when the registry refuses the connection or sends nothing for 3 seconds once connected, so a version that ran before starts without the network. A connection that never opens, as to a proxy npm can’t reach, holds the start longer, as npm’s registry describes. Name the server cora, as the examples do. Choosing the version says which version to give.

Terminal window
claude mcp add cora -- npx --yes --prefer-offline=false --fetch-retries=0 --fetch-timeout=3000 @vispero/cora-mcp@<version>

That adds the server for you, in the current project. --scope user adds it in every project instead.

--scope project writes it to .mcp.json in the project root, to commit for everyone who works on the project:

.mcp.json
{
"mcpServers": {
"cora": {
"type": "stdio",
"command": "npx",
"args": [
"--yes",
"--prefer-offline=false",
"--fetch-retries=0",
"--fetch-timeout=3000",
"@vispero/cora-mcp@<version>"
]
}
}
}
  • Claude Code asks you to approve a server from .mcp.json before it first uses it in the project.
  • /mcp shows each server’s status.
  • Claude Code loads MCP tools on demand, through its tool search, so the agent finds cora-mcp’s tools when it looks for them. To load them as every session starts, add "alwaysLoad": true to the entry, as the plugin’s entry does. Their definitions then take space in every session’s context.
Terminal window
codex mcp add cora -- npx --yes --prefer-offline=false --fetch-retries=0 --fetch-timeout=3000 @vispero/cora-mcp@<version>

That writes the server to ~/.codex/config.toml, for every project. A trusted project’s own .codex/config.toml can hold one for that project alone. Then edit the entry:

~/.codex/config.toml
[mcp_servers.cora]
command = "npx"
args = [
"--yes",
"--prefer-offline=false",
"--fetch-retries=0",
"--fetch-timeout=3000",
"@vispero/cora-mcp@<version>"
]
startup_timeout_sec = 60
env_vars = ["DISPLAY", "TEST_USER_EMAIL", "TEST_USER_PASSWORD"]
  • startup_timeout_sec: Codex gives a server 10 seconds to start by default. The first start downloads cora-mcp, and may then fetch the project’s release, which can take longer.
  • env_vars: Codex starts a server with only a few of its own variables, such as PATH and HOME. Name the others cora-mcp needs:
    • on Linux, DISPLAY, for a browser window;
    • on Linux, XDG_CONFIG_HOME when you set it, so cora-mcp finds your credential and your user config;
    • CORA_TOKEN, when the agent signs in with a CI token;
    • the proxy and certificate variables your network needs, such as HTTPS_PROXY and NODE_EXTRA_CA_CERTS: see Networks and proxies;
    • the variables browser.setup reads its secrets from, such as TEST_USER_PASSWORD above.

In the Codex TUI, /mcp lists the active servers.

By default, Codex asks you before it calls a tool that is not read-only. It skips the ask for a tool that declares it destroys nothing and acts on nothing beyond its own server. verify_fix declares that: it acts only on cora-mcp’s browser, the project and its state.

So of CORA’s tools, Codex asks before scan_url, which loads any URL the agent names. Of the browser_* tools, it asks before each one that acts on the page, such as browser_navigate and browser_click. To let a tool run without asking, set its approval_mode under the entry:

~/.codex/config.toml
[mcp_servers.cora.tools.scan_url]
approval_mode = "approve"

For the plugin’s entry, set default_tools_approval_mode under [plugins."cora@vispero".mcp_servers.cora], which lets every tool of the plugin’s cora-mcp run without asking, or approval_mode under its tools.<tool> for one tool:

~/.codex/config.toml
[plugins."cora@vispero".mcp_servers.cora]
default_tools_approval_mode = "approve"

A client that starts a server over stdio runs the same command, npx --yes --prefer-offline=false --fetch-retries=0 --fetch-timeout=3000 @vispero/cora-mcp@<version>, with the server named cora. Where the client starts a server with only some of your variables, pass on those the Codex entry names.

cora init fetches cora-mcp only for the coding agents it sets up. For a client it doesn’t set up, such as Windsurf, fetch the release before the client’s first start, at the version of @vispero/cora the project has installed, which npx cora --version prints:

Terminal window
npx --yes --prefer-offline=false @vispero/cora-mcp@<version> --version

It puts the release in npm’s cache and prints its version, so cora-mcp’s first start in the project doesn’t wait for the download. Where the entry names another version, such as the latest in an entry that serves every project, run it with that version too.

Give the entry the version of @vispero/cora the project has installed, which npx cora --version prints. cora-mcp then starts without fetching another release. For an entry that serves every project, give it the latest release, which npm view @vispero/cora-mcp version prints.

Either way, cora-mcp runs at each project’s own version, as Version alignment describes. So upgrading a project’s cora needs no change to the entry.

Always give a version. Without one, npx runs whichever release is the latest when the agent starts.

In a project with @vispero/cora installed, an entry can run the project’s cora instead, with no version in it:

Terminal window
claude mcp add --scope project cora -- npx --no cora mcp

cora mcp fetches the cora-mcp release at the project’s cora version, then runs it. So an entry committed with the project follows its cora through upgrades.

  • Options after mcp, such as --headless, pass to cora-mcp.
  • Keep --no, and this form, in the project’s own .mcp.json or .codex/config.toml. --no makes npx stop when the project has no @vispero/cora installed. Without it, npx would fetch and run an unrelated npm package named cora, without asking, since an agent gives it no terminal to ask on.
  • It runs a release npm has cached without asking the registry, so it starts where npm’s proxy or registry can’t be reached (npm’s registry).
  • It has no release to fall back on. When it cannot fetch the release, such as offline before the first fetch, it stops with mcp.release-unavailable.

cora-mcp runs at the version of @vispero/cora the project has installed. So an agent’s scans use the same rules, config and fingerprints as the project’s cora scan and CI.

  • When the entry’s release is another version, cora-mcp fetches the project’s release through npm on its first start, then hands over to it. Later starts use npm’s cache.
  • npx cora init fetches the release when it sets a coding agent up, so that agent’s first start does not wait for the download.
  • When the release cannot be fetched within 5 seconds, such as offline, cora-mcp serves with the release the agent started. It says so on stderr, naming both versions and the command that fetches the release by hand.
  • Outside a project, or in one without @vispero/cora installed, it serves with the release the agent started.

cora-mcp finds the project from the directory the agent starts it in, which is the workspace the agent opened. In a monorepo whose root has no config and does not list @vispero/cora, start it in the app’s directory. Codex’s cwd setting does that, as does opening Claude Code there.

By default, cora-mcp’s browser opens a window you see too. You can watch the agent work in it. You can also sign in yourself when the agent reaches a sign-in page it cannot get past, such as one that asks for a second factor.

Where no display can show a window, the browser runs headless all the same. That is Linux without an X11 or Wayland display, as in a cloud agent, a container, CI, or WSL without WSLg, and macOS or Windows in an SSH session. cora-mcp then warns setting ignored on stderr as it starts, naming mcp.headless and no-display.

Any of three ways runs it headless on any machine, without that warning:

  • --headless in the entry, after the package. In a config file, it is the last item of args.
  • CORA_MCP_HEADLESS=1 in the environment the client starts cora-mcp in.
  • mcp.headless set to true in your user config, for every project and every client on the machine.
Terminal window
claude mcp add cora -- npx --yes --prefer-offline=false --fetch-retries=0 --fetch-timeout=3000 @vispero/cora-mcp@<version> --headless

Which value wins says which of them decides when more than one is set. Whether a machine has a display is the machine’s, so leave the flag out of an entry you commit: the user config or the variable says it for one machine. A browser with a window that does not start, such as on a display that refuses the window, fails with browser.launch-failed, whose hint names all three.

cora-mcp’s browser signs in to your app the way cora scan does, with the config’s browser.storageState or browser.setup: see Signing in. cora-mcp reads the config again as it needs it:

  • An edit to browser takes effect when the browser next starts, once it has closed, such as after the agent calls browser_close. The next browser tool then starts a fresh browser.
  • An edit to rules applies to the next scan.

A sign-in made in the browser window, by you or the agent, lasts until the browser closes.