# Install

> Unzip etch-agent, install its locked runtime, and register the MCP server in Claude Code, Codex, or opencode.

# Install

The fastest path: unzip the package and tell your agent to read the bundled `onboarding.md`. It detects the harness, merges the config, and verifies the connection for you. This page is the same procedure written out for humans, with Claude Code, Codex, and opencode as the worked examples - any other MCP client follows the same shape.

## Unzip and install the runtime

Extract `etch-agent-<version>.zip` into a durable location, for example:

```text
etch-agent/
├── README.md
├── AGENTS.md
├── CHANGELOG.md
├── onboarding.md
├── LICENSE
└── mcp/
    ├── server.js            ← the MCP server your harness launches
    ├── package.json         ← locked runtime manifest
    ├── bun.lock
    └── skills/              ← core and user agent skills
```

The unzipped folder name is version-agnostic, so a future release can be dropped over the same path without touching your MCP config. The version lives in the ZIP filename and `CHANGELOG.md`.

Then install the locked runtime from the package root:

```sh
bun install --cwd mcp --frozen-lockfile --no-save
```

This installs the connector (`@digital-gravy/etch-connector`), `ws`, and `zod` locally inside `mcp/node_modules/`. The ZIP deliberately contains no connector code - it is installed on your machine, under its own license terms, at review-pinned versions.

Check your Bun version first (`bun --version`); **1.3.14 or newer** is required.

## Values every config needs

Two absolute paths go into every harness config:

| Placeholder | Meaning | How to get it |
| --- | --- | --- |
| `SERVER_PATH` | Absolute path to `mcp/server.js` inside the unzipped package. | Run `pwd` inside `mcp/` and append `/server.js`. |
| `BUN_PATH` | Absolute path to the `bun` binary. | Run `which bun`. If the harness inherits your shell PATH, the plain string `"bun"` works. |

Also pick a `--client-name` value (e.g. `claude`, `codex`, `opencode`) - it only labels the instance in startup logs.

## Claude Code

Project-scoped config in `.mcp.json` at the project root, or a global entry under the top-level `mcpServers` object of `~/.claude.json`:

```json
{
  "mcpServers": {
    "etch-agent": {
      "command": "BUN_PATH",
      "args": ["SERVER_PATH", "--client-name", "claude"]
    }
  }
}
```

Merge into the existing `mcpServers` object; do not overwrite other entries. Restart Claude Code afterwards.

## Codex

Config file: `~/.codex/config.toml`. TOML, not JSON:

```toml
[mcp_servers.etch-agent]
command = "BUN_PATH"
args = ["SERVER_PATH", "--client-name", "codex"]
```

Append to the existing file; do not overwrite other `[mcp_servers.*]` blocks. Restart Codex afterwards.

## opencode

Config file: `~/.config/opencode/opencode.json`. Note the shape differs from Claude Code: a single `command` array under `mcp`, no separate `args`:

```json
{
  "mcp": {
    "etch-agent": {
      "type": "local",
      "command": ["BUN_PATH", "SERVER_PATH", "--client-name", "opencode"]
    }
  }
}
```

Restart opencode afterwards.

## Other harnesses

Most MCP clients use the Claude Code JSON shape - put `etch-agent` under the client's own `mcpServers` key:

| Harness | Config location |
| --- | --- |
| Claude Desktop | `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/`, Windows: `%APPDATA%\Claude\`) |
| Cursor | `.cursor/mcp.json` |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
| ZCode | Settings UI → MCP Servers → paste the entry into **Full configuration** (scope: User) |

The ZCode entry uses this JSON in the UI:

```json
{
  "etch-agent": {
    "type": "stdio",
    "command": "BUN_PATH",
    "args": ["SERVER_PATH", "--client-name", "zcode"],
    "env": {}
  }
}
```

## Run several harnesses at once

The connector is shared, not exclusive. The first harness to start becomes the connector host (it owns ports `7331` and `7332`); any harness started afterwards detects it and reuses it. You can install `etch-agent` into Claude Code, Codex, and opencode at the same time and run them simultaneously.

Two rules:

- **Only one agent should mutate the same Etch target at a time.** Two agents editing the same builder tab will collide. Different targets in different tabs are fine.
- For an isolated instance (a scratch harness that must not share the connector), add a distinct port argument such as `--connector-ws-port 17331`. A custom port runs standalone: it hosts nothing and reuses nothing.

## Verify the installation

1. **Connector is up.** The first harness's startup log should read `[etch-agent:<name>] hosting the connector (host mode)`; any harness started later should read `reusing an existing connector (client mode)`.
2. **A target answers.** Log into WordPress, open the Etch builder for a page or template, and click **AI Connector** in the builder. Then ask your agent to call `etch_list_targets` - your tab should appear with its URL and title.

If `etch_list_targets` comes back empty, see [Troubleshooting](./troubleshooting.mdx).
