fairquery-contact-enricher
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fairquery-contact-enricherget contact emails and phones for acme.com and stripe.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Website Contact & Company Enricher
Fairquery Apify Actor that turns a list of domains into one clean row per company: business emails (validated for MX, disposable domains and typos), phone numbers (E.164), social profiles, company name, description and postal address, taken from the homepage and its contact / about / imprint pages. Plain HTTP, no browser, robots.txt respected, one request at a time per site.
When to use this Actor (LLM / tool selection)
Use it when an agent or sales-ops workflow needs to:
Add a contact email, phone and LinkedIn company page to a list of company websites (CRM enrichment, lead lists, vendor onboarding)
Find the generic inbox (
info@,sales@,support@,press@) of a company and check that its domain actually receives mailGet the legal company name and address from structured data or the imprint page (EU sites)
Collect a company's official social accounts
Do not use it to find personal emails of individuals or to scrape people's profiles. By default it returns role / generic mailboxes only (emailScope: "role"); personal LinkedIn profiles (/in/…) are never returned.
Related MCP server: Brand Intelligence MCP
How it works
Normalises each input (
https://www.Acme.com/contact,jane@acme.com,acme.com→acme.com) and removes duplicates.Reads
robots.txt(RFC 9309: missing = allowed, 5xx = disallowed) and honoursDisallowrules andCrawl-delayfor user agentFairqueryBot.Fetches the homepage, then the best-scoring same-site pages (contact, Kontakt, contacto, about, imprint/Impressum, legal notice, team…) up to
maxPagesPerDomain, waitingrequestDelayMsbetween requests to the same site.Extracts: JSON-LD
Organization/LocalBusiness(name, legalName, telephone, email, address, sameAs),mailto:andtel:links, Cloudflare-protected emails,name [at] domain [dot] comobfuscation,og:site_name,<address>blocks, social links.Validates emails with the same code as Fairquery Email Validator: syntax, DNS-over-HTTPS MX/null-MX, disposable list, free-provider and typo checks (no SMTP probing).
Input
Field | Type | Default | Description |
|
| (required) | Domains, URLs or emails |
| int |
| 1–15, homepage included |
|
|
|
|
| bool |
| MX / disposable / typo |
| bool |
| SPF/DMARC for the company mail domain |
| string | – | e.g. |
| int |
| Sites in parallel |
| int |
| Delay between requests to one site |
| int |
| Per request |
| int |
| Safety cap |
{ "domains": ["apify.com", "stripe.com", "https://basecamp.com/"], "maxPagesPerDomain": 4 }Output
{
"schema_version": "1.0.0", "type": "domain", "input": "apify.com", "domain": "apify.com", "final_url": "https://apify.com/",
"company_name": "Apify Technologies s.r.o.",
"description": "Cloud platform for web scraping, browser automation, AI agents, and data for AI…",
"emails": [
{ "email": "hello@apify.com", "source_url": "https://apify.com/contact", "is_role_account": true, "on_company_domain": true,
"is_free_provider": false, "is_disposable": false, "verdict": "valid", "reasons": ["ROLE_ACCOUNT"], "has_mx": true, "mail_provider": "Google Workspace / Gmail" }
],
"primary_email": "hello@apify.com",
"phones": [{ "e164": "+18889262289", "raw": "+1 888 926 2289", "source_url": "https://stripe.com/contact/sales", "source": "tel" }],
"social_links": { "linkedin": ["https://linkedin.com/company/apify"], "twitter": ["https://x.com/apify"], "github": ["https://github.com/apify"] },
"address": "Na Příkopě 959/27, 11000, Prague, CZ",
"mail_domain": { "has_mx": true, "null_mx": false, "mail_provider": "Google Workspace / Gmail", "has_spf": null, "has_dmarc": null, "dmarc_policy": null },
"pages_crawled": ["https://apify.com/", "https://apify.com/contact"], "pages_blocked_by_robots": 0, "robots_txt": "ok", "email_scope": "role"
}Error rows (type: "error", never charged): INPUT_EMPTY, INVALID_DOMAIN, MAX_DOMAINS_EXCEEDED, SITE_UNREACHABLE, BLOCKED_BY_ROBOTS, ENRICH_FAILED.
RUN_SUMMARY (key-value store): pages fetched, pages blocked by robots.txt, emails found vs. excluded by scope, DNS requests, charged events.
Pricing
Pay per event: domain-enriched, once per domain that returns a result row. Unreachable, blocked or invalid domains are free. See the pricing tab.
Memory / runtime
Default 256 MB, no browser, no proxy. With the default politeness settings a domain takes about 3–8 s (homepage + 4 pages, 1 s apart), and 5 domains run in parallel, so 100 domains finish in roughly 1–3 minutes. Sites that block datacenter IPs or need JavaScript to render contact details will return fewer fields.
MCP / Apify tools
Call from agents via Apify MCP with Actor fairquery/website-contact-company-enricher:
{ "actor": "fairquery/website-contact-company-enricher", "input": { "domains": ["acme.com"] } }Local stdio MCP server
The mcp/ folder is a stdio MCP server (TypeScript, @modelcontextprotocol/sdk) with two tools, both with annotations and output schemas:
Tool | What it does | Cost |
| Runs this Actor and returns the rows | Needs |
| Cleans URLs/emails into unique domains, lists invalid ones | Free, local, no token |
cd mcp && npm install && npm run build
node scripts/smoke-test.mjs # initialize + tools/list + free tool, no token
APIFY_TOKEN=... node scripts/smoke-test.mjs --call # real call{ "mcpServers": { "fairquery-contact-enricher": { "command": "node", "args": ["/path/to/website-contact-company-enricher/mcp/dist/index.js"], "env": { "APIFY_TOKEN": "<your Apify token>" } } } }Docker: the root Dockerfile builds the MCP server image (docker build -t fairquery-contact-enricher-mcp .); it is also the Dockerfile for Glama. The Actor image is .actor/Dockerfile. glama.json lists fairquery as maintainer.
Local development
npm install
npx apify run # input from storage/key_value_stores/default/INPUT.json
npm testKits & templates
Optional guides from Fairquery for wiring this Actor into agents and automations (the Actor works fine without them):
AI Agent Data Toolkit Quick-Start (PDF): MCP setup for Claude Desktop and Cursor, API calls, recipes, cost estimates.
n8n + Zapier Workflow Template Pack: 10 importable n8n workflows for the four original Fairquery Actors (SEC EDGAR, website/tech, email, OSV); it does not include workflows for this Actor yet, but the patterns adapt easily.
Agent Prompt Pack for Research & Lead Ops: 69 prompts for company research, lead cleaning, SEO and security reviews.
Agent Starter Kit: 10 copy-paste MCP + n8n recipes ($5): 10 copy-paste MCP + n8n recipes, with ready-made Claude/Cursor configs and 3 starter workflows.
Disclaimer
Returns only information that companies publish on their own websites. You are responsible for how you use it: business contact data can still be personal data under GDPR/UK GDPR, so have a lawful basis, honour opt-outs, and follow anti-spam law (CAN-SPAM, ePrivacy/PECR) when you contact anyone. DNS checks cannot prove a mailbox exists.
Links
License: MIT
Available Tools
2 toolsenrich_domainsEnrich domains with public business contactsARead-onlyIdempotent
WHAT: For each company domain, crawl the homepage plus up to N contact/about/imprint pages (plain HTTP, robots.txt respected, polite per-site delay) and return one row with company_name, description, business/role emails (MX, disposable and typo validated), phones (E.164), social profiles (LinkedIn company, X, Facebook, Instagram, YouTube, GitHub...), postal address and mail-domain info. WHEN TO USE: enriching a lead/CRM list of company websites with public contact data; finding the official contact email or address of a business. WHEN NOT TO USE: to clean/dedupe a messy list first or preview what will be billed, call normalize_domains (free). Not for finding personal emails of individuals, LinkedIn people search, or JavaScript-only sites that need a browser. COST: paid. Runs Apify Actor fairquery/website-contact-company-enricher with your APIFY_TOKEN; pay-per-event "domain-enriched", once per domain that returns a result row. Unreachable, blocked or invalid domains are free. ~2-10 s per domain. RETURNS: {count, items}. type="domain" row per domain: input, domain, final_url, company_name, description, emails[], primary_email, phones[] (E.164), social_links, address, addresses, mail_domain (MX/provider, SPF/DMARC if requested), pages_crawled, pages_blocked_by_robots, email_scope, enriched_at; or type="error" rows (code, message, retryable). EXAMPLE: {"domains":["stripe.com","https://basecamp.com/about"],"maxPagesPerDomain":3} -> 2 domain rows.
| Name | Required | Description | Default |
|---|---|---|---|
| domains | Yes | Required. Domains, website URLs or email addresses (the domain part is used); comma/semicolon lists are split. Example: ["apify.com","https://stripe.com","info@basecamp.com"]. | |
| emailScope | No | "role" (default, GDPR-friendly) = generic mailboxes only (info@, sales@, support@); "business" = also named addresses on the company's own domain; "all" = every address published on the pages. | |
| checkSpfDmarc | No | Default false. Add SPF/DMARC presence and DMARC policy for the company mail domain. | |
| validateEmails | No | Default true. DNS-over-HTTPS MX lookup plus disposable and typo checks on found emails (no SMTP probing). | |
| maxPagesPerDomain | No | Pages fetched per domain, 1-15 (default 5): homepage plus the best contact/about/imprint pages linked from it. | |
| defaultPhoneCountry | No | ISO 3166-1 alpha-2 code, e.g. "US", "DE". When set, national-format numbers in page text are also parsed; otherwise only tel: links, JSON-LD and +international numbers. No default. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows in items |
| items | Yes | Dataset rows: type=domain or type=error |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/idempotent/non-destructive, and the description layers on substantial extra context: pay-per-event billing (once per domain returning a row), free failures for unreachable/blocked/invalid domains, ~2-10 s per domain, robots.txt respect, per-site delay, and the APIFY_TOKEN requirement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Strongly front-loaded and labelled (WHAT/WHEN/COST/RETURNS/EXAMPLE), so an agent can scan it fast. It is on the long side, and the RETURNS block partially duplicates the output schema, which slightly dilutes conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema and rich annotations, the description still covers cost, auth, failure modes, timing, and scope exclusions. Nothing an agent needs to decide or invoke correctly appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so baseline is 3. The description adds genuine meaning via maxPagesPerDomain ('homepage plus up to N contact/about/imprint pages') and the validation chain behind emails (MX, disposable, typo) and optional SPF/DMARC, though most parameter detail remains in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: crawls a company domain's homepage and contact pages to return public business contact data, with the exact field set enumerated. It also implicitly distinguishes itself from normalize_domains by describing enrichment/paying-per-domain rather than list cleanup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit WHEN TO USE (lead/CRM enrichment, finding official business contact info) and WHEN NOT TO USE (list cleaning, personal emails, LinkedIn people search, JS-only sites), plus a named alternative: normalize_domains, flagged as free.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
normalize_domainsNormalize and dedupe domains (free)ARead-onlyIdempotent
WHAT: Turn URLs, email addresses and messy strings into bare registrable hostnames (lowercase, no scheme/path/www), remove duplicates and list entries that are not valid domains. WHEN TO USE: before enrich_domains, to clean an input list and see exactly which domains would be billed. WHEN NOT TO USE: to get contacts, company names or check that a site is reachable - use enrich_domains. Does no DNS lookup. COST: free; local, no network, no APIFY_TOKEN, deterministic. RETURNS: {domains: string[], invalid: string[], duplicates_removed: number}. EXAMPLE: {"inputs":["https://www.Stripe.com/pricing","info@stripe.com","not a domain"]} -> {"domains":["stripe.com"],"invalid":["not a domain"],"duplicates_removed":1}
| Name | Required | Description | Default |
|---|---|---|---|
| inputs | Yes | Required. URLs, domains or email addresses; each entry may also be a newline/comma/semicolon-separated list. Example: ["https://www.acme.com/contact","sales@acme.com"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| domains | Yes | Unique normalized domains, input order |
| invalid | Yes | Entries that could not be parsed as a domain |
| duplicates_removed | Yes | Count of duplicate entries dropped |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint=false and destructiveHint=false, and the description adds genuinely new behavioral context: it is local, free, deterministic, requires no APIFY_TOKEN, and performs no network/DNS activity. It also states why it exists ('see exactly which domains would be billed'), which no annotation conveys.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (WHAT, WHEN TO USE, WHEN NOT TO USE, COST, RETURNS, EXAMPLE) make it skimmable and front-load purpose before routing. Each block carries distinct information with no filler, and the example compactly demonstrates dedupe plus invalid-entry handling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The only parameter is fully specified and an output schema exists, so return values need no further prose; the inline RETURNS note is a bonus. Cost, side-effect profile, and pre-requisite chaining with enrich_domains are all covered, leaving no gap for an agent to fill.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is a single required parameter, so the schema already documents the input format, including the newline/comma/semicolon-separated list behavior. The description's mention of URLs, emails and messy strings plus the worked example largely restates that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with an explicit verb+resource ('Turn URLs, email addresses and messy strings into bare registrable hostnames') and enumerates the transformation rules (lowercase, no scheme/path/www). It explicitly names what it is not ('use enrich_domains') so an agent can separate it from its only sibling without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit WHEN TO USE (before enrich_domains, to preview billed domains) and WHEN NOT TO USE (contacts, company names, reachability checks), naming the alternative tool and a boundary condition ('Does no DNS lookup'). Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
enrich_domains - First observed
normalize_domains
TDQS
Scored across 2 tools
The two tools have clearly distinct roles: normalize_domains cleans and previews input locally for free, while enrich_domains performs the paid network enrichment. The descriptions explicitly state when to use each and when not to use them, eliminating overlap.
Both tool names follow the same predictable verb_noun snake_case pattern: normalize_domains and enrich_domains. The names clearly indicate the action and target resource.
A two-tool surface is thin but focused for a contact-enrichment server. The prep tool is useful, though the set could benefit from at least one additional operation for batch handling or cost estimation.
The core workflow—cleaning domains and enriching them with contact data—is covered well. Minor gaps remain around large-batch/async processing and explicit paid-cost preview, which agents may need for bigger lead lists.
Maintenance
Related MCP Connectors
Domain enrichment: email provider, DMARC/SPF/DKIM, WHOIS age, SSL, hosting and CDN per domain.
Enrich any domain into a full company profile with firmographics and buying signals.
Domain & brand intelligence: company enrichment, tech stack detection, brand research.
Company enrichment for AI agents: firmographics, tech stack, headcount, funding, domain emails.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables scraping of emails, phone numbers, and social profile links from website domains. Supports batch processing of up to 20 domains and can find company websites by keyword/company name.2MIT
- AlicenseNot gradedqualityFmaintenanceProvides domain and brand intelligence for AI agents, including company enrichment, tech stack detection, and brand research from free public sources with an on-demand cache.MIT
- AlicenseAqualityAmaintenanceEnables enriching company domains into structured firmographics including employee band, industry, HQ, founded year, revenue estimate, logo, and description, with source provenance and data completeness scoring.177 npm1MIT
- AlicenseAqualityBmaintenanceDomain and company intelligence for AI agents. Enables vetting companies, qualifying leads, and mapping targets from free public data without API keys.62 npm1MIT