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.
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.
compile_audienceturns the brief into an audience definition, a readback and any questions, such as which Manchester.count_audiencereturns Total, New to you and Emailable, with the count id.preview_recordsshows up to 25 masked rows with why each matches.quote_orderreturns a machine quote: records after overlap and suppression, credits, GBP ex VAT, the licence and aquote_idvalid 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.
| How | When it applies | What the person sees |
|---|---|---|
| Form | The host supports elicitation and a signed-in person is behind it | One 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 page | The host cannot show a form, or you use a standard API key | A link to mydatahub.emailmovers.com/quotes/{id}/approve that returns a confirmation token |
| Agent key | A human set a monthly budget and a per-order cap in the app | Nothing: 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.
| # | Tool | What it does | Cost | Scope |
|---|---|---|---|---|
| 1 | get_plans | Plans and prices | Free | none |
| 2 | get_account | Account and balance | Free | account:read |
| 3 | list_filters | Filter catalogue | Free | none |
| 4 | search_filter_values | Search filter values | Free | none |
| 5 | expand_job_titles | Expand job titles | Free | none |
| 6 | resolve_location | Resolve a location | Free | none |
| 7 | compile_audience | Compile a brief | Free | none |
| 8 | count_audience | Count an audience | Free | none |
| 9 | preview_records | Preview sample records | Free | none |
| 10 | save_audience | Save an audience | Free | audiences:write |
| 11 | list_audiences | List saved audiences | Free | audiences:read |
| 12 | list_field_sets | List field sets | Free | none |
| 13 | quote_order | Quote an order | Free | none |
| 14 | create_order | Create an order (spends credits) | 1 credit per record | orders:write |
| 15 | get_order | Get order status | Free | orders:read |
| 16 | fetch_order_records | Fetch order records | Free under licence | records:read |
| 17 | push_to_crm | Push an order to a CRM | Free | pushes:write |
| 18 | lookup_company | Look up a company | Free | none |
| 19 | enrich_contact | Enrich a contact (spends credits) | 1 credit on match | enrich:write |
| 20 | check_suppression | Check suppression | Free | suppressions:read |
| 21 | report_objection | Report an objection | Free | suppressions:write |
| 22 | get_compliance_receipt | Get a compliance receipt | Free | orders: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.
| Resource | Title | Cached | Scope |
|---|---|---|---|
mydatahub://catalogue | Filter catalogue | 24 hours, public | none |
mydatahub://pricing | Plans and prices | 1 hours, public | none |
mydatahub://compliance | Compliance and trust | 24 hours, public | none |
mydatahub://datasets | Datasets | 24 hours, public | none |
mydatahub://audiences/{id} | Saved audience | read fresh, private | audiences:read |
mydatahub://orders/{id} | Order | read fresh, private | orders:read |
| Prompt | Arguments | What it does |
|---|---|---|
build_list | who, 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_makers | sector, 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_brief | brief | Turn 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_audience | audience_id | Recount a saved audience on the current dataset version and summarise what changed since its last count. |
explain_compliance | use_case | Explain 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
- Read Spending safely before you let an agent order.
- Browse every tool in the MCP tool reference.
- Moving from today's tools? Use the migration guide.