sitecheck-mcp
MCP server that answers "is this website legit or a scam?". It gathers evidence from registration data, TLS, DNS, certificate-transparency and archive history, crowd-sourced phishing/malware feeds, optional reputation APIs, brand look-alike analysis and the landing page itself, and returns a weighted verdict with the reasons behind it.
Verdicts: low_risk · caution · suspicious · likely_scam · dangerous
(any critical signal) · not_registered. low_risk means no evidence
found, not verified safe: fresh scam domains go unlisted for hours to days.
Tools
| Tool | Parameters | What it does |
|---|---|---|
check_site |
url, fetch_page=True, keep_query=False |
Full assessment: verdict, 0-100 risk_score, red_flags, trust_signals, facts, coverage, next_steps |
domain_intel |
domain |
Age, registrar, .au registrant + ABN/ACN, TLS (DV/OV/EV), DNS/mail, Tranco rank |
reputation |
url, keep_query=False |
Blocklists + reputation APIs only |
lookalike_check |
domain |
Typosquats, homoglyph/IDN spoofs, brand-stuffed names |
inspect_page |
url, keep_query=False |
One guarded GET + content red flags |
verify_business |
abn_or_acn |
ABN/ACN checksum + Australian Business Register lookup |
source_status |
refresh_feeds=False |
Which sources are configured; feed ages |
Evidence sources
| Source | Key? | Signal |
|---|---|---|
| RDAP (rdap.org) | no | registration date, registrar, status |
| auDA WHOIS (port 43) | no | .au registrant entity + ABN/ACN (.au RDAP has no creation date) |
| DNS (dnspython) | no | resolves, MX/SPF/DMARC |
| TLS handshake | no | validity, issuer, DV/OV/EV, certificate organisation |
| crt.sh | no | first certificate ever logged (age lower bound) |
| Wayback CDX | no | first archive capture (age lower bound) |
| Tranco top-1M | no | popularity rank (top 100k kept) |
| Phishing.Database ACTIVE | no | crowd-sourced active phishing domains (~390k) |
| OpenPhish community | no | live phishing URLs |
| URLhaus online feed | no | live malware URLs |
| ABN/ACN checksum | no | fake business numbers fail the check digits |
| Google Safe Browsing v4 | SAFE_BROWSING_API_KEY |
Google's phishing/malware lists |
| VirusTotal v3 | VIRUSTOTAL_API_KEY |
engine verdicts, community votes, WHOIS age |
| urlscan.io search | URLSCAN_API_KEY |
community scans + verdicts |
| URLhaus host API | ABUSECH_AUTH_KEY |
host malware history |
| ABN Lookup | ABN_LOOKUP_GUID |
entity name, status, registration date |
Trustpilot and ScamAdviser were evaluated and left out: both refuse non-browser clients (403), and working around bot protection is out of scope.
Feeds are cached in ~/.cache/sitecheck-mcp (SITECHECK_CACHE_DIR) and
refreshed on use (Tranco weekly, phishing feeds 6–12 h). A failed refresh
keeps serving the stale copy.
Safety design
- No SSRF: every host is resolved and refused unless all its addresses are globally routable (no loopback, RFC1918, 100.64/10 tailnet, link-local). The page fetcher re-checks on every redirect hop.
- Query strings stripped by default before any fetch or lookup:
phishing links carry per-recipient tokens, and fetching one tells the
sender the message was opened.
keep_query=trueopts in. - Lookups only: nothing is submitted for scanning (VirusTotal/urlscan submissions are public).
- One plain GET, no JavaScript, no cookies kept, 2 MB cap, 6 redirects max.
- Logs record tool name, outcome and duration only, never arguments.
Scoring
An additive model from a baseline of 10: red flags add points, trust signals
subtract. Any critical signal forces dangerous (feed listing, Safe
Browsing, ≥3 VirusTotal engines, homoglyph of a brand, a brand domain as a
subdomain, a brand login page on the wrong domain). The weights are judgement
calls, not probabilities; see scoring.py. Feed hits are exact-host:
the phishing lists include shared platforms (sites.google.com), which are
downgraded to informational. The same goes for URLhaus's per-host count
(drive.google.com carries thousands of uploaded malware URLs). The platform
list (SHARED_PLATFORM_HOSTS in checker.py) holds exact hosts where many
users share one hostname. Per-user subdomains (x.netlify.app) are their own
site, and an exact-URL listing stays critical everywhere.
Whose reputation counts:
- Rank, age and the registrant's ABN belong to the registered domain. They
vouch for the host only if it resolves and isn't borrowing someone else's
name. A dead hostname or a fake-.au host gets none of them (noted as
not credited). - A live subdomain gets a scaled share of its parent's rank (
parent_popular): −30 under a top-1k parent, −15 under a top-10k one. - Fake .au suffixes (
fake_au_suffix):x.au.com(au.com is KDDI's ordinary .com),x.comau.shop,-com-aulabels, and.com.au/.gov.auinside a subdomain (mygov.gov.au.verify.top). A real .com.au needs an ABN/ACN to register; these look the same and need nothing. - Young ABNs earn no trust: an active registration under a year old gives
no credit, and under 90 days is a mild flag. Scam operators register real
Pty Ltds. The age comes from
AbnStatusEffectiveFrom, because the ABR JSON has no original-registration date.
Known limit: sites behind a JavaScript bot gate hide their storefront from
the fetch. A home-made gate ("verifying your browser") on a young, unranked
site is scored as a cloaking signal, and the content checks report
blocked by ... bot challenge.
Install
uvx sitecheck-mcp --stdio # or: pip install sitecheck-mcp
Claude Desktop / Claude Code (stdio):
{"mcpServers": {"sitecheck": {"command": "uvx", "args": ["sitecheck-mcp", "--stdio"]}}}
Every reputation API key is optional; source_status shows which sources are active.
Running
uv run --env-file .env sitecheck-mcp --stdio # stdio client
MCP_BEARER_TOKEN=... uv run sitecheck-mcp # HTTP :8333/mcp, bearer required
Tests
uv run --extra test pytest tests/ -q # unit + mocked (offline)
SITECHECK_LIVE=1 uv run --extra test pytest tests/test_integration.py -v # live, read-only
Metadata
Release files for sitecheck-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sitecheck_mcp-0.1.0.tar.gz | 112.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sitecheck_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 158.2 kB
Release files / sitecheck_mcp-0.1.0.tar.gz
| Download URL | sitecheck_mcp-0.1.0.tar.gz |
|---|---|
| Size | 112.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9b7574302bb17579ceeb4bc307ddcdbfe81281f7f170d99fd8d223736594aea1
|
|
BLAKE2b-256 checksum How to use checksums |
3dcce44c52414693169bfc48d03b439a4088f626a429445de9e0ab0e3dfe441a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sitecheck_mcp-0.1.0-py3-none-any.whl
| Download URL | sitecheck_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 46.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0a5fb8313055cd89b095c200730c457b071aa65e1ee9ac42f8c87c6255c6379f
|
|
BLAKE2b-256 checksum How to use checksums |
181da543b253c75215c5235378cfe420757b613134abb46e4b8470bc7bfe3534
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for sitecheck-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.