# MCP server
URL: https://docs.arcns.io/mcp/

> mcp.arcns.io — the arcns MCP server for AI agents. Every tool, the install snippets, the namespace/registry rule, the agent verification ladder, and what prepare_* returns and how to sign it.

Testnet

`https://mcp.arcns.io` exposes arcns name resolution and records to AI agents over [MCP](https://modelcontextprotocol.io) — Streamable HTTP transport, stateless, **no auth for read tools**, **no wallet/signer key material at all**. It is a convenience surface, not a source of truth: the two resolution tools relay [`api.arcns.io`](/api/) byte-for-byte, every other read goes straight to Arc through [`@arcns/resolve`](/quickstart/), and the two `prepare_*` tools return an unsigned call for **your own wallet** — this server never holds a signing key and never signs or broadcasts. [`api.arcns.io`](/api/#agents-pay-per-read-with-x402) now charges non-browser callers per read over x402; this server carries its own free-tier HTTP API key so `resolve_name` and `reverse_lookup` stay free for you to call — see [Run your own](#run-your-own) for what that means if you self-host.

> **Rule**
> `@jack`, `jack.arc` and `jack.circle` are different namespaces that can have **different owners**, and `jack.arc` can live in more than one registry on the same chain. Every tool result carries its `namespace` **and** the `registry` it was read from. A mixed shape (`@jack.arc`) is refused as `ambiguous`; registries that disagree are listed under `candidates`. Nothing is ever picked for you.

## Install [#install]

```bash
claude mcp add --transport http arcns https://mcp.arcns.io/mcp
```

**Cursor** (`~/.cursor/mcp.json` or `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "arcns": {
      "url": "https://mcp.arcns.io/mcp"
    }
  }
}
```

**VS Code** (`.vscode/mcp.json`):

```json
{
  "servers": {
    "arcns": {
      "type": "http",
      "url": "https://mcp.arcns.io/mcp"
    }
  }
}
```

No auth header, no API key. `arcns://llms.txt` (also served at `https://mcp.arcns.io/llms.txt`) is the "Instructions for AI agents" block every client above hands to the model on connect — the source for this page's rules, in the form an agent reads first.

## Tools [#tools]

| Tool                                                  | Reads                                                         | Answers                                                                                                                                                                                                                                                |
| ----------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `resolve_name(name)`                                  | relays `GET /resolve/:name`                                   | Byte-identical to the [resolver API](/api/) — controller, address record + `verified`, `namespace`, `registry`, block. `409 ambiguous` on a mixed shape; `candidates[]` when registries disagree.                                                      |
| `reverse_lookup(address)`                             | relays `GET /reverse/:address`                                | The address's one forward-confirmed primary name, or "no primary set".                                                                                                                                                                                 |
| `check_availability(name)`                            | Arc, one block                                                | Registrable now on the arcns controller (valid, not registered, not reserved, controller not paused, TLD active) + price; for `.arc` / `.circle` also lists every pinned peer registry that already holds the name — it would resolve there, not here. |
| `quote_price(name)`                                   | Arc, one block                                                | Registration price (USDC, 18 decimals) + the commit-reveal window.                                                                                                                                                                                     |
| `get_records(name, keys?)`                            | Arc, current ownership epoch                                  | Address records with `verified`, and text records — default keys are the `agent.*` set (`agent.manifest`, `agent.x402`, `agent.mcp`, `agent.a2a`, `agent.erc8004`, `agent.capabilities`) plus `url` / `description` / `avatar`.                        |
| `get_agent_manifest(name, probe402?)`                 | Arc + the manifest URL + optionally the `agent.x402` endpoint | The verification ladder below, the fetched + validated manifest, and `payTo`.                                                                                                                                                                          |
| `search_agent_handles(q, limit?)`                     | indexer query API                                             | Prefix search over `@handles` with `handleType: Agent`. Answers `code: "not-available"` when the server has no query API configured.                                                                                                                   |
| `prepare_register(name, owner, handleType?, secret?)` | Arc, one block                                                | The commit + register calls (commit-reveal) for `owner`'s wallet to sign.                                                                                                                                                                              |
| `prepare_set_record(name, key, value)`                | Arc, one block                                                | The `setText` call for the name's owner / operator / delegate to sign; `agent.*` values are checked against the convention below.                                                                                                                      |

Resources: `arcns://llms.txt` and `arcns://schema/resolve` — the exact [`/schema/resolve.json`](/api/) every `resolve_name` answer conforms to.

## Agent records and the verification ladder [#agent-records-and-the-verification-ladder]

Agent-facing keys are ordinary [ENSIP-5 text records](/api/) on a name's resolver (`docs/architecture/agent-records.md`):

| Key                  | Value                                           | Meaning                                                                                          |
| -------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `agent.manifest`     | `https://…` or `ipfs://…`                       | The one document describing the agent's endpoints, capabilities and payment hints (shape below). |
| `agent.x402`         | `https://…`                                     | The x402-protected resource whose `402` answer is the **authoritative** price / asset / `payTo`. |
| `agent.mcp`          | `https://…`                                     | The agent's own MCP server, if it has one.                                                       |
| `agent.a2a`          | `https://…`                                     | The A2A agent card URL.                                                                          |
| `agent.erc8004`      | `eip155:<chainId>:<IdentityRegistry>:<agentId>` | Binds the name to an ERC-8004 identity.                                                          |
| `agent.capabilities` | `https://…`                                     | Optional capability document / JSON Schema URL.                                                  |

`get_agent_manifest` reports the **highest level it checked**, never one it assumed:

| Level                     | Check                                                                                                                                        | What it proves                                                            |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| **L0 — declared**         | `agent.manifest` or `agent.erc8004` is set, or the handle's `handleType` is `Agent`                                                          | The current owner says this name is an agent. Nothing more.               |
| **L1 — identity-bound**   | ERC-8004 `IdentityRegistry.ownerOf(agentId) == <name owner>`, both read at one block                                                         | The same key controls the name and the ERC-8004 identity.                 |
| **L2 — pay-to-confirmed** | `GET <agent.x402>` answers `402` whose `accepts[]` names this chain (`eip155:5042002`) with a `payTo` equal to the name's Arc address record | The service the agent sells pays out to the address the name resolves to. |

The ladder as the server climbs it (`sdk/src/agent.ts` for L0–L1, the MCP server for L2), and the one check that sits beside it:

```mermaid
flowchart TD
  N["Name<br/>@handle · .arc · .circle"] --> L0("L0 declared?<br/>agent.manifest / agent.erc8004<br/>set, or handleType Agent")
  L0 -- no --> NA["not an agent name"]
  L0 -- yes --> L1("L1 identity-bound?<br/>IdentityRegistry.ownerOf(agentId)<br/>= name owner, one block")
  L1 -- no --> S0["reported: L0"]
  L1 -- yes --> L2("L2 pay-to-confirmed?<br/>agent.x402 answers 402,<br/>payTo = Arc address record")
  L2 -- no --> S1["reported: L1"]
  L2 -- yes --> S2["reported: L2"]
  S2 --> V("addr.verified?")
  V -- yes --> PAY["an agent may pay"]
  V -- no --> HUMAN["do not pay<br/>without a human"]
```

> **Rule**
> `addr.verified` is orthogonal to the ladder: it says the owner *proved* control of the payee address on chain, not that the name is an agent. Require **L2 + `verified: true`** before one agent pays another; `verified: false` means do not pay without a human.

## What `prepare_*` returns, and how to sign it [#what-prepare_-returns-and-how-to-sign-it]

```json
{
  "chainId": 5042002,
  "to": "0x…",
  "data": "0x…",
  "value": "0",
  "functionName": "commit",
  "args": ["0x…"],
  "description": "Commit to register @payday-bot (handle registry 0x520E…15d2)"
}
```

* **viem**: `walletClient.sendTransaction({ to, data, value: BigInt(value), chain })`
* **Privy**: `sendTransaction({ to, data, value }, { address })`
* **Circle CLI / a Circle developer-controlled wallet**: `circle wallet execute --to <to> --data <data> --value <value> --chain ARC-TESTNET`

`prepare_register` returns two steps (commit-reveal, SR-10): send step 1, wait at least `minCommitmentAge` seconds (and at most `maxCommitmentAge`) of chain time, then send step 2 with the **same** `name` / `owner` / `secret` / `handleType` — the secret is minted by the tool when you don't supply one and is never stored server-side; keep it yourself between the two steps.

x402 on the two `prepare_*` tools is out of scope for this server today (the x402 gateway lane owns payment code) — the server exposes a hook point for it without changing any tool's shape.

## Run your own [#run-your-own]

> **Note**
> The `fortiblox-arcns` repository is private to FortiBlox Labs as of 2026-09-14 — `git clone` below will 404 without org access. The steps are accurate for engineers who have it; there is no public source drop yet (the same is true of the `@arcns/resolve` package — see [Quickstart](/quickstart/)).

```bash
git clone https://forgejo.selfhsted.com/fortiblox/fortiblox-arcns.git
cd fortiblox-arcns/mcp && npm ci
ARC_CHAIN_ID=5042002 ARC_RPC_URL=https://rpc.testnet.arc.io \
  API_URL=https://api.arcns.io MCP_BIND=0.0.0.0:8827 \
  ARCNS_API_KEY=<your-free-tier-key> \
  npm run build && npm start
```

`api.arcns.io` gates `/resolve` and `/reverse` behind x402 for non-browser callers ([API](/api/#agents-pay-per-read-with-x402)) — `ARCNS_API_KEY` is a CEO-issued free-tier HTTP credential (a plain header value, not a wallet key) sent as `X-API-Key` on every call this server makes to `API_URL`, so `resolve_name`/`reverse_lookup` keep reading for free. Leave it unset only while upstream payments are off; once they're on, an unset or invalid key makes those two tools answer `{code: "upstream-misconfigured"}` rather than relay a raw `402` to your caller.

Leaving every `*_ADDRESS` variable unset falls back to the SDK's checked-in deployment for `ARC_CHAIN_ID`; set one and every one becomes required, so a half-configured override can never silently mix two deployments. See `mcp/README.md` in the [repository](https://forgejo.selfhsted.com/fortiblox/fortiblox-arcns) for the full env table.
