Skip to navigation

Sign up as an AI agent and get tools with no account

Get an API key and make your first tool call when you have no account and no human to ask.

This is the path for an agent that needs tools right now and has no account. One unauthenticated request creates an organization, an API key, a tool pack, and a registered user, and the response carries everything the next call needs. A human can take ownership later, or never.

When you need this

  • You have no Merge account and no API key.
  • Nobody is available to sign up, click through a form, or paste you a credential.
  • You called https://ah-api.merge.dev/mcp, the OAuth route, and got 401 {"detail": "OAuth authentication required."}.
  • You called a /tool-packs/<id>/registered-users/<id>/mcp URL and got 403 {"detail": "Authentication credentials were not provided."}, which that route returns for a missing key and a rejected one.
  • The task needs a third-party tool (Jira, GitHub) and you hold no credentials for it.

If a person is already in the loop, sign up in the dashboard and read Building an agent instead, which covers the same ground with the dashboard in front of you.

Sign up

The Merge CLI is the recommended path. It stores the key for you, so nothing has to print or copy it, and it writes tool-use instructions into the project you are working in.

brew install pipx # macOS, if you do not have pipx
pipx install merge-api # already installed? run: merge update
merge --version # 0.4.0 or later

Requires Merge CLI 0.4.0 or later. merge agent signup does not exist in earlier versions, and an older CLI fails with “No such command”. Homebrew Python refuses a bare pip install with externally-managed-environment, so install pipx first on macOS.

Check whether you already have an account before signing up:

merge agent whoami # prints your account ids, or exits with "Not signed up"
merge agent signup # no arguments, no authentication

signup creates the organization, saves the credentials to ~/.merge/config.json, and prints the organization name, the tool pack and registered user ids, and the claim URL. It never prints the API key. Running it a second time is refused with already_signed_up.

It also writes Merge CLI instructions into the current project for the host it detects: CLAUDE.md plus a Bash(merge *) permission in .claude/settings.json for Claude Code, .cursorrules for Cursor, or AGENTS.md for anything else. Pass --no-setup to skip those writes, or --setup <target> to pick the host.

Without the CLI

The endpoint is public, so any HTTP client works. Use this when you cannot install anything or you are not in Python.

curl -X POST https://ah-api.merge.dev/api/v1/agent/signup/
import requests
signup = requests.post("https://ah-api.merge.dev/api/v1/agent/signup/").json()

No authentication, no request body. Agent Handler rate limits the endpoint per IP and returns 429 {"non_field_errors": ["Rate limit exceeded"]} with no Retry-After header. A concurrent burst reaches that limit, while requests sent one at a time can each succeed, so sign up once and store the credentials instead of retrying in a loop.

The response carries the api_key string, the new organization’s id and name, a claim link, and the two ids the next call needs. See the API reference for the full response schema.

{
"api_key": "<54-character key>",
"organization": {
"id": "3c90c3c0-6d46-4b50-8888-8dd25736052f",
"name": "agent-amber-cedar-otter-7f3k"
},
"claim_url": "https://ah.merge.dev/claim/<token>",
"claim_expires_at": "2026-09-01T12:00:00Z",
"tool_pack_id": "9b2a5c1e-4f3d-4a6b-9c8d-1e2f3a4b5c6d",
"registered_user_id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"next_step": "Run: merge search-tools \"<intent>\". Guide: https://docs.merge.dev/merge-agent-handler/setup/agent-quickstart"
}

Store the key before doing anything else. It is returned once and there is no account to log into and recover it from, because the organization has no users yet.

What you get

Signup returns the three things a tool call needs, rather than leaving them to a follow-up round of management calls.

FieldWhat it isWhy it’s there
api_keyAn unrestricted production key for the new organization. The CLI saves it to ~/.merge/config.json and never prints it; over HTTP it comes back as a plain stringAuthorizes every call below
tool_pack_idA tool pack named “My first Tool Pack”, holding a curated starter set of connectorsDecides which tools exist
registered_user_idA production registered user named Agent, with origin_id of agentDecides whose credentials run the call

This key is organization-wide: it reaches every Tool Pack and Registered User in the account it just created. That is fine for one agent acting as itself. Once the agent serves more than one person, or a downstream service needs its own credential, mint user-scoped keys from it with POST /api/v1/access-keys/ rather than passing this one around.

The starter tool pack covers eight connectors: Asana, GitHub, HubSpot, Jira, Linear, Notion, Weather, and Wikipedia. It is a starting set rather than the catalog, because seeding every connector would mean thousands of rows written on an unauthenticated request. Add the connectors you actually need from Tool packs, or create a second pack and leave this one alone.

Agent Handler refuses to add a connector to a tool pack until the organization holds OAuth credentials for it, and the 400 response names the connector that needs them. Every seeded connector either needs no credential or runs on Merge’s OAuth app, while Slack and the Google connectors need you to register your own OAuth app first, which an agent cannot do without a person.

Weather and Wikipedia are in the set deliberately: neither needs a credential, so you can prove the whole path works before touching OAuth.

Make the first tool call

The Agent registered user starts with no connected credentials, so start with a connector that does not need one.

merge search-tools "what is the weather forecast"
merge execute-tool weather__get_forecast '{"input": {"latitude": 37.7749, "longitude": -122.4194}}'

search-tools is the call to reach for first. Describe what you want to do in plain language and it returns compact schemas for the tools that match, which is what keeps a full catalog out of the agent’s context. Tool names are <connector>__<tool>, with two underscores. Narrow with --connector <slug> when you already know the connector. Avoid list-tools; the full catalog is too large to be useful.

To point an MCP client at Agent Handler instead of using the CLI, assemble the URL from the two ids and pass the key as Authorization: Bearer <API_KEY>:

https://ah-api.merge.dev/api/v1/tool-packs/<TOOL_PACK_ID>/registered-users/<REGISTERED_USER_ID>/mcp

MCP integration has the client-by-client configuration.

Create your own tool pack

Signup gives you a broad pack so your first tool call works without any setup. An MCP client that connects to that pack receives all of it, around 450 tools and 600 KB of schemas, before the agent calls anything. Create a pack holding only the connectors your task needs, then point the MCP URL at that one. A pack with a single connector returns around 23 tools and 70 KB.

The key signup returned authorizes the create call:

curl -X POST https://ah-api.merge.dev/api/v1/tool-packs/ \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"name": "Notion research agent",
"description": "Notion only, for the research agent",
"connectors": [{"slug": "notion", "auth_scope": "INDIVIDUAL"}]
}'
pack = requests.post(
"https://ah-api.merge.dev/api/v1/tool-packs/",
headers={"Authorization": f"Bearer {signup['api_key']}"},
json={
"name": "Notion research agent",
"description": "Notion only, for the research agent",
"connectors": [{"slug": "notion", "auth_scope": "INDIVIDUAL"}],
},
).json()
print(pack["id"])

The call returns 201 and the new pack’s id. Put that id in the MCP URL in place of the one signup returned, keeping the registered user id you already have. Adding a connector to the pack signup created is a separate action that makes that pack larger. Tool packs covers picking individual tools and choosing credential scope.

Add a connector to the pack

You can add connectors to the pack with the key signup already returned. PATCH /api/v1/tool-packs/{id}/connectors/ upserts the connectors in the body and leaves the rest of the pack in place, so one call reaches most of the catalog without a person signing in.

curl -X PATCH https://ah-api.merge.dev/api/v1/tool-packs/<TOOL_PACK_ID>/connectors/ \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '[{"slug": "outlook", "auth_scope": "INDIVIDUAL"}]'
requests.patch(
f"https://ah-api.merge.dev/api/v1/tool-packs/{signup['tool_pack_id']}/connectors/",
headers={"Authorization": f"Bearer {signup['api_key']}"},
json=[{"slug": "outlook", "auth_scope": "INDIVIDUAL"}],
)

Send the connectors as a bare JSON list, because an object such as {"connectors": [...]} returns 400 "Expected a list of items but got type dict". DELETE /api/v1/tool-packs/{id}/connectors/<slug>/ removes a single connector and returns 204. Keep both apart from PATCH /api/v1/tool-packs/{id}/, where connectors is a full replacement that detaches anything you leave out.

The call succeeds for any connector whose credentials the organization can satisfy. A connector that needs its own OAuth app, which covers Slack and the Google connectors, returns the 400 naming it instead.

Connect a credentialed connector

Anything reading real data needs the Agent registered user to hold a credential for it. There is no browser session to run Link in, so mint a magic link and hand the URL to whoever owns the account:

merge authenticate notion

The response carries a URL. The person who opens it authenticates against their own Notion account, and the credential lands on the Agent registered user. The next notion__ tool call goes through.

For an agent serving more than one person, create a registered user per person rather than sharing the Agent one. Registered users covers why, and the isolation you get from it.

Handing the organization to a human

claim_url is how the org gets an owner. Show it whenever you want a person to take over: they open it, sign in, and become an admin of the organization that already exists, with its key, tool pack, registered user, credentials, and logs intact. Run merge agent whoami --show-claim-url to print it again.

Two properties worth relying on: the key works before the claim and after it, so a handoff never interrupts a running agent, and the link stops working at claim_expires_at. If it lapses before anyone uses it, reissue a fresh one rather than signing up again, which would abandon everything the agent has already connected.

A human who claims the org lands on the same default tool pack rather than a second copy, so nothing is duplicated by the handoff.

Rules for agents

  • Never print, log, or read the API key. The CLI loads it from its config for every command.
  • Sign up once per machine. Check with merge agent whoami first; merge agent signup refuses to run twice.
  • claim_url and the magic link URL are secrets. Show them to your user directly, as plain text on the Merge domain, never shortened, relabeled, or posted in a shared channel.

Next

Shape what the agent can reach with Tool packs.