ChristianPresley/threatintel-mcp
GitHub: ChristianPresley/threatintel-mcp
将 VirusTotal 和 urlscan.io 封装为 MCP 工具,使 AI agent 能够自主完成威胁情报指标的追踪关联分析。
Stars: 0 | Forks: 0
# threatintel-mcp
一个封装了威胁情报查询 API —— **urlscan.io** 和 **VirusTotal** —— 的 [MCP](https://modelcontextprotocol.io) 服务器,使得 AI agent(例如 Claude)能够在调查过程中像分析师在终端上那样,对指标进行追踪分析。
## 为什么会有这个项目
当你调查一个可疑指标时,你会进行追踪分析:一个 URL 指向一个域名,该域名解析到一个 IP,该 IP 属于一个 ASN,一个被释放的文件具有一个哈希值,而该哈希值出现在其他扫描中。每一次跳转都是一次向不同威胁情报平台发起的 API 调用。
将这些平台作为 **MCP 工具** 暴露出来,可以让 agent 自主地并以自然语言的方式进行这种追踪分析 —— “这个域名是恶意的吗?它的主机上还有什么?” —— 同时让人类始终参与到判断环节中。MCP 是实现这一目标的完美契合点:一个小型服务器,适配任何支持 MCP 的客户端。
## 它的功能 —— 工具
| 工具 | 提供商 | 用途 |
|------|----------|---------|
| `scan_url` | urlscan.io | 提交 URL 进行实时沙箱扫描(返回一个 `uuid`)。 |
| `get_url_result` | urlscan.io | 轮询扫描 `uuid` 以获取判定结果及联系过的基础设施。 |
| `search_urlscan` | urlscan.io | 被动搜索历史扫描记录(Elasticsearch 查询语法)。 |
| `lookup_hash` | VirusTotal v3 | 对文件哈希(MD5/SHA-1/SHA-256)进行多引擎检测及威胁标签查询。 |
| `lookup_domain` | VirusTotal v3 | 查询域名的信誉、注册商、创建日期和分类。 |
| `lookup_ip` | VirusTotal v3 | 查询 IP 的信誉及托管上下文(ASN、所有者、国家)。 |
每个工具的 docstring 都被写成了一个 **“何时调用我”** 的 prompt —— FastMCP 会将类型提示和 docstring 转换为模型所能看到的 JSON Schema 和描述,因此这些工具对 agent 来说是自我文档化的。
## 架构与设计决策
**三个 urlscan 原语,三个 VT 查询。** urlscan 围绕其自身的提交 → 轮询 → 搜索循环进行建模;VirusTotal 围绕直接对象查询进行建模。这种映射使得每个工具都是对一个 endpoint 的轻量级、可预测的封装。
**紧凑、结构化的输出 —— 而非原始的 API JSON。** 单个 VirusTotal 文件报告或 urlscan 结果可能高达数百 KB(每个 AV 引擎的判定、完整的 DOM、每个请求/响应)。将这些内容转储到模型的上下文中不仅浪费,还会掩盖关键信号。每个工具都会将响应投影到调查人员实际进行追踪分析时所关注的少数几个字段上 —— 检测率、威胁标签、信誉、ASN/所有者、联系过的域名/IP、首次/末次发现时间。这是一个经过深思熟虑的设计选择,在 `virustotal.py` / `urlscan.py` 中的每个 `summarize_*` 函数处都有注释说明。
**所有工具输出均被视为不受信任并进行了消歧处理。** 威胁情报响应包含 *由攻击者控制* 的内容 —— 钓鱼页面的标题、恶意域名、WHOIS 记录。MCP 工具输出对模型而言是一个 **prompt 注入攻击面**,对于在终端阅读的人类而言是一个 **点击风险**。因此,每个指标在输出时都会在一个核心拦截点(`sanitize.py`)进行消歧处理(`http` → `hxxp`,`evil.test` → `evil[.]test`,`1.2.3.4` → `1[.]2[.]3[.]4`)。
**客户端速率限制。** VirusTotal 公共层级允许每分钟 4 次请求和每天 500 次请求。基于 API 的滑动窗口限制器(`ratelimit.py`)会在本地进行节流,因此一个行为良好的服务器在正常的单分析师使用情况下永远不会触发上游的 429 错误。
**结构化错误,绝不抛出原始 traceback。** 身份验证失败、404、上游 429、超时和触及本地速率限制等都会被映射到小型的分类字典(`errors.py`)中,以便 agent 决定是重试、退避还是请求密钥。
**仅从环境中读取机密信息。** `VT_API_KEY` 和 `URLSCAN_API_KEY` 从环境变量(或本地的、被 gitignored 的 `.env` 文件)中读取。没有任何内容被硬编码。
### 传输方式:stdio vs. Streamable HTTP
- **stdio**(默认)—— 客户端通过 stdin/stdout 将服务器作为子进程启动。最适合在**单一本地分析师**使用 Claude Desktop 或 IDE MCP 客户端、并在其自己的工作站上使用自己的密钥运行时使用。
- **Streamable HTTP** (`--transport http`) —— 服务器作为长期运行的网络进程。最适合**共享的团队部署**:一个服务器持有组织的密钥和速率限制配额,多名分析师将其客户端指向该服务器。
## 设置
需要 Python 3.10+。
```
git clone https://github.com/ChristianPresley/threatintel-mcp.git
cd threatintel-mcp
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
cp .env.example .env # then edit .env and add your keys
```
获取 API 密钥:
- VirusTotal:
- urlscan.io:
## 运行
```
# stdio (local analyst) — 这是 MCP client 为你启动的:
threatintel-mcp --transport stdio
# Streamable HTTP (shared team) — 运行在端口上的长驻 server:
threatintel-mcp --transport http --host 0.0.0.0 --port 8000
```
### Claude Desktop / MCP 客户端配置
添加到 `claude_desktop_config.json`(macOS:
`~/Library/Application Support/Claude/`, Windows:
`%APPDATA%\Claude\`):
```
{
"mcpServers": {
"threatintel": {
"command": "threatintel-mcp",
"args": ["--transport", "stdio"],
"env": {
"VT_API_KEY": "your-virustotal-key",
"URLSCAN_API_KEY": "your-urlscan-key"
}
}
}
}
```
如果 `threatintel-mcp` 不在客户端的 `PATH` 中,请使用 venv 入口点的绝对路径(例如 Windows 上的 `.venv/Scripts/threatintel-mcp.exe`),或者通过 `python -m threatintel_mcp.server` 调用。
## 实战示例:追踪分析可疑域名
分析师交给 agent 一个可疑链接。一个自然的调查流程:
1. **`scan_url("http://secure-login-microsoft.example/")`** — 提交一个
*未公开的* 扫描(这样就不会惊动对手)并返回一个 `uuid`。
2. **`get_url_result(uuid)`** — 返回 `malicious: true`,品牌为
`Microsoft`(凭证钓鱼),以及一组联系过的域名/IP,包括
位于 ASN `EVIL-HOST` 上的 `page_ip: 203[.]0[.]113[.]9`。
3. **`lookup_domain("secure-login-microsoft.example")`** — VT 显示其创建
日期为三天前(新注册域名信号),并且已经有几个引擎
对其进行了标记。
4. **`lookup_ip("203.0.113.9")`** — 该托管 IP 信誉不佳,且所在的
国家与被冒充的品牌不一致。
5. **`search_urlscan("page.ip:203.0.113.9")`** — 被动地揭示了同一台主机上的*其他*
钓鱼页面,从而扩大了该活动的足迹。
五个跳转,两个提供商,一个 MCP 服务器 —— 并且记录中的每个指标
都经过了消歧处理,因此不会发生意外点击或在下游被重新解析的情况。
## 开发
```
pytest # runs the mocked test suite — no real API calls are made
ruff check . # lint
```
测试使用 `respx` 模拟所有 HTTP 交互;该测试套件绝不会接触
网络,也不需要真实的 API 密钥。
## 许可证
MIT © 2026 Christian Presley — 见 [LICENSE](LICENSE)。
标签:AI智能体, API集成, MCP, Python, 可观测性, 威胁情报, 安全, 安全规则引擎, 开发者工具, 无后门, 超时处理, 逆向工具