Email Validation
Check email addresses from your AI client, one at a time or a whole list: each result comes with a status, a reason and what to do next. Unknown results are free.
Hosted MCP Server
npx add-mcp 'https://api.email-validation.org/mcp'Installs into Claude Code, Codex, Cursor and more
Documentation
MCP Server Setup Guide
URL: https://email-validation.org/docs/mcp/ Updated: 2026-10-26
Documentation index: https://email-validation.org/llms.txt
The Model Context Protocol (MCP) is an open standard that lets AI assistants and agents use tools from other
services. The email-validation.org MCP server is one of those tools. Add it to an MCP client such as Claude, ChatGPT, Cursor or
VS Code, and the model can validate email addresses, read your credit balance and run bulk jobs for you on your
account. It uses the same credits, limits and rules as the REST API: unknown results are free, and so are errors.
- Endpoint:
https://api.email-validation.org/mcp(a remote server: Streamable HTTP, stateless, nothing to install); for EU data residency,https://api-eu.email-validation.org/mcp(EU data residency) - Authentication: an API key from the dashboard, sent on every request as
Authorization: Bearer <your API key>; or, in clients that support OAuth, a sign-in in your browser (details) - Protocol revisions: 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26
- Price: nothing extra. Tool calls use the same credits as the REST API (details).
In five minutes:
- Create an API key for your assistant, with a daily credit cap.
- Connect your client: Claude, Claude Code, ChatGPT, Cursor, VS Code, Windsurf or any other MCP client.
- Check the connection with a test address. It costs nothing.
- Validate real addresses from the chat, and learn to read the answers.
1. Get an API key
- Sign in or create an account. A new account comes with 500 free credits (100 when you sign up with a free email provider such as Gmail, Outlook or Yahoo, or another personal mailbox such as a paid one like Fastmail or one from your internet provider).
- Open API keys in the dashboard and click Create API key.
- In Name, name the key after the assistant that will use it, for example "Claude" or "Cursor", so you can tell keys apart in the list and in Usage.
- Under Permissions, keep Validate and Account, which are ticked for new keys. They let the assistant
use
validate_emailandget_credits. Tick Bulk only if the assistant should run bulk jobs. - Open Limits and set a Daily credit cap, for example 100. The key stops for the day once it has used that many credits, including the credits of bulk jobs it creates.
- Click Create key. If the page asks you to confirm with your passkey first, do so: creating a key needs a recent sign-in.
- Copy the key. The full key is shown once, so copy it before you close the dialog.
Keep the key in an environment variable, not in a shared file. The examples below use EV_API_KEY:
export EV_API_KEY="ev_live_…"
Never paste the key into the chat itself: the model does not need to see it, and chats are stored. Clients that support OAuth can skip the key: see Sign in instead of a key. The details of keys, scopes and caps are in Authentication.
2. Connect your client
| Client | With an API key | With a sign-in (OAuth) | Where you set it up |
|---|---|---|---|
| Claude (claude.ai and Claude Desktop) | Yes, with request headers (beta) | Yes, recommended | Customize → Connectors |
| Claude Code | Yes | Yes | claude mcp add or .mcp.json |
| ChatGPT | No | Yes | Settings → Apps, in developer mode |
| Cursor | Yes | Yes | mcp.json |
| VS Code and GitHub Copilot | Yes | Yes | mcp.json |
| Windsurf (Devin Desktop) | Yes | Yes | mcp_config.json |
| Other MCP clients | Yes | If they support OAuth 2.1 | The client's MCP settings |
| Your own code (Claude API, OpenAI API) | Yes | Not needed | The request |
Claude: claude.ai and Claude Desktop
Claude connects to remote MCP servers as custom connectors. A connector you add on claude.ai also works in Claude Desktop, because Claude connects to the server from Anthropic's cloud, not from your computer. On the Free plan you can add one custom connector.
- Go to Customize → Connectors and click Add custom connector. On Team and Enterprise plans an Owner adds it instead, under Organization settings → Connectors → Add → Custom, and each member then clicks Connect on it.
- Name it, for example email-validation.org, and enter
https://api.email-validation.org/mcpas the MCP server URL. - Choose how to authenticate:
- Sign in (recommended): under Authentication, choose Sign in now or Sign in when needed. Under OAuth client, choose Register automatically. Do not choose Use Claude's published identity: our server does not support that method, and the sign-in fails. Click Add, then Connect: Claude sends you to our site, where you sign in, check the permissions it asks for and allow it (how sign-in works). A signed-in app has no daily credit cap; use an API key if you want one.
- API key: under Authentication, choose No sign-in. Under Request headers, pick
authorizationand enterBearerfollowed by your key, with the space: Claude sends the value exactly as you type it. You can pickx-api-keyinstead and enter the key alone. Request headers are in beta and not every organization has them yet; if you do not see the section, use the sign-in.
- In a chat, click + → Connectors and turn email-validation.org on for that conversation.
You cannot change a connector's authentication after you add it: remove the connector and add it again. You do not
need claude_desktop_config.json: that file starts local servers on your computer, and this server is remote.
Claude Code
Add the server from a terminal. Your shell fills in the key, and Claude Code keeps it in its local configuration:
claude mcp add --transport http email-validation https://api.email-validation.org/mcp \
--header "Authorization: Bearer $EV_API_KEY"
To share the setup with a project without sharing the key, put this in .mcp.json at the project root instead.
Claude Code reads EV_API_KEY from the environment when it starts:
{
"mcpServers": {
"email-validation": {
"type": "http",
"url": "https://api.email-validation.org/mcp",
"headers": {
"Authorization": "Bearer ${EV_API_KEY}"
}
}
}
}
Run /mcp in Claude Code to check that the server is connected and offers four tools. To sign in instead of
using a key, add the server without the --header line, then choose it in /mcp and authenticate in your
browser.
ChatGPT
ChatGPT connects to remote MCP servers as apps in developer mode, a beta for the Plus, Pro, Business, Enterprise and Edu plans on the web. ChatGPT cannot send a fixed API key, so it uses the sign-in.
- In ChatGPT, open Settings → Apps → Advanced settings and turn on Developer mode. In a Business, Enterprise or Edu workspace, an admin has to allow developer mode first.
- Click Create app. Enter a name, for example email-validation.org, and
https://api.email-validation.org/mcpas the server URL. - Choose OAuth as the authentication, then create the app.
- ChatGPT sends you to our site: sign in, check the permissions it asks for and allow it.
- In a chat, open the + menu of the message box, choose Developer mode and turn email-validation.org on.
ChatGPT asks you to confirm each validate_email and create_bulk_job call before it runs, because these calls
spend credits. Check the addresses in the request and confirm. get_credits and get_bulk_job are marked as
read-only tools.
Cursor
Add the server to ~/.cursor/mcp.json (every project) or .cursor/mcp.json (one project). Cursor fills in
${env:EV_API_KEY} from its environment:
{
"mcpServers": {
"email-validation": {
"url": "https://api.email-validation.org/mcp",
"headers": {
"Authorization": "Bearer ${env:EV_API_KEY}"
}
}
}
}
Then open Cursor's MCP settings and check that email-validation is enabled and lists four tools. To sign in
instead of using a key, leave out headers: Cursor shows a button to sign in when it connects.
VS Code and GitHub Copilot
Add the server to .vscode/mcp.json in your workspace, or to the mcp.json of your user profile. VS Code asks for
the key the first time the server starts and keeps it in its secret storage:
{
"inputs": [
{
"type": "promptString",
"id": "ev-api-key",
"description": "email-validation.org API key",
"password": true
}
],
"servers": {
"email-validation": {
"type": "http",
"url": "https://api.email-validation.org/mcp",
"headers": {
"Authorization": "Bearer ${input:ev-api-key}"
}
}
}
}
Start the server from the file (or with MCP: List Servers), then use the tools in Copilot Chat in agent mode. To
sign in instead of using a key, leave out inputs and headers: VS Code asks you to sign in when the server
starts.
Windsurf (Devin Desktop)
Windsurf is now called Devin Desktop. Open its MCP settings from the agent panel's menu, open the raw configuration
(mcp_config.json) and add the server. It fills in ${env:EV_API_KEY} from its environment:
{
"mcpServers": {
"email-validation": {
"serverUrl": "https://api.email-validation.org/mcp",
"headers": {
"Authorization": "Bearer ${env:EV_API_KEY}"
}
}
}
}
Save the file and refresh the MCP servers in the panel; email-validation should list four tools. To sign in
instead of using a key, leave out headers.
Other MCP clients
Any client that supports remote (Streamable HTTP) servers with a custom header can connect: give it the endpoint URL
and the Authorization header. If your client cannot set Authorization, send the key in X-Api-Key instead.
Many clients accept a configuration like this one, and the request below checks the connection from a terminal:
JSON
{
"mcpServers": {
"email-validation": {
"type": "http",
"url": "https://api.email-validation.org/mcp",
"headers": {
"Authorization": "Bearer ${EV_API_KEY}"
}
}
}
}
curl
# Check the connection by listing the tools (2025-06-18 protocol revision).
curl https://api.email-validation.org/mcp \
-H "Authorization: Bearer $EV_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
From your own code with an LLM API
You can also give the server to a model in your own program. The model provider connects to the server from its cloud and sends your key on every call, so you write no MCP code. Allow only the tools you need, and give the key a daily credit cap.
With the Claude API (the MCP connector, in beta):
import os
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
betas=["mcp-client-2025-11-20"],
mcp_servers=[{
"type": "url",
"url": "https://api.email-validation.org/mcp",
"name": "email-validation",
"authorization_token": os.environ["EV_API_KEY"],
}],
tools=[{
"type": "mcp_toolset",
"mcp_server_name": "email-validation",
"default_config": {"enabled": False},
"configs": {"validate_email": {"enabled": True}, "get_credits": {"enabled": True}},
}],
messages=[{"role": "user", "content": "Can I send to accepted@sandbox.email-validation.org?"}],
)
print("".join(block.text for block in response.content if block.type == "text"))
With the OpenAI Responses API (a remote MCP tool):
import os
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="YOUR_MODEL", # an OpenAI model that supports remote MCP tools
tools=[{
"type": "mcp",
"server_label": "email_validation",
"server_url": "https://api.email-validation.org/mcp",
"headers": {"Authorization": f"Bearer {os.environ['EV_API_KEY']}"},
"allowed_tools": ["validate_email", "get_credits"],
"require_approval": "never",
}],
input="Can I send to accepted@sandbox.email-validation.org?",
)
print(response.output_text)
With approval set to never, every call the model makes runs without asking you, so the key's daily cap is your
limit. Other frameworks and providers that support remote MCP servers take the same three things: the URL, the
Authorization header and the tools to allow.
3. Check it works with test addresses
Addresses on sandbox.email-validation.org return a fixed answer for every reason and never use a credit:
<reason>@sandbox.email-validation.org returns that reason. Ask your assistant, for example:
Validate
accepted@sandbox.email-validation.organd tell me if I can send to it.
The model calls validate_email and gets this summary back, with the full result:
accepted@sandbox.email-validation.org is valid (accepted: Mailbox accepts mail). Recommended action: send. free (no credit used).
Test addresses still need a working API key or sign-in, so they test your setup end to end. The full list is on Test addresses. If the model says it has no such tool, turn the server on for the chat (see your client above); if it reports an error, see Troubleshooting.
4. Tutorial: validate emails in a chat
Three worked examples. They use test addresses, so you can try each one for free and get the same answers. With
real addresses, each answer costs 1 credit, except unknown answers and errors.
Validate one address
Check whether
accepted@sandbox.email-validation.orgis a real mailbox before I add it to the CRM.
The model calls validate_email once with the address. It reads the one-line summary and the result fields, and
answers in plain words: the mailbox accepts mail, so you can send to it. Before a newsletter or a sales email, ask
for the check right where you collect or paste the address.
Check a short list
Validate these addresses and tell me which ones to keep:
accepted@sandbox.email-validation.org,no_mailbox@sandbox.email-validation.org,disposable@sandbox.email-validation.org.
The model calls validate_email once per address, and each call returns its own summary:
accepted@sandbox.email-validation.org is valid (accepted: Mailbox accepts mail). Recommended action: send. free (no credit used).
no_mailbox@sandbox.email-validation.org is invalid (no_mailbox: Mailbox not found). Recommended action: remove. free (no credit used).
disposable@sandbox.email-validation.org is disposable (disposable: Disposable inbox). Recommended action: remove. free (no credit used).
So it keeps the first address and drops the other two. With real addresses, three answers cost up to 3 credits. For
more than a few dozen addresses, ask for a bulk job instead: the model calls create_bulk_job with the list, then
get_bulk_job until the job is done. That needs a key with the Bulk permission, or a signed-in app you allowed
the Bulk permission; for big files, use the dashboard or the bulk API.
Explain a "catch_all" result
Validate
catch_all@sandbox.email-validation.org. It says catch_all: explain why, and tell me whether I should email it.
The summary the model gets:
catch_all@sandbox.email-validation.org is catch_all (catch_all: Catch-all domain). Recommended action: send_with_caution. free (no credit used).
And the full result:
{
"email": "catch_all@sandbox.email-validation.org",
"status": "catch_all",
"reason": "catch_all",
"action": "send_with_caution",
"account": "catch_all",
"domain": "sandbox.email-validation.org",
"did_you_mean": null,
"free_email": false,
"role_account": false,
"disposable": false,
"catch_all_domain": true,
"mx_found": true,
"mx_record": "mx.sandbox.email-validation.org",
"smtp_provider": "other",
"domain_age_days": 3650,
"processed_at": "2026-10-20T09:30:00.000Z",
"credits_used": 0,
"request_id": "req_7Hq2LmX9cV4bN8tR1zK6wD"
}
How the model, and you, read it:
statusis the verdict:catch_allmeans the address may work but cannot be confirmed.reasonsays why:catch_allmeans the domain accepts mail for every address (catch_all_domainistrue), so no check can prove this one mailbox exists. See the catch_all status.actionis what to do:send_with_cautionmeans send if the address matters to you, for example a customer who just signed up, and watch for bounces; leave it out of cold campaigns. The four actions are explained in Statuses.did_you_meansuggests a fix when the address looks like a typo of a common domain; here it isnull.credits_usedis 0 for a test address. A real catch-all address costs 1 credit.
The meaning of every status and reason is on Statuses and reasons.
Example prompts
- "Check whether jane@example.com is a valid address before I add it to the CRM."
- "Here are 300 sign-ups from last week: create a bulk job, wait for it, and tell me how many are catch-all or disposable."
- "How many credits do I have left, and when do the next ones expire?"
- "This address bounced last month: check it again with fresh set to true."
Sign in instead of a key
Clients that support OAuth 2.1 can connect without a key: add the server with only its URL, and the client opens our site in your browser. Sign in, check the app's name, where it sends you back to and the permissions it asks for, and allow it. The client then gets a token that works only with the permissions you approved and uses your credits like a key does. Disconnect it at any time under API keys, in Connected apps. The details are in OAuth for apps and AI agents.
A signed-in app is not an API key you can edit:
- No daily credit cap. It can spend up to your whole balance, within your account's rate limit. To cap what an assistant spends per day, connect it with an API key that has a daily cap, where the client can send one.
- It keeps the permissions you approved. The consent page shows the permissions the app asks for, and you allow or deny them as a whole. If it asks for Bulk and you do not need bulk jobs, click Deny and use an API key without Bulk. To change an app's permissions later, disconnect it under Connected apps and connect it again.
Clients register themselves with dynamic client registration. In Claude, that is the Register automatically option; clients that only offer a published client identity cannot sign in yet, so use an API key with them.
Tools
| Tool | What it does | Arguments | Credits |
|---|---|---|---|
validate_email | Validate an email address | email, ip_address (optional), timeout (optional), fresh (optional) | 1 credit per result; unknown results, malformed and sandbox addresses are free. |
get_credits | Get the credit balance | none | Free. |
create_bulk_job | Create a bulk validation job | emails, start (optional), webhook_endpoint_id (optional) | 1 credit per unique address that needs a check; unknown results are refunded. |
get_bulk_job | Get a bulk job | job_id | Free. |
Each tool returns structured content with the same fields as the REST API, plus a one-line summary for the model
(for example the status, the recommended action and whether a credit was used). validate_email returns the
validation result. For accepted@sandbox.email-validation.org it looks like this:
{
"email": "accepted@sandbox.email-validation.org",
"status": "valid",
"reason": "accepted",
"action": "send",
"account": "accepted",
"domain": "sandbox.email-validation.org",
"did_you_mean": null,
"free_email": false,
"role_account": false,
"disposable": false,
"catch_all_domain": false,
"mx_found": true,
"mx_record": "mx.sandbox.email-validation.org",
"smtp_provider": "other",
"domain_age_days": 3650,
"processed_at": "2026-10-20T09:30:00.000Z",
"credits_used": 0,
"request_id": "req_7Hq2LmX9cV4bN8tR1zK6wD"
}
get_credits returns the credit balance with the credit lots that expire soonest.
create_bulk_job and get_bulk_job return the job object; the agent polls get_bulk_job
until the job is completed, then you download the results as CSV in the dashboard or with the
bulk API. A job that stays ready with an error_code (for example
insufficient_credits) could not start and needs your action.
Credits and pricing
validate_emailcosts 1 credit per answer.unknownanswers are free, and so are malformed addresses and test addresses.- An address checked in the last 12 months can be answered from our result cache
(
processed_atis when the answer was produced). A cached answer still costs 1 credit. Setfreshtotrueto check the address again. create_bulk_jobholds one credit per unique address that needs a check; duplicates and malformed addresses are free, and credits forunknownresults come back when the job ends.get_creditsandget_bulk_jobare free. Errors never use a credit.- There is no separate MCP plan: you buy the same credit packs, which last 24 months.
Limits
- A
validate_emailcheck takes at most 15 seconds; slower checks returnunknownand are free. create_bulk_jobtakes up to 10,000 addresses in one call. For bigger lists use the bulk API or the dashboard.- A request to the MCP endpoint is at most 4 MB. A larger one is refused with HTTP
413(payload_too_large) before any tool runs. - A JSON-RPC batch holds at most 20 messages. A longer one is refused with HTTP
400(invalid_request) before any tool runs. - Tool calls share your account's rate limit with the REST API: 500 requests per second after your first purchase, 20 before. A key can have a lower limit of its own. Test addresses and malformed addresses do not count toward it (they have a separate, much higher safety limit).
- Errors come back as tool errors with the same codes as the REST API, and no credit is used.
Security
- Keep the key secret. Put it in an environment variable or the client's secret storage, never in the chat,
a shared document or a file you commit. The snippets above read it from
EV_API_KEY. - One key per assistant, with a daily credit cap and only the permissions it needs: no Bulk unless it runs bulk jobs. A key used from a browser also gets a list of allowed origins.
- A signed-in app has no daily cap. It keeps the permissions you approved on the consent page and can spend up to your whole balance (details). Where the client can send a key, a key with a daily cap limits spend.
- Watch what the model does. Clients ask before a tool runs; choose "Always allow" only for a server and a chat
you trust. In Claude you can block a tool you do not need, such as
create_bulk_job, under Customize → Connectors. Text the model reads (a web page, an email) can try to make it call tools. A key's daily cap limits what such a call can spend; a signed-in app has no cap, so keep tool confirmations on for it (in ChatGPT, do not turn them off). - Revoke what you no longer use. Under API keys, revoke a key, and disconnect an app that signed in under Connected apps: both stop at once. Rolling a key keeps the old key working for the grace period you choose (24 hours unless you change it), so when a key has leaked, revoke it or roll it with Stop the old key now, then follow If a key leaks.
- Check the usage. Usage in the dashboard shows the calls and credits per key, so an unexpected spike is easy to spot.
Troubleshooting
| What you see | What to do |
|---|---|
The client cannot connect, or says the server needs authentication (HTTP 401 unauthorized) | No key was sent, or the key is wrong, revoked or expired. Check that the client's configuration has the Authorization header and the whole key. A header that is sent but empty or without Bearer gives HTTP 400 instead (next rows). |
| The client opens a browser sign-in | That is the OAuth sign-in: sign in and allow the app. To use an API key instead, add the Authorization header to the client's configuration. |
| The sign-in page shows an error | Connect with an API key instead (the snippets above). |
| Claude: the sign-in fails with "Use Claude's published identity" | Remove the connector and add it again with Register automatically as the OAuth client. |
| Claude: there is no Request headers section | Request headers are in beta and not available to every organization. Use the sign-in instead. |
| ChatGPT: there is no Create app button | Turn on Developer mode under Settings → Apps → Advanced settings. In a workspace, ask an admin to allow it. |
| ChatGPT asks to confirm every check | That is expected: validate_email spends a credit, so ChatGPT asks first. Check the address and confirm. |
HTTP 400 invalid_request with "Malformed Authorization header" | The value must be Bearer followed by the key. An empty EV_API_KEY gives this error: an app started from the Dock or the Start menu does not see variables from your shell profile, so set the key where the client runs. A key entered without Bearer (for example under authorization in Claude) gives it too. |
HTTP 400 invalid_request (other messages) | The key is in the URL, or two different keys were sent. Send one key, in a header only. |
HTTP 400 with "Unsupported protocol version" | Update the client: the server answers protocol revisions 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26. |
Tool error forbidden | The key lacks the scope the tool needs (bulk for the bulk tools, account:read for get_credits), or the account is on hold. Change the key's scopes under API keys; for a signed-in app, disconnect it under Connected apps and connect again, approving the permission. |
Tool error insufficient_credits or key_daily_cap | The account is out of credits, or the key reached its daily cap (signed-in apps have none). Buy credits or raise the cap. |
Tool error rate_limited | Too many calls at once. Wait the number of seconds the error gives, then retry. |
| The answer seems out of date | It may have come from the result cache (a check made in the last 12 months). Ask the agent to set fresh to true. |
| No tools appear | Restart the client or reload its MCP servers, check that the server is enabled, and turn it on for the chat. |
Every error code is listed on Errors.
Discovery
The server is described in our MCP server card and AI catalog, so directories and clients that read these files can find it. The same key also works with the A2A endpoint and the Agent Skill.