# 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.

Source: https://emailmovers.com/mydatahub/docs/quickstart/agents
Updated: 16 October 2026

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.

> **Not yet live.** The 22 tools described here are built and tested locally and are not yet live. Today https://mcp.mydatahub.uk serves the current product with 13 session-bound tools, which the 22 replace. The new server is at https://mydatahub.emailmovers.com/mcp. https://mcp.mydatahub.uk keeps serving today's product after launch, until the new server supports OAuth sign-in from the client, and then passes MCP through to it, so that an existing install keeps working without a reinstall. The launch date is to confirm.

## 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.

```bash
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.

> **Proposed.** A listing in the Claude directory is under consideration and not decided. Until then, add the connector by URL.

### 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.

```json
{
  "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.

| 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](https://emailmovers.com/mydatahub/docs/spending-safely.md).

## 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](https://emailmovers.com/mydatahub/docs/authentication.md).

## 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`](https://emailmovers.com/mydatahub/docs/reference/mcp/get_plans.md) | Plans and prices | Free | none |
| 2 | [`get_account`](https://emailmovers.com/mydatahub/docs/reference/mcp/get_account.md) | Account and balance | Free | `account:read` |
| 3 | [`list_filters`](https://emailmovers.com/mydatahub/docs/reference/mcp/list_filters.md) | Filter catalogue | Free | none |
| 4 | [`search_filter_values`](https://emailmovers.com/mydatahub/docs/reference/mcp/search_filter_values.md) | Search filter values | Free | none |
| 5 | [`expand_job_titles`](https://emailmovers.com/mydatahub/docs/reference/mcp/expand_job_titles.md) | Expand job titles | Free | none |
| 6 | [`resolve_location`](https://emailmovers.com/mydatahub/docs/reference/mcp/resolve_location.md) | Resolve a location | Free | none |
| 7 | [`compile_audience`](https://emailmovers.com/mydatahub/docs/reference/mcp/compile_audience.md) | Compile a brief | Free | none |
| 8 | [`count_audience`](https://emailmovers.com/mydatahub/docs/reference/mcp/count_audience.md) | Count an audience | Free | none |
| 9 | [`preview_records`](https://emailmovers.com/mydatahub/docs/reference/mcp/preview_records.md) | Preview sample records | Free | none |
| 10 | [`save_audience`](https://emailmovers.com/mydatahub/docs/reference/mcp/save_audience.md) | Save an audience | Free | `audiences:write` |
| 11 | [`list_audiences`](https://emailmovers.com/mydatahub/docs/reference/mcp/list_audiences.md) | List saved audiences | Free | `audiences:read` |
| 12 | [`list_field_sets`](https://emailmovers.com/mydatahub/docs/reference/mcp/list_field_sets.md) | List field sets | Free | none |
| 13 | [`quote_order`](https://emailmovers.com/mydatahub/docs/reference/mcp/quote_order.md) | Quote an order | Free | none |
| 14 | [`create_order`](https://emailmovers.com/mydatahub/docs/reference/mcp/create_order.md) | Create an order (spends credits) | 1 credit per record | `orders:write` |
| 15 | [`get_order`](https://emailmovers.com/mydatahub/docs/reference/mcp/get_order.md) | Get order status | Free | `orders:read` |
| 16 | [`fetch_order_records`](https://emailmovers.com/mydatahub/docs/reference/mcp/fetch_order_records.md) | Fetch order records | Free under licence | `records:read` |
| 17 | [`push_to_crm`](https://emailmovers.com/mydatahub/docs/reference/mcp/push_to_crm.md) | Push an order to a CRM | Free | `pushes:write` |
| 18 | [`lookup_company`](https://emailmovers.com/mydatahub/docs/reference/mcp/lookup_company.md) | Look up a company | Free | none |
| 19 | [`enrich_contact`](https://emailmovers.com/mydatahub/docs/reference/mcp/enrich_contact.md) | Enrich a contact (spends credits) | 1 credit on match | `enrich:write` |
| 20 | [`check_suppression`](https://emailmovers.com/mydatahub/docs/reference/mcp/check_suppression.md) | Check suppression | Free | `suppressions:read` |
| 21 | [`report_objection`](https://emailmovers.com/mydatahub/docs/reference/mcp/report_objection.md) | Report an objection | Free | `suppressions:write` |
| 22 | [`get_compliance_receipt`](https://emailmovers.com/mydatahub/docs/reference/mcp/get_compliance_receipt.md) | 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.

```ts
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](https://emailmovers.com/mydatahub/docs/errors.md).

## Protocol revisions

The server speaks the [2026-07-28 revision](https://modelcontextprotocol.io/specification/2026-07-28/changelog) 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](https://emailmovers.com/mydatahub/docs/spending-safely.md) before you let an agent order.
- Browse every tool in the [MCP tool reference](https://emailmovers.com/mydatahub/docs/reference/mcp.md).
- Moving from today's tools? Use the [migration guide](https://emailmovers.com/mydatahub/docs/migrate.md).
