Skip to content
Back to Docs

MCP server: run DirectoryDuck from an AI agent

Connect Claude, Cursor or any MCP client to your account. From a chat, the agent can create a directory, fill it with AI discovery, publish the listings, hand you the embed snippet, connect your own domain and get you a checkout link.

Every tool is included in the paid plans (Starter, Growth and Pro), available now. On the Free plan a key can call the read-only tools (list_listings, get_discovery_job and get_embed_snippet) and start_checkout; create_directory, run_discovery, add_listing, publish_listings and connect_domain answer that they need a paid plan. The per-minute limit per key applies on every plan, Free included.

1. Create a key

In the dashboard, open Settings → API keys, name the key (for example "Claude Code") and pick its permissions. The key starts with ddmcp_ and is shown once: copy it then. It is not your directory's widget key, which can't be used here.

2. Connect your client

Server URL https://directoryduck.com/api/mcp (Streamable HTTP), with the key in an Authorization: Bearer header.

Claude Code

claude mcp add --transport http directoryduck https://directoryduck.com/api/mcp \
  --header "Authorization: Bearer ddmcp_YOUR_KEY"

Cursor

Add this to .cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project, then restart Cursor:

{
  "mcpServers": {
    "directoryduck": {
      "url": "https://directoryduck.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ddmcp_YOUR_KEY"
      }
    }
  }
}

Claude Desktop

Claude's Connectors screen signs in with OAuth, which this server does not offer yet, so connect through the open-source mcp-remote bridge (it needs Node.js). In Claude Desktop, open Settings → Developer → Edit Config, add this to claude_desktop_config.json and restart Claude:

{
  "mcpServers": {
    "directoryduck": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://directoryduck.com/api/mcp",
        "--header",
        "Authorization:${DIRECTORYDUCK_AUTH}"
      ],
      "env": {
        "DIRECTORYDUCK_AUTH": "Bearer ddmcp_YOUR_KEY"
      }
    }
  }
}

Any other MCP client

Point it at the URL and send the header on every request. The server is stateless: it speaks MCP 2026-07-28 and serves 2025-era clients too; there is no session to open or close and no SSE stream to keep.

POST https://directoryduck.com/api/mcp
Authorization: Bearer ddmcp_YOUR_KEY
Content-Type: application/json
Accept: application/json, text/event-stream

3. Ask for a directory

For example: "Create a directory of dog groomers in Austin, find about 15 with DirectoryDuck, publish them and give me the embed snippet." The agent calls create_directory, run_discovery, get_discovery_job until the job is done, publish_listings and get_embed_snippet.

Tools

Every id you pass must be one of your own: another account's directory or job answers as not found. Each tool needs one permission on the key.

create_directory

mcp:writeStarter and up

Create a new directory in your DirectoryDuck account. It gets a public page at https://directoryduck.com/<slug> (the slug is made from the name). Next: run_discovery to fill it with AI, or add_listing to add listings by hand. Your plan limits how many directories you can have (Starter 1, Growth 5, Pro unlimited).

namerequiredstringDirectory name, e.g. "Austin Dog Groomers"
nicherequiredstringWhat the directory lists, e.g. "dog groomers"
locationstringWhere, if it is local, e.g. "Austin, TX"

run_discovery

mcp:spendStarter and up

Start an AI discovery job: AI searches the web for businesses matching your query, reads each website and drafts a listing. Costs credits, like the dashboard: 10 to start, 1 for the web search, and 2 per business found. Most it can cost: small (up to 15 businesses) 41, medium (40) 91, large (100) 211 credits. Duplicates of listings you already have are skipped and cost nothing. It runs in the background for a few minutes: poll get_discovery_job with the job_id it returns, then publish_listings { all_found: true } to publish the results. One job per directory at a time.

directory_idrequiredstringThe directory_id (a UUID)
queryrequiredstringWhat to find, e.g. "dog groomers in Austin, TX"
size"small" | "medium" | "large"How many businesses to look for: small 15, medium 40, large 100 Default "small".

get_discovery_job

mcp:readevery plan, Free included

The status and progress of a discovery job started with run_discovery, the credits it used, and, once it is done, how many results are ready to publish with a sample of them.

job_idrequiredstringThe job_id (a UUID)

list_listings

mcp:readevery plan, Free included

The listings of one of your directories, in a stable order, a page at a time (pass next_cursor back as cursor). Status: prospect = found but not published, active = published on the public page; also contacted, claimed, inactive. Also returns counts per status and how many discovery results are waiting to be published.

directory_idrequiredstringThe directory_id (a UUID)
status"prospect" | "contacted" | "claimed" | "active" | "inactive"Only listings with this status
limitintegerPage size, 1-100 Default 25.
cursorstringnext_cursor from the previous page

add_listing

mcp:writeStarter and up

Add one listing to one of your directories. It starts unpublished (status prospect) unless publish is true; publish later with publish_listings. Your plan limits listings per directory (Starter 500, Growth 2,000, Pro unlimited).

directory_idrequiredstringThe directory_id (a UUID)
namerequiredstringBusiness or listing name
website_urlstringhttps://...
descriptionstring
emailstring
phonestring
categoriesstring[]
locationobjectThe business address; every part optional. Shown on the public listing page and in its structured data.
publishbooleantrue = publish it on the public page now Default false.

publish_listings

mcp:writeStarter and up

Publish listings on the directory's public page. Either listing_ids (listings of this directory to publish), or all_found: true to publish everything found and not yet published: every prospect listing, plus every finished discovery result that has no listing yet and scored 70 or more for relevance (or was approved in the dashboard); rejected and low-relevance results are skipped. Publishing costs no credits. A directory shows at most 10 featured listings: a listing that is still featured from before is published without its Featured badge when the directory already shows 10 (featured_removed lists them).

directory_idrequiredstringThe directory_id (a UUID)
listing_idsstring[]Listings to publish
all_foundbooleantrue = publish every prospect listing and every discovery result scoring 70+ (or approved in the dashboard) not yet published; low matches are left out

get_embed_snippet

mcp:readevery plan, Free included

The copy-paste snippet that puts the whole directory (search, filters, listing pages, inquiry form) on any website with one script tag, with the directory's public key filled in, plus where to paste it on common platforms.

directory_idrequiredstringThe directory_id (a UUID)

connect_domain

mcp:writeStarter and up

Serve one of your directories on your own domain or subdomain (e.g. directory.example.com) instead of directoryduck.com/<slug>. Returns the DNS records to set at your DNS provider; the domain goes live once DNS points at us (call it again to re-check). Starter: one domain per account; Growth and Pro: one per directory.

directory_idrequiredstringThe directory_id (a UUID)
hostnamerequiredstringThe domain, e.g. "directory.example.com"

start_checkout

mcp:billingevery plan, Free included

Get a Stripe Checkout link for a DirectoryDuck plan (Starter $39/mo, Growth $99/mo, Pro $249/mo; yearly = 2 months free). Open the link in a browser to pay; nothing is charged by this call. While paid plans are not open yet it says so instead of returning a link.

planrequired"starter" | "growth" | "pro"The plan to buy
interval"monthly" | "yearly"Billing interval Default "monthly".

Credits

Only run_discovery spends credits, the same credits and the same prices as discovery in the dashboard: 10 to start, 1 for the web search and 2 per business found. Duplicates of listings you already have are skipped and cost nothing. The most a job can cost: small 41 credits (up to 15 businesses), medium 91 (40), large 211 (100). A job needs at least 13 credits left to start.

Every other tool costs no credits. Publishing listings costs nothing.

Limits

  • Requests per minute per key: Free 10, Starter 30, Growth 60, Pro 120. Every MCP request counts, listing the tools and the read-only tools included, so each tool call costs one. Over the limit you get HTTP 429 with a Retry-After header.
  • One JSON-RPC message per request: batches (JSON arrays) are refused with HTTP 400. Request bodies are limited to 256 KiB. The server takes POST only and keeps no stream open.
  • One discovery job per directory at a time.
  • Your plan's directory and listing limits apply (Starter 1 directory and 500 listings, Growth 5 and 2,000 each, Pro unlimited).
  • Up to 5 active keys per account.
  • AI discovery pauses for everyone when DirectoryDuck's monthly AI budget is reached; run_discovery then says so and charges nothing.

Permissions and security

  • mcp:read: List listings, read discovery jobs and get the embed snippet.
  • mcp:write: Create directories, add and publish listings, connect a domain.
  • mcp:spend: Run AI discovery, which uses credits like the dashboard does.
  • mcp:billing: Start a checkout (returns a link you open and pay in your browser).
  • A key acts as you. We store only a fingerprint (SHA-256) of it, so a lost key can't be shown again: rotate it (new key, same permissions, the old one stops at once) or revoke it in Settings → API keys.
  • start_checkout only returns a Stripe Checkout link; you open it and pay in your browser. Nothing is charged inside the chat.

Errors

A refused tool call comes back as a tool result marked as an error, with a code and what to do next: invalid_input, not_found, scope_missing, plan_required (a Free key calling a tool that needs Starter and up), limit_reached, conflict (for example a discovery already running in that directory), refused (not enough credits, the AI budget, a domain that can't be used), unavailable or failed. A missing, wrong or revoked key is HTTP 401; over the rate limit, HTTP 429.

Prefer plain HTTP?

The public REST API reads published listings and reviews with your directory's widget key.