Skip to main content
Installing Reticle by hand is two independent halves: register the MCP server so your agent gets the reticle_* tools, then add the SDK to your app so there is something for those tools to talk to. You need both, in that order. Do only the first half and the tools appear but every call reports no session. Do only the second and your app connects to a daemon nobody is asking questions.
You probably do not need this page. Two commands do all of it:
The first registers the MCP server with every agent it can reach. The second wires the app. See the quickstart.This page is for the cases those cannot cover: a machine where piping a script is not allowed, an agent Reticle does not know, or a step the installer reported as needing a hand (Codex CLI is the usual one, because its config is TOML that Reticle will not rewrite).
If you want the CLI without the script:
reticle setup mcp is exactly the registration half of the installer, and it prints any client it could not write for you.

Part 1. Register the MCP server

There is no config file that all agents share. Each harness has its own path and its own schema, so write only the one you actually use.

Claude Code

Register once, globally, and every project has it:
Confirm with claude mcp list. reticle should be there. If the claude CLI isn’t available, merge one key into mcpServers in ~/.claude.json. It is a large stateful file, so merge, never rewrite:

Cursor, VS Code, Windsurf

Same shape, different file and root key. Cursor and Windsurf use mcpServers; VS Code uses servers:

Codex CLI

TOML, in .codex/config.toml. This is the one init cannot write for you:

OpenCode

Note the flat command array and the required type:
Restart your agent afterwards. It read its server list at startup and nothing re-reads it. /mcp manages servers that are already loaded, so it cannot discover a new one. Restart Claude Code, reload the Cursor window, or press Start in .vscode/mcp.json.

Part 2. Wire the SDK into your app

Vite

That’s the whole web install. The plugin stamps source locations onto elements. The thing that turns a DOM node into src/components/Login.tsx:81. And injects connect() so you can’t forget it.

Anything without the plugin

If you’re not on Vite or Next, call connect() yourself, guarded so it never reaches production:
connect() is dev-only by design. Guard it with whatever your bundler gives you: import.meta.env.DEV, process.env.NODE_ENV !== 'production', or a build flag. Reticle also self-guards, but two locks on a door that leads to your users is a reasonable number.

Tauri. and the step whose failure is silent

The frontend is identical to any web app. The CSP is not optional:
Tauri’s default CSP blocks the bridge WebSocket before it opens. Your app runs perfectly and simply never connects, with no error to go on. Keep ipc: http://ipc.localhost in connect-src, Tauri v2 needs it for invoke itself. And drop the ws:// entries from your release config.
Screenshots and headless mode need the Rust crate, which is versioned independently of the npm packages:
IPC observation needs nothing on the Rust side. An invoke('load_todos') already reaches Reticle as ipc://load_todos.

Electron, and the rest of desktop

Main-process and renderer wiring, IPC observation, and what differs from the web install.

Part 3. Prove it

A session in the output means the app connected. That. Not a tick in a checklist, is the install finished. If it says nothing connected, the usual cause is a port disagreement between your app and the daemon. The browser console will carry [Reticle] this page could not open a websocket to … naming the exact address it tried; set it explicitly with VITE_RETICLE_WS_URL=ws://localhost:4400/reticle or reticle.connect({ url }). Still stuck? npx @reticlehq/server doctor checks Chromium, the daemon and the port in one command.

Instrument your app

Register stores, signals and testids so your verdicts get stronger than “the DOM changed”.

Quickstart

Drive your first flow and read a real verdict.
Last modified on September 23, 2026