urlscan-mcp
MCP server for urlscan.io that scans URLs, searches historical scan data, and assesses indicators with compact, context-efficient summaries instead of raw API responses.
README
urlscan-mcp
An MCP server for the urlscan.io API. Scan URLs, search the historical scan corpus, and assess indicators from Claude Code, Claude Desktop, Cursor, or any other MCP client.
Fourteen tools. Python 3.10+. MIT.
Why another one
The existing urlscan MCP servers expose roughly one tool — "scan a URL" — and return the raw API response. That is a problem in practice, because a urlscan result document is frequently several megabytes: every request, every response header, every cookie. Handed to a model verbatim it swallows the context window and buries the handful of facts anyone wanted.
This server is built around four decisions:
-
Responses are shaped, not forwarded. Every tool returns a summary built for a model to reason over. The raw document stays one
full=Trueaway. Measured against live scans of a news site: 2.7 MB → 3.3 KB, a 812× reduction, on a page making 244 requests. Three real scans came in at 240×, 571× and 812×. -
It degrades instead of failing. Search and the country list work with no API key at all.
server_capabilitiesreports exactly what is available, so the model never has to discover a limitation by hitting it. -
It never implies safety it cannot evidence. The search API returns no verdict data at all — with or without a key. A tool that reads a missing verdict as "clean" reports every malicious indicator on earth as safe, so this one distinguishes no data from no findings, everywhere, and falls back to signals it can actually observe: apex domain age, Umbrella popularity rank, and submitter tags.
-
Domain and URL lookups match redirectors. urlscan records the submitted URL under
task.*and the final, post-redirect page underpage.*. Queryingpage.*alone — which is what the obvious implementation does — silently misses every domain that redirects away, and redirecting away is exactly what link shorteners, phishing redirectors and traffic distribution systems do. Verified against the live API:page.domain:lzphy.topreturns zero hits whiletask.domain:lzphy.topreturns the scan, because the page redirected to github.com. Reporting "no scans found" for an indicator that has been scanned is the same failure as reading a missing verdict as "clean", so both lookups query(page.X OR task.X).The trap is what comes next. A redirected scan's
page.*fields describe the destination, so reading apex domain age or Umbrella rank off them credits the indicator with someone else's reputation —lzphy.topinherited github.com's 13-year age and rank 1508, which in turn suppressed the "no established traffic" risk signal.assess_indicatortherefore derives reputation only from scans that actually landed on the indicator, reportsscans_redirected_awayandredirect_destinationsseparately, and says explicitly when no signal can be attributed. Manufacturing a good reputation is a worse failure than withholding a verdict.
Install
git clone <this repo>
cd urlscan-mcp
pip install -e .
Optional but recommended — a free API key from urlscan.io/user/signup:
cp .env.example .env # then set URLSCAN_API_KEY
Claude Code
claude mcp add urlscan --env URLSCAN_API_KEY=your_key_here -- python -m urlscan_mcp.server
Claude Desktop / Cursor
Add to your MCP config:
{
"mcpServers": {
"urlscan": {
"command": "python",
"args": ["-m", "urlscan_mcp.server"],
"env": { "URLSCAN_API_KEY": "your_key_here" }
}
}
}
What needs a key
Verified against the live API on 2026-08-03 — note this differs from what the
public docs imply, which is why server_capabilities exists.
| Works without a key | Requires a key |
|---|---|
search_scans and all search_by_* |
scan_url, scan_and_wait |
list_available_countries |
get_scan_result, get_page_dom |
assess_indicator |
get_quotas |
get_screenshot_url |
verdicts (present in results only) |
Verdicts never appear in search responses on the free plan, key or not —
only in individual result documents. assess_indicator runs on search, so it
reports verdicts.available: false and reasons from observable signals
instead. That is deliberate, and the reason is in the tool's own output.
Tools
Scanning
scan_url— submit a URL, return immediately with a UUIDscan_and_wait— submit, poll, and return the finished summary in one call
Retrieval
get_scan_result— summarised scan result (full=Truefor the raw document)get_page_dom— captured DOM, truncatedget_screenshot_url— screenshot and report links
Search
search_scans— raw ElasticSearch query stringsearch_by_domain— a domain and its subdomainssearch_by_ip— what else was served from an addresssearch_by_asn— everything within an autonomous systemsearch_by_hash— pivot from a known-bad resource to every page serving it
Assessment
assess_indicator— aggregate every recent scan of a domain, IP, URL or SHA-256 into one reputation picture, with explicit caveats
Account
get_quotas,list_available_countries,server_capabilities
Example
> assess_indicator for the domain in this phishing report
{
"indicator": "…",
"scans_found": 92,
"verdicts": {
"available": false,
"note": "urlscan.io did not return verdict data for these scans. This is
normal without an API key. It does NOT mean the indicator is clean."
},
"reputation_signals": {
"min_apex_domain_age_days": 6,
"ranked_in_umbrella": false
},
"risk_signals": [
"Apex domain is very young (6 days) — common in phishing.",
"Not present in the Umbrella popularity ranking — no established traffic.",
"Submitters tagged scans with 'phishing'."
],
"assessment": "No malicious verdict across 92 scan(s), but the apex domain is
only 6 days old and it has no Umbrella popularity ranking.
Treat as unproven rather than benign."
}
Development
pip install -e ".[dev]"
pytest
35 offline tests — no network, no key required. They cover query escaping,
redirector matching (page.* vs task.*),
input validation, auth degradation, response shaping against malformed
documents, and the assessment logic's refusal to imply safety.
Limits
- Verdict-based search (
verdicts.score:>50) requires a paid urlscan plan and returns HTTP 403 otherwise. - Structure and similarity search are Pro-only and are not wrapped here.
assess_indicatorreads the last 100 matching scans, not the full history.- urlscan verdicts are heuristic and community-influenced. Nothing here is ground truth, and the tools say so in their own output rather than leaving the model to infer it.
- Cloaked pages routinely serve different content to scanners than to victims. A clean scan is evidence about one fetch, from one country, at one time.
Who built this
I build MCP servers and LLM agent integrations against real systems. If you have an internal API your team would want to drive from Claude, Cursor, or any other MCP client, that is a fixed-price, five-day job — aryan.kshir10@gmail.com.
Also: DEEP, a local-first AI assistant with a cybersecurity engine, MIT.
MIT. Not affiliated with urlscan.io.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。