sabit-mcp
Sabit · ثابت
Verified, not guessed.
A self-hostable email-verification engine in Rust. A layered, free-before-expensive pipeline (syntax → IDN/EAI → typo → gibberish → disposable/role → DNS/MX/null-MX → auth records → SMTP probe → catch-all) emits a 0–100 confidence score plus a coarse safe / risky / invalid / unknown status. The engine runs inside the sabitd server daemon; you reach it three ways — the sabit CLI, an HTTP API, and an MCP server for AI agents — all returning the same result.
Getting started · Usage · MCP · CLI · API · Architecture · Docs
Table of contents
Overview
Email verification is sold as a binary checkbox — "is this address valid?" — and that framing is why every vendor's marketed 98–99% accuracy collapses in independent tests. Hunter.io's 2026 benchmark of 15 verifiers on ~3,000 real business addresses found no tool scored above 75%; the top three were Hunter (70.00%), Clearout (68.37%), and Kickbox (67.53%). The hard part isn't syntax — it's that catch-all domains make per-mailbox SMTP probing meaningless (15–28% of B2B domains are catch-all), Yahoo returns 250 for every address as an anti-harvesting measure, and probing from a dirty IP just gets you blocklisted.
Sabit treats verification as what it actually is: a multi-signal probabilistic risk-scoring pipeline, not a yes/no checker. It layers fast, free, local checks ahead of the slow, fragile, network-bound ones, weighs every signal into a single score, and is honest about uncertainty — risky and unknown are first-class outcomes, not failures.
Use it however you work: the sabit CLI for scripts and one-off checks, the HTTP API for your backend or signup flow, or the MCP server so an AI agent can decide — with evidence — whether an address is safe to email instead of trusting a fabricated binary. Every interface talks to the same sabitd engine and returns the same result object.
Features
Layered, free-before-expensive pipeline — every check that can run offline runs first; the network is the last resort, and a null-MX or no-MX+no-A domain short-circuits to
invalidbefore any probe.0–100 confidence score + coarse status —
safe / risky / invalid / unknown, modeled on Reacher's taxonomy so existing tooling maps cleanly. You set the threshold per use case (strict for cold outreach, lenient for signup forms).Three interfaces, one result — a CLI, an HTTP API, and an MCP server all call the same engine and return the same object. The MCP tools (
verify,submit_batch,task_status,auth_check,parse_bounce,doctor) are honest by design: a tool never returnssafefor an address the protocol couldn't confirm.Never sends mail — the prober opens TCP to the MX, does
EHLO → MAIL FROM → RCPT TO → QUIT, and reads the reply code. NoDATAis ever transmitted, so no message is ever delivered.Catch-all aware — repeated randomized probes detect accept-all domains and downgrade the result to
riskyinstead of a falsevalid.Disposable & role detection, kept fresh — a real community blocklist (7k+ domains) plus MX-fingerprint clustering and role/free-webmail classification; the daemon auto-refreshes the volatile lists from source on a schedule (or
sabit lists update).Deliverability built in — SPF/DKIM/DMARC/BIMI reading, DSN/NDR bounce parsing (RFC 3464/3463), and ARF feedback-loop parsing (RFC 5965), not bolted on.
Self-hosted and private — runs on your own unblacklisted VPS; nothing about what you verify leaves your server; no telemetry.
Why Sabit
The state of the art is mostly closed SaaS that hides its method and oversells its accuracy. The strongest open prior art — Reacher / check-if-email-exists — proved the modern technique: SMTP for domains where it still works, headless provider-specific checks where it doesn't, and per-domain rule overrides. Sabit builds on that, adds an explicit weighted scoring model and a deliverability layer, and exposes it through a CLI, an HTTP API, and an MCP server so it fits a script, a backend, or an AI agent equally.
Principle | How Sabit applies it |
Cheapest signal first | Local layers (syntax/typo/gibberish/disposable) resolve obvious input before any network call |
Probabilistic, not binary | Every signal is weighted into a 0–100 score; |
Honest about uncertainty | Catch-all, anti-harvesting |
Built to integrate | One result contract over a CLI, an HTTP API, and an MCP server — evidence and confidence, not a fabricated yes/no |
Responsible probing by default | FCrDNS-checked HELO, real |
What Sabit is not
Not a sender. Sabit verifies and scores; it never delivers mail. The deliverability layer parses bounces and reads auth records, but the only thing it sends to a target MX is an envelope it abandons before
DATA.Not a guarantee. The only ground truth for deliverability and ownership is double opt-in. Everything else is inference. Sabit is built to express confidence, not to fake certainty.
Not a list-buying or scraping tool. It has no address-generation or harvesting features; dictionary attacks and list scraping are the abuse it is designed not to be.
Not a hosted SaaS. It is software you run. There is no Sabit cloud, no per-check billing, and no telemetry phoning home.
Architecture
CLIENTS (thin — no verification logic, just point at a sabitd over HTTP)
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ sabit-mcp (MCP, for agents) │ │ sabit (CLI: verify/batch/…) │
└───────────────┬──────────────┘ └───────────────┬──────────────┘
└───────────────┬──────────────────┘
HTTPS (REST + task polling)
│
════════════════════════════════▼═══════════════════════════════════ server boundary
┌──────────────────────────────────────────────────────────────────┐
│ sabitd — the daemon (runs where probing is possible: port 25, │
│ clean IP, PTR/FCrDNS). HTTP API + task/job worker (sabit-server). │
├──────────────────────────────────────────────────────────────────┤
│ sabit-core (Rust — the only place behavior lives) │
│ Local • Syntax (RFC 5321) • Typo • IDN→Punycode • Gibberish │
│ • Disposable + MX-fingerprint • Role / free classify │
│ Network • DNS: MX+A/AAAA, null-MX, SPF/DKIM/DMARC/BIMI (hickory) │
│ • SMTP probe: RCPT-TO, no DATA, greylist retry │
│ • Catch-all detection • Per-provider routing │
│ • Bounce/DSN parser • Feedback-loop ingester │
│ Scoring • Weighted 0–100 score → {safe|risky|invalid|unknown} │
└──────────────────────────────────────────────────────────────────┘All verification behavior lives in sabit-core, which runs only inside sabitd — the
server daemon on a host that can actually probe (outbound port 25, a clean IP, matching
PTR/FCrDNS). The sabit CLI and sabit-mcp are deliberately thin: they translate transport and
relay the result contract, holding no engine logic, so a laptop or an agent host needs nothing
special. The core still splits cleanly into a local half (pure, offline, deterministic —
verify --local) and a network half (DNS + SMTP). Full reasoning is in
ARCHITECTURE.md.
The result contract
Every interface returns the same object. A verify of one address:
{
"input": "jane.doe@example.com",
"status": "safe",
"score": 96,
"syntax": {
"valid": true,
"normalized": "jane.doe@example.com",
"domain": "example.com",
"is_idn": false,
"is_eai": false
},
"mx": { "accepts_mail": true, "null_mx": false, "records": ["aspmx.l.example.com"] },
"smtp": {
"can_connect": true,
"is_deliverable": true,
"is_catch_all": false,
"has_full_inbox": false,
"is_disabled": false,
"verif_method": "smtp"
},
"misc": { "is_disposable": false, "is_role_account": false, "is_free": false },
"auth": { "spf": true, "dkim": true, "dmarc": "p=reject", "bimi": false },
"signals": { "gibberish": 0.02, "typo_suggestion": null, "greylisted": false },
"took_ms": 812
}status is the coarse verdict; score is the tunable number; signals and the per-layer blocks are the evidence. See the result object and How it works.
Getting started
No compiler needed — the installer pulls prebuilt binaries.
1. Run the server (sabitd) on a probing-capable host (port 25 open, clean IP, PTR/FCrDNS):
curl -fsSL https://raw.githubusercontent.com/ruwadgroup/sabit/main/install.sh | sh -s -- daemon
sudoedit /etc/sabit/sabit.toml # set smtp.helo to this host's FQDN (matching its PTR)
sudo systemctl enable --now sabitdFront it with a TLS-terminating proxy and enable server.api_key_file before exposing it. Full
guide: packaging/README.md.
2. Point a client at it (laptop / CI / next to an agent):
curl -fsSL https://raw.githubusercontent.com/ruwadgroup/sabit/main/install.sh | sh -s -- cli mcp
mkdir -p ~/.config/sabit && $EDITOR ~/.config/sabit/config.toml # set your sabitd url + token
sabit doctor # can the SERVER probe? (port 25, PTR/FCrDNS)
sabit verify jane.doe@example.com # one address
sabit batch contacts.csv --out results.jsonl # async task: submit, poll, fetch
# Or use it from an AI agent (Claude Code) over MCP:
SABIT_SERVER=https://sabit.example.com SABIT_TOKEN=sk_live_… \
claude mcp add sabit -- sabit-mcpSee Getting started and Use with AI agents.
Documentation
Doc | What you'll find |
Install the server, configure a client, first verification | |
Everyday CLI usage — verify, batch tasks, auth, bounces | |
The MCP server: setup, tools, a typical agent flow | |
Every command and flag | |
Endpoints, bearer auth, the result object, errors | |
Server ( | |
Running | |
The scoring model, the pipeline, and honest uncertainty | |
The deep design reference |
Start at docs/README.md.
Repository layout
sabit/
├── crates/
│ ├── sabit-core/ # the engine: local + network layers + scoring (server-side only)
│ ├── sabit-server/ # HTTP API + task/job worker (lib, used by sabitd)
│ ├── sabitd/ # the server DAEMON — runs the engine + API on a probing-capable host
│ ├── sabit-client/ # thin HTTP client + multi-instance config (shared by the clients)
│ ├── sabit-cli/ # the `sabit` binary — a thin client of a sabitd instance
│ └── sabit-mcp/ # the MCP server — a thin client that exposes sabitd to agents
├── packaging/ # systemd unit, sysusers/tmpfiles, default config, nfpm (.deb/.rpm)
├── data/ # disposable lists, MX fingerprints, rules.json, name corpus
├── conformance/ # fixtures + cross-interface accuracy harness
├── docs/ # everything in the table above
└── .github/ # CI, release, security scanning, templatesServer vs. client. Verification only happens in sabitd, which must run where SMTP probing
is possible — a host with outbound port 25, a clean IP, and matching PTR/FCrDNS (a VPS, not a
laptop). The sabit CLI and sabit-mcp carry no verification logic; they point at one (or more)
sabitd instances over HTTP and relay the result. Install and operate the daemon per
packaging/README.md.
Roadmap
The engine (local + DNS + SMTP layers, catch-all detection, per-provider routing, scoring), the sabitd HTTP API with the async task system, bearer auth, the deliverability parsers (DSN, ARF), and the Linux packaging are in place. On the roadmap: populated community data bundles with a refresh mechanism, an SMTP-verdict cache, a broader per-provider headless module set (Outlook B2C / Yahoo), real STARTTLS upgrade, a Streamable-HTTP MCP transport, and shared/persistent task storage. Full plan: ROADMAP.md.
Responsible use
SMTP probing uses the same handshake spammers use to harvest addresses, and aggressive probing can violate a receiving provider's ToS and get your IP blocklisted. Sabit ships responsible defaults — FCrDNS-checked HELO, a real MAIL FROM, per-domain rate caps, jittered backoff, and never sending DATA — but the operator is responsible for lawful use. Verifying a list you already hold for a legitimate purpose is generally defensible; probing arbitrary harvested addresses is not. See Deployment → responsible probing. This is technical guidance, not legal advice.
Contributing
Contributions are welcome — especially disposable-domain and MX-fingerprint updates, per-provider rules (data/rules.json), accuracy-corpus addresses (with permission), and SMTP edge-case reports. Read CONTRIBUTING.md for the invariants, dev setup, and commit conventions (Conventional Commits with enforced scopes).
Community & support
Bugs & features — GitHub issues (structured templates)
Security reports — privately, per SECURITY.md
Governance — GOVERNANCE.md
License
Apache-2.0. Sabit bundles community disposable-domain lists and an n-gram name corpus under their own licenses — see LICENSING.md.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ruwadgroup/sabit'
If you have feedback or need assistance with the MCP directory API, please join our Discord server