EmailmoversMyDataHub docs
Browse the docs

Start here

Quickstart for agents

Connect Claude, ChatGPT or Cursor to the MyDataHub MCP server at https://mydatahub.emailmovers.com/mcp, and call its 22 tools from code. Looking is free; spending needs a quote and a confirmation.

Updated 16 October 2026View as Markdown

The MCP server has 22 tools, and 20 of them cost 0 credits. An agent can count, preview and quote without a key, and needs one only when a tool acts for your account. Counts, quotes and records are the same objects you see in the app and over REST.

Connect a client

The server URL is https://mydatahub.emailmovers.com/mcp on streamable HTTP, beside the REST API at /v1 on the same host. Installs made at https://mcp.mydatahub.uk keep working: that address stays on today's product until the new server supports OAuth sign-in from the client, then passes MCP through to it and never redirects.

At launch an assistant connects with the same mdh_live_ API key that works on the REST API, sent as a bearer token. Signing in with OAuth 2.1 and PKCE from the client, with no key to copy, is planned for after launch.

Any client that supports remote MCP servers over streamable HTTP can connect with a MyDataHub API key. A client that cannot send a key can still use the free tools, which need none.

Claude

In Claude Code, add the server from the command line with your API key as a header.

claude mcp add --transport http mydatahub https://mydatahub.emailmovers.com/mcp \
  --header "Authorization: Bearer $MYDATAHUB_API_KEY"

In Claude on the web or the desktop app, add a custom connector from the connectors settings and paste the server URL. Until OAuth sign-in from the client arrives after launch, a connector that cannot send a key uses the free tools: counts, previews and quotes. https://mcp.mydatahub.uk serves today's product, which does not take mdh_ keys.

ChatGPT

Add the server as a custom connector in ChatGPT's connector settings, with the server URL. Whether custom connectors are available depends on your plan (to confirm). Until OAuth sign-in from the client arrives after launch, a connector that cannot send a key uses the free tools.

When ChatGPT presents a client certificate, MyDataHub records its fingerprint on every order it places. A listing in ChatGPT apps is under consideration and not decided.

Cursor

Add the server to .cursor/mcp.json in your project, or the global file. The standard form takes a URL and optional headers.

{
  "mcpServers": {
    "mydatahub": {
      "url": "https://mydatahub.emailmovers.com/mcp",
      "headers": { "Authorization": "Bearer ${env:MYDATAHUB_API_KEY}" }
    }
  }
}

An "Add to Cursor" deeplink on this page and a cursor.directory listing are under consideration and not decided. Check Cursor's own documentation for the config syntax of your version.

Your first conversation

Ask for what you want in plain English: "How many finance directors work at law firms in Manchester? Quote me 300 of them." The agent should walk the free steps in this order and then stop.

  1. compile_audience turns the brief into an audience definition, a readback and any questions, such as which Manchester.
  2. count_audience returns Total, New to you and Emailable, with the count id.
  3. preview_records shows up to 25 masked rows with why each matches.
  4. quote_order returns a machine quote: records after overlap and suppression, credits, GBP ex VAT, the licence and a quote_id valid for 24 hours.

Only then does the agent call create_order. The server's own instructions say it plainly: "Count first, preview second, quote third, then create_order. Counting, previewing and quoting are free; one credit buys one complete UK record. create_order needs a quote_id from quote_order."

How a spend is confirmed

create_order needs the quote_id and an idempotency_key. It has no confirmation flag, and the input schema refuses one, because a flag set by a model is never consent. Instead one of three things confirms the spend.

HowWhen it appliesWhat the person sees
FormThe host supports elicitation and a signed-in person is behind itOne checkbox that reads "Spend 5,000 credits (£1,249.00 ex VAT bought the cheapest way) for 5,000 contacts, 12 month multi-use licence"
Approval pageThe host cannot show a form, or you use a standard API keyA link to mydatahub.emailmovers.com/quotes/{id}/approve that returns a confirmation token
Agent keyA human set a monthly budget and a per-order cap in the appNothing: the order runs inside the limits

At launch an assistant connects with an API key, so a spend is confirmed on the approval page, or by an agent key within its limits. The form needs a signed-in person behind the host, which comes with OAuth sign-in from the client after launch.

With none of the three, the tool returns a confirmation-required problem with the approval_url and creates nothing. The agent keeps the quote_id and hands the link to you. See Spending safely.

Agent keys

An agent key is an API key with kind agent. A person creates it in the app with a label, the tools it may call, a monthly budget in credits, a per-order cap, an expiry and an optional webhook URL.

It shows a live spend meter and can be revoked at any time. The default budget is 1,000 credits a month, £250 at the per-contact scale, until raised (to confirm).

An agent key may call only the tools in its allowed_tools. Over a budget it gets agent-budget-exceeded with an approval_url for the key owner and a top_up_url.

The owner is told only when the key has a webhook_url with an endpoint registered at that URL. See Authentication.

The tools

Every tool has a title, annotations and an output schema. Reads set readOnlyHint true.

Writes set readOnlyHint false, destructiveHint false and idempotentHint true. Only push_to_crm sets openWorldHint true.

#ToolWhat it doesCostScope
1get_plansPlans and pricesFreenone
2get_accountAccount and balanceFreeaccount:read
3list_filtersFilter catalogueFreenone
4search_filter_valuesSearch filter valuesFreenone
5expand_job_titlesExpand job titlesFreenone
6resolve_locationResolve a locationFreenone
7compile_audienceCompile a briefFreenone
8count_audienceCount an audienceFreenone
9preview_recordsPreview sample recordsFreenone
10save_audienceSave an audienceFreeaudiences:write
11list_audiencesList saved audiencesFreeaudiences:read
12list_field_setsList field setsFreenone
13quote_orderQuote an orderFreenone
14create_orderCreate an order (spends credits)1 credit per recordorders:write
15get_orderGet order statusFreeorders:read
16fetch_order_recordsFetch order recordsFree under licencerecords:read
17push_to_crmPush an order to a CRMFreepushes:write
18lookup_companyLook up a companyFreenone
19enrich_contactEnrich a contact (spends credits)1 credit on matchenrich:write
20check_suppressionCheck suppressionFreesuppressions:read
21report_objectionReport an objectionFreesuppressions:write
22get_compliance_receiptGet a compliance receiptFreeorders:read

tools/list returns the 22 tools in this fixed order with ttlMs 300000, so host prompt caches hit. A result stays under about 8,000 tokens: records pages hold at most 100 rows over MCP, and a cross-tab at most 200 cells.

Resources and prompts

Resources are documents a host can read and cache. Prompts are templates a person invokes. Every prompt walks only the free steps and says not to call create_order without your confirmation.

ResourceTitleCachedScope
mydatahub://catalogueFilter catalogue24 hours, publicnone
mydatahub://pricingPlans and prices1 hours, publicnone
mydatahub://complianceCompliance and trust24 hours, publicnone
mydatahub://datasetsDatasets24 hours, publicnone
mydatahub://audiences/{id}Saved audienceread fresh, privateaudiences:read
mydatahub://orders/{id}Orderread fresh, privateorders:read
PromptArgumentsWhat it does
build_listwho, where (optional), how_many (optional)Build a UK B2B contact list step by step: compile the brief, count, preview a masked sample and quote, stopping before any spend.
senior_decision_makerssector, area (optional)Count senior decision makers (the sdm title bundle) in a sector and area, broken down by seniority, with a masked sample.
quote_from_briefbriefTurn a written brief into an audience, a count, a masked sample and a machine quote for a person to review. Nothing is ordered.
refresh_saved_audienceaudience_idRecount a saved audience on the current dataset version and summarise what changed since its last count.
explain_complianceuse_caseExplain how the records may be used lawfully for a given use case, from the published compliance position.

Call the server from code

The official TypeScript SDK connects to the server and lists the tools. This needs @modelcontextprotocol/sdk and Node 22 or later.

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const key = process.env.MYDATAHUB_API_KEY;
const transport = new StreamableHTTPClientTransport(new URL("https://mydatahub.emailmovers.com/mcp"), {
  requestInit: key ? { headers: { Authorization: `Bearer ${key}` } } : {},
});
const client = new Client({ name: "example-agent", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools();
console.log(tools.map((tool) => tool.name).join(", "));

const counted = await client.callTool({
  name: "count_audience",
  arguments: {
    audience: {
      schema: "mydatahub.audience/1",
      where: {
        all: [
          { field: "company.sic_2007", op: "in", values: ["C"] },
          { field: "company.employee_band", op: "gte", value: "50-99" },
        ],
      },
    },
  },
});
console.log(counted.structuredContent);
await client.close();

structuredContent matches the tool's output schema, and the first text block is a one-line summary that leads with the number. A failed call returns isError true, with the sentence a person acts on followed by the whole problem as JSON. See Errors.

Protocol revisions

The server speaks the 2026-07-28 revision natively and keeps 2025-11-25 and 2025-06-18 clients working. Legacy initialize is accepted, Mcp-Session-Id is ignored, GET and DELETE return 405, and the Origin header is validated. server/discover advertises the supported versions with ttlMs 3600000 and a public cache scope.

Next steps