🔍 Search MCP Server
安全研究搜索聚合 MCP 服务器 —— 一站式搜索微信公众号、奇安信攻防社区、先知社区的安全技术文章,可选叠加 KimiCode 通用全网搜索。
✨ 特性
- 🔎 多源聚合 — 微信公众号 / 奇安信攻防社区 / 先知社区,一个指令搜遍安全垂直站点
- 🌐 通用全网(可选) — 接入 KimiCode 搜索/抓取接口,补齐三个垂直源覆盖不到的全网内容
- 🛡️ TLS 指纹规避 —
curl_cffiChrome TLS 指纹,降低搜狗反爬/验证码触发;先知文章走 Playwright 过 WAF JS 挑战 - 🧠 智能召回 — 本地源 0 命中时自动剥离版本号/噪声词、拆中英连写并重搜一次(如
fastjson1.2.80利用→fastjson) - 🧹 结果整理 — 跨源按 URL 去重、摘要空白归一化与预览截断、可选按日期排序
- 📄 文章全文提取 — 自动识别来源提取干净正文,保留代码块;未知来源回退 KimiCode 抓取
- ⚡ 并发搜索 —
search_all多源同时查询
📦 安装
pip install -e .
python -m playwright install chromium # 先知文章获取需要
⚙️ MCP 配置
{
"mcpServers": {
"search-mcp": {
"command": "python",
"args": ["-m", "search_mcp"],
"env": {
"KIMI_CODE_API_KEY": "sk-kimi-xxxxxxxx"
}
}
}
}
command需指向装了本包的那个 Python(pip install -e .所在环境),也可用控制台脚本search-mcp。KIMI_CODE_API_KEY:KimiCode 的密钥(sk-kimi-...),仅search_web与search_all(include_web=True)需要;不配也不影响三个本地源。- ⚠️ 它不是 Kimi/Moonshot 开放平台的
KIMI_API_KEY,两者不通用。 - 缺失时相关工具返回友好提示而非报错。
🖥️ CLI 模式
无子命令时启动 MCP 服务器;带 search / fetch 子命令时为一次性 CLI,复用与 MCP 完全相同的工具函数,结果一致。
search-mcp search "fastjson1.2.80利用" # 默认聚合本地三源(含自动降级召回)
search-mcp search "spring利用" --web # 叠加 KimiCode 全网(需 key)
search-mcp search "XSS" --source butian # 指定单源
search-mcp search "SSRF" --source web --json # 全网 + 原始 JSON 输出
search-mcp search "RCE" --sort-by-date # 按日期倒序
search-mcp fetch https://xz.aliyun.com/t/xxxx # 取文章全文
search 选项:--source {all,weixin,butian,xianzhi,web}、--web、--page、--limit、--content、--sort-by-date、--json。每源命中状态打印到 stderr,结果到 stdout(便于管道处理)。
🛠️ 工具一览
| Tool | 参数 | 说明 | | ---------------- | ------------------------------------------------- | ---------------------------------------------------------- | | search_weixin | query, page=1 | 搜索微信公众号文章(搜狗微信搜索) | | search_butian | query, page=1 | 搜索奇安信攻防社区文章 | | search_xianzhi | query, page=1 | 搜索先知社区文章 | | search_all | query, page=1, include_web=False, sort_by_date=False | 并发搜索本地三源(include_web=True 叠加全网),去重合并,附 sources 状态 | | search_web | query, limit=10, include_content=False | KimiCode 通用全网搜索(需 key;query 出网至 api.kimi.com) | | fetch_article | url | 获取文章全文,自动识别来源路由;未知来源回退 KimiCode 抓取 |
💡 本地源(butian/xianzhi/微信)的站内搜索是字面匹配,带版本号或中文连写复合词易 0 命中——已由智能召回兜底;查具体版本/CVE 也可直接用
search_web。
返回格式
{
"results": [
{
"title": "文章标题",
"url": "https://...",
"abstract": "摘要预览(空白已归一化,约 200 字内)",
"source": "weixin",
"author": "公众号名 / 站点名",
"date": "2025-01-01",
"content": "完整正文(仅 search_web include_content=True 时)"
}
],
"count": 10,
"sources": { "weixin": 10, "butian": 8, "xianzhi": 0, "web": 4 }
}
- 空字段自动省略;
sources仅search_all返回(值为条数或"error",便于区分"没结果"与"该源被限流/验证码挡住")。 - 跨源结果按归一化 URL 去重,本地原生抓取优先于全网的同链接重复项;
count为去重后的数量。
🔐 反爬绕过原理
| 来源 | 搜索 | 文章获取 | 技术方案 | | ------------ | ------------------ | ---------- | ------------------------------------------------ | | 微信(搜狗) | curl_cffi | curl_cffi | Chrome TLS 指纹 + JS 跳转 URL 拼接解析 | | 奇安信 | curl_cffi | curl_cffi | 无反爬限制 | | 先知 | curl_cffi + CSRF | Playwright | CSRF Token + Alibaba WAF JS Challenge (headless) | | 全网(Kimi) | KimiCode HTTP API | KimiCode | 官方 search/fetch 接口(需密钥) |
TLS 指纹用于规避/降低搜狗反爬触发,并非验证码自动求解;被拦截时对应源返回空结果。
🧩 扩展新来源
在 search_mcp/scrapers/ 下新建 scraper,三步搞定:
# search_mcp/scrapers/your_source.py
from .base import BaseScraper
from ..types import SearchResult
class YourScraper(BaseScraper):
name = "your_source"
async def search(self, query: str, page: int = 1) -> list[SearchResult]:
# 实现搜索逻辑;用 await self._fetch(url) 发请求
...
async def fetch_article(self, url: str) -> str:
# 实现文章提取逻辑
...
然后在 scrapers/__init__.py 与 server.py 中注册即可。
📁 项目结构
search_mcp/
├── __init__.py
├── __main__.py # 入口
├── server.py # MCP 工具注册 + 去重/清洗/召回兜底
├── types.py # SearchResult 数据模型
└── scrapers/
├── base.py # BaseScraper (curl_cffi AsyncSession)
├── weixin.py # 微信搜索
├── butian.py # 奇安信攻防社区
├── xianzhi.py # 先知社区
└── kimi.py # KimiCode 通用全网搜索 / 抓取





