AI agents, MCP and CLI
Tell an agent “set up 1DB for acme.com” in any project. It adds the website, writes its keys to the project, wires the form and sends a test lead.
Why use it
Without it, connecting a site means copying an endpoint, a key and a form slug from the dashboard into the project, then writing the form code. Your agent is already in the project and knows its framework, so it can do all of that and prove a lead arrives, without you leaving the editor. You only approve the sign-in once, and add the keys to your host when you deploy.
Before you start
- A 1DB account where you are an admin of the organization (agent tokens act as their admin).
- Node 18 or newer (
node -v), fornpx. - Claude Code for the one-command setup. Other agents work too: see Other MCP clients.
1. Connect once
In your own terminal, from any folder:
npx @1db/cli setupIt opens 1DB in your browser to approve the sign-in (pick the organization and the scopes), then adds the 1DB MCP server to Claude Code for every project. Restart Claude Code to load it. You do this once per computer, not once per project.
It creates an agent token (1db_at_…) that acts for you in that organization. It stays in your user config, never in a project. The per-website keys (1db_…) an agent writes into a project can only send leads. See or revoke tokens in Settings → API keys → Agent tokens.
Not in CI or a shared machine
The token can manage your organization. Run setup on your own computer, never in a CI job, a container image or a project script.
2. Ask for it
Open Claude Code in the website's project and say:
Set up 1db for acme.comClaude calls onboard_website, writes DB_API_ENDPOINT, DB_API_KEY and DB_FORM_SLUG to the env file (and git-ignores it), wires the form, then uses send_test_lead and list_leads to prove leads arrive. Asking twice is safe: the same website comes back, not a copy.
For a site that is already connected and needs another form:
Add a quote request form to acme.com in 1dbClaude calls create_form, which returns the new form's slug and fields. The site keeps its ingest key; the new form posts with its own formSlug. Pass a template (quote-request, pickup-request, contact) for ready-made fields, and defaultLeadType / defaultProductType for leads that arrive without them. See form templates and defaults.
3. Go live
.env.local only exists on your computer. The deployed site sends nothing until its host has the same variables:
- Add
DB_API_ENDPOINT,DB_API_KEYandDB_FORM_SLUG(with any prefix the project uses) to your host's production environment variables: Vercel → Settings → Environment Variables, Netlify → Site configuration → Environment variables, Cloudflare → Settings → Variables. - Redeploy. Most hosts only read new variables on the next deploy.
- Submit the real form on the live site, then check it arrived:
npx @1db/cli leads acme.com, or ask Claude to list the leads.
A test lead from the agent proves the key and form slug. Only a submission on the live site proves the deployed form.
Already using 1DB?
Nothing changes for sites that already send leads: the endpoint and keys are the same. To confirm a project is wired up right, run this in its root folder:
npx @1db/cli check # compare the project's DB_* vars with 1DB
npx @1db/cli check --send # also post one test lead with those exact valuesIt finds the variables in the project's .env* files (including older 1DB_ names and NEXT_PUBLIC_/VITE_ prefixes), checks the endpoint, key and form slug against the website, and checks the env files are git-ignored. It exits non-zero when something is wrong. To hand it to the agent in that project instead:
This project already sends leads to 1DB. Check the setup without rewriting working code:
1. Run `npx @1db/cli@latest check` in the project root and read the result. If it says I'm not
logged in, stop and ask me to run `npx @1db/cli setup` in my own terminal.
2. Fix only what it marks ✗ (wrong endpoint, wrong form slug, env file tracked by git).
3. Don't rename env vars or replace values that work. Don't put any 1db_at_ token in the project.
4. Tell me which variables the live site's host needs, if any are missing there.Configure it
With the matching scopes, an agent can finish the setup too:
Make the quote form on acme.com default to product type pallets
Email ops@acme.com when the quote form gets a lead
Forward every new lead to https://api.acme.com/leads with our API keyupdate_website,list_product_types: name, domain, status, product types and the website-level fallback product type.get_form,update_form: rename a form, change its slug, replace its fields or set its default lead type and product type.set_form_notifications: notification emails (up to 10) and a webhook per form.list_forwarding_rules,create_forwarding_rule,update_forwarding_rule,delete_forwarding_rule: send each new lead to an outside endpoint, with agenericorrepackifyprofile. New rules start disabled; secrets are stored and never returned.delete_form,delete_website: needconfirmset to the slug. Leads are kept, but a live form posting to it starts failing.
Other tools: get_website, list_websites, scan_domain, whoami. Destinations must be public https:// URLs. HubSpot and Salesforce connections use OAuth, so they are set up in the dashboard.
Token scopes
Each token only does what its scopes allow; anything else gets a 403 naming the missing scope. Pick them when creating a token in Settings or approving a CLI sign-in. whoami shows a token's scopes.
| Scope | Allows |
|---|---|
sites | Add websites and forms, change their settings, get ingest keys, send test leads |
leads | Read leads and their contact details |
routing | Forwarding rules, notification emails and webhooks: anything that sends leads somewhere |
delete | Delete websites, forms and forwarding rules |
The defaults, sites and leads, cover setting up a site. Give an agent you don't run yourself sites only. Tokens created before scopes existed keep sites and leads.
Test leads are real leads
send_test_lead, 1db send and 1db check --send post through the same endpoint as your site. The lead shows in the dashboard and counts in stats, and it runs the site's CRM sync, notification emails, webhooks and forwarding. It is tagged with source 1db-test so you can find and delete it.
Agents are told to send one per check. If the site already syncs to a CRM or forwards leads, expect one test contact to show up there too.
Keeping tokens safe
- Two kinds of key. The agent token (
1db_at_…) manages your organization and lives in~/.config/1db/config.jsonand your Claude Code config. The ingest key (1db_…) goes in projects and can only send leads.1db checkfails if an agent token ends up in a project. - A token leaked? Revoke it in Settings → API keys → Agent tokens; it stops working at once. Then run
npx @1db/cli setup --reloginfor a new one. - You'll know when one is made. Organization owners get an email whenever a new agent token is created.
- Switch organization with
npx @1db/cli setup --reloginand pick the other one when approving. - Sign out with
npx @1db/cli logoutandclaude mcp remove 1db, then revoke the token in Settings.
Troubleshooting
| You see | What to do |
|---|---|
| Claude has no 1DB tools | Restart Claude Code after setup. claude mcp list should show 1db. |
401 invalid or revoked token | The token was revoked. Run npx @1db/cli setup --relogin. |
403 missing scope | The message names the scope. Run npx @1db/cli setup --relogin and tick it. |
404 website not found | The token is for another organization, or the slug is wrong. whoami and websites show both. |
429 | Over 60 requests a minute. Wait a minute. |
| Sign-in code expired | Codes last 10 minutes. Run the command again. |
| Leads arrive locally but not from the live site | The host is missing the variables, or wasn't redeployed. See Go live. |
Lead rejected: Form not found | DB_FORM_SLUG isn't a form on that site. npx @1db/cli check lists the right ones. |
Other MCP clients
Create a token in Settings (or run npx @1db/cli mcp after logging in) and point any Streamable HTTP client (Cursor, Windsurf, VS Code and others) at the server with the token as a header:
claude mcp add --scope user --transport http 1db https://www.1-db.com/api/mcp \
--header "Authorization: Bearer 1db_at_..."The server takes the token as a header, not an OAuth sign-in, so it can't be added as a connector on claude.ai or in the Claude desktop chat yet. Use Claude Code, another client that sends headers, or the CLI.
Or use the CLI yourself
npx @1db/cli login # browser sign-in (or --token 1db_at_...)
npx @1db/cli init acme.com # scan + add the site, write DB_* vars to .env.local
npx @1db/cli check acme.com # compare this project's DB_* vars with 1DB
npx @1db/cli check --send # ...and post one test lead with the project's own values
npx @1db/cli leads acme.com # see it arrive
npx @1db/cli keys acme.com # print the site's endpoint, key and form slug
npx @1db/cli form acme.com --name "Quote request" --fields "email*,name,phone:phone,message:textarea"
# add another form to the site, print its slug
npx @1db/cli product-types add "Pallets" # new organizations start with no product types
npx @1db/cli form acme.com --template quote-request --product-type pallets
# or start from a template, with form defaults
npx @1db/cli form-edit acme-quote-request --lead-type buy
npx @1db/cli site acme.com --product-type pallets --status active # website-level fallback
npx @1db/cli notify acme-quote-request --emails ops@acme.com
npx @1db/cli forwarding add --name "Our API" --endpoint https://api.acme.com/leads --auth-token ... --profile generic --enableRun it from the project's root folder: init and check read and write the env files there. init never replaces values a project already has; it lists the differences and leaves them (pass --force to overwrite).
Every command takes --json. Use --prefix NEXT_PUBLIC_ or --prefix VITE_ when the variables must reach the browser. Install it with npm i -g @1db/cli to type 1db instead of npx @1db/cli.
Or call the agent API
curl -X POST https://gallant-goshawk-513.convex.site/v1/agent/onboard \
-H "Authorization: Bearer $ONEDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain":"acme.com"}'POST /v1/agent/onboard{ domain, name?, fields? }: scans the domain and creates the website with its ingest key and contact form. Retrying returns the same website withcreated: false.POST /v1/agent/forms{ website, name?, slug?, fields?, preset?, template?, defaultLeadType?, defaultProductType? }: adds a form to an existing website (nameortemplaterequired). Fields default to the preset, then the organization's default preset, then the standard contact fields. Retrying with the same slug (or name) returns the same form.GET /v1/agent/website?website=acme.com: endpoint, ingest key, forms and fields.POST /v1/agent/test-lead{ website, data?, formSlug? }: sends a real lead through/v1/leads, tagged source1db-test.GET /v1/agent/leads?website=acme.com&limit=20: newest leads first.GET /v1/agent/websites,GET /v1/agent/me,POST /v1/agent/scan.POST /v1/agent/website/update{ website, name?, domain?, status?, defaultProductType?, productTypes? },GET /v1/agent/product-types,POST /v1/agent/product-types{ name, slug?, category? },POST /v1/agent/product-types/import{ rule }(routing; adds the product types that rule's destination accepts).GET /v1/agent/form?form=slug,POST /v1/agent/forms/update{ form, name?, slug?, fields?, defaultLeadType?, defaultProductType? }(""clears a default).POST /v1/agent/forms/notifications{ form, email?: { enabled, recipients }, webhook?: { enabled, url, headers? } }(routing).GET|POST /v1/agent/forwarding,POST /v1/agent/forwarding/update{ id, ..., profile?: "generic" | "repackify" }(routing);POST /v1/agent/forwarding/delete{ id, confirm: name }(delete).POST /v1/agent/forms/delete{ form, confirm },POST /v1/agent/website/delete{ website, confirm }(delete).
Errors come back as { error, hint? }. Limit: 60 requests a minute per token (bursts to 120).
What lands in the project
DB_API_ENDPOINT=https://gallant-goshawk-513.convex.site
DB_API_KEY=1db_...
DB_FORM_SLUG=contact
# one per extra form made with create_form
DB_QUOTE_REQUEST_FORM_SLUG=acme-quote-requestThe form posts to ${DB_API_ENDPOINT}/v1/leads with the key in an X-API-Key header and formSlug in the JSON body. Keep the call on the server and the variables stay unprefixed. If the browser sends it, add the prefix your framework needs (NEXT_PUBLIC_DB_API_KEY, VITE_DB_API_KEY) with --prefix. The ingest key can only send leads, so that is safe, but a server route keeps it out of view.
The form code itself is in the Next.js, React and HTML forms guides, which use the same variable names. Agents can read /llms.txt for a plain-text index.