All posts

Give a Claude API Agent Email Verification With the MCP Connector

··6 min read

To give a Claude agent email verification through the API, use Anthropic's MCP connector: add SimpleVerifier's remote MCP server to the mcp_servers list of a Messages API request, enable its tools with an mcp_toolset entry, and pass your API key as the authorization_token. Claude then calls verify_email itself whenever it needs to check an address, and your script reads the final answer. There is no MCP client to build.

This is the route for your own agents: an outbound research script, an SDR agent that finds contacts, an enrichment job. If you only want verification inside Claude Desktop, Claude Code or Cursor, see verify emails with Claude MCP. If you call the REST API from code, see the quickstart.

What you need

  • A SimpleVerifier plan with API and MCP access: Pro, Business or Agency. Pro is $39 a month and includes 10,000 API calls a month, then $1.50 per 1,000 on monthly billing. Pro email verification also runs the first 100,000 checks a month at full speed, then slower, never cut off. See pricing.
  • An API key from the API keys page, shown once, starting sv_live_.
  • An Anthropic API key and the anthropic Python package.

How the connector works

Anthropic documents the MCP connector as a beta feature with two parts. The mcp_servers array holds connection details: type: "url", the url, a name and an optional authorization_token. The tools array holds an {"type": "mcp_toolset", "mcp_server_name": ...} entry that says which of that server's tools to enable. You send a beta header with the request (the docs list mcp-client-2025-11-20 in their examples, and they say the older mcp-client-2025-04-04 is deprecated).

Two limits from Anthropic's page matter. Only MCP tool calls are supported, not other protocol features. And the server must be publicly reachable over HTTP, with both Streamable HTTP and SSE supported, while local STDIO servers cannot be connected directly. SimpleVerifier's server is a public Streamable HTTP endpoint at https://simpleverifier.com/api/mcp, so it fits. Check the connector page for the current beta header and model list before you deploy, because beta details change.

The script

Install the SDK and set two environment variables: ANTHROPIC_API_KEY and SIMPLEVERIFIER_KEY.

pip install anthropic
export ANTHROPIC_API_KEY="sk-ant-xxx"
export SIMPLEVERIFIER_KEY="sv_live_xxx"
import json
import os
import anthropic

MCP_URL = "https://simpleverifier.com/api/mcp"

SYSTEM = """You check email addresses with the SimpleVerifier tools.
Rules:
- Never invent, repair or guess an email address. Check only what you are given.
- Use verify_email for one address, verify_emails for up to 100.
- If verify_emails returns done false, call get_job_results with the job_id
  until done is true before you answer.
- Decide only from the action field of each result:
  send -> "send"; send_with_care -> "review"; retry_later -> "retry";
  do_not_send -> "remove".
- If likely_invented is true, answer "remove" and say it looks made up.
- Reply with JSON only: a list of {"email", "decision", "reason"}."""

client = anthropic.Anthropic()


def check(addresses: list[str]) -> list[dict]:
    response = client.beta.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=2000,
        system=SYSTEM,
        messages=[{"role": "user", "content": "Check these:\n" + "\n".join(addresses)}],
        mcp_servers=[
            {
                "type": "url",
                "url": MCP_URL,
                "name": "simpleverifier",
                "authorization_token": os.environ["SIMPLEVERIFIER_KEY"],
            }
        ],
        tools=[
            {
                "type": "mcp_toolset",
                "mcp_server_name": "simpleverifier",
                "default_config": {"enabled": False},
                "configs": {
                    "verify_email": {"enabled": True},
                    "verify_emails": {"enabled": True},
                    "get_job_results": {"enabled": True},
                },
            }
        ],
        betas=["mcp-client-2025-11-20"],
    )

    tool_errors = [
        block for block in response.content
        if block.type == "mcp_tool_result" and block.is_error
    ]
    if tool_errors:
        raise RuntimeError(f"Verification tool failed: {tool_errors[0].content}")

    text = "".join(block.text for block in response.content if block.type == "text")
    return json.loads(text)


if __name__ == "__main__":
    print(check(["jane@company.com", "sam@acme.io"]))

What each part does:

  • The allowlist. default_config disables everything, and configs enables the three tools a lead checker needs. The agent cannot call check_phone_format, check_domain or get_usage, which keeps the tool list short and the behaviour predictable. Anthropic documents this allowlist pattern on the connector page.
  • The system prompt. It makes the agent branch only on action, which has a fixed shape with no nulls: send, send_with_care, retry_later or do_not_send. Only valid ever gives send. It also handles the unfinished job case, where verify_emails returns a job_id after its 45 second wait and the agent finishes with get_job_results.
  • The model name is the one the connector page shows in its supported list. Use whichever supported model fits your budget.
  • Tool errors. The response has mcp_tool_use and mcp_tool_result blocks, and a result with is_error set means the call failed. The script raises on that instead of letting the model paper over it.

Do not trust the model with the final send

The model reads the tool results and writes JSON. It can still be wrong. If this feeds a sender, enforce the rule in code too. Verify with a second, deterministic path for anything that matters:

import os
import requests

def action_for(email: str) -> str:
    r = requests.get(
        "https://simpleverifier.com/api/v1/verify",
        params={"email": email},
        headers={"Authorization": f"Bearer {os.environ['SIMPLEVERIFIER_KEY']}"},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["action"]

Use the agent for judgement and summaries, and let your own call decide whether a send is allowed. The reply fields are listed in the API docs.

Handling 402 and 429

The server answers with the HTTP errors below. How the connector reports one to you (a failed tool result, or an error on the whole request) is Anthropic's behaviour, so test it once with a revoked key and a burst of calls before you rely on it. Either way your script has two jobs: notice, and decide whether to retry.

Failure Cause What your script should do
429 More than 120 requests a minute. REST and MCP share the limit, and every MCP request counts, including initialize and tools/list Wait, then retry the whole call. An agent that loops over many addresses can hit this. Batch with verify_emails
402 Starter plan, lapsed subscription, or a yearly plan that has used this month's included calls Stop and alert. Retrying cannot fix it. See errors
401 Wrong or revoked key Stop. Create a new key
Slow call A mailbox check can take up to 30 seconds on a slow mail server Expect it. Do not set short client timeouts

A simple wrapper retries only the rate limit. Adjust the string check to however the failure shows up in your test:

import time

def check_with_retry(addresses, attempts=3):
    for attempt in range(attempts):
        try:
            return check(addresses)
        except RuntimeError as error:
            if "429" in str(error) and attempt < attempts - 1:
                time.sleep(30 * (attempt + 1))
                continue
            raise

Cost control

Every tool call counts against the same calls as REST: 10,000 a month included on Pro, then $1.50 per 1,000 on monthly billing. On yearly billing the included calls are a fixed monthly quota, and further calls return 402 until the 1st (UTC). Three habits keep spend predictable:

  1. Use verify_emails for groups instead of one tool call per address.
  2. Deduplicate before the call. The server deduplicates within a batch, but your agent should not ask twice.
  3. Cache results in your own database by address for as long as is sensible for your use, so the agent does not re-check the same lead.

Model usage is billed separately by Anthropic.

Safety notes

  • Keep both keys on your server. Never ship them to a browser. The SimpleVerifier docs say the same for the REST API.
  • The authorization_token is sent to the MCP server with each request. Use a dedicated API key for the agent so you can revoke it alone on the API keys page.
  • Do not paste real customer lists into prompts you are not allowed to share with a model provider. Think about who may see the addresses.

The short version

Add https://simpleverifier.com/api/mcp to mcp_servers, enable only verify_email, verify_emails and get_job_results, and pass your key as authorization_token with the MCP beta header. Branch on action, stop on 402, retry 429 with a wait, and keep a deterministic check in front of any send. The full tool list and limits are on the MCP docs.

Common questions

Do I need to build an MCP client to use an MCP server with the Claude API?

No. Anthropic's MCP connector lets the Messages API connect to a remote MCP server directly. You list the server in mcp_servers and enable its tools with an mcp_toolset entry in tools. Anthropic documents it as a beta feature that requires a beta header.

What kind of MCP server works with the connector?

Anthropic's documentation says only tool calls are supported, and the server must be publicly reachable over HTTP, with Streamable HTTP and SSE supported. Local STDIO servers cannot be connected directly. SimpleVerifier's server is a public Streamable HTTP endpoint.

Should the agent use verify_emails or verify_email?

verify_email for one address at a time, such as an agent that finds a contact and checks it. verify_emails for up to 100 addresses in one call. Lists beyond that belong in a CSV upload.

How do I stop the agent from emailing risky addresses?

Put the rule in the system prompt and enforce it again in your own code. The model decides which tool to call, but your code should read the returned action and refuse to send unless it is send.

What happens when the key hits a 402 or 429?

The tool call fails and the agent sees an error result. A 429 means more than 120 requests a minute, so wait and retry. A 402 means the plan has no API access or a yearly quota is used, which no retry fixes.

Check your list before you send

Real mailbox checks over SMTP, and nothing is sent to the address. Sign in with Google and your first 100 email checks are free, no card. Plans for bigger lists are on the pricing page.