Skip to main content
Glama
7-e1even

search-mcp

by 7-e1even
README.md
# 🔍 Search MCP Server

> 安全研究搜索聚合 MCP 服务器 —— 一站式搜索微信公众号、奇安信攻防社区、先知社区的安全技术文章,可选叠加 KimiCode 通用全网搜索。

## ✨ 特性

- 🔎 **多源聚合** — 微信公众号 / 奇安信攻防社区 / 先知社区,一个指令搜遍安全垂直站点
- 🌐 **通用全网(可选)** — 接入 KimiCode 搜索/抓取接口,补齐三个垂直源覆盖不到的全网内容
- 🛡️ **TLS 指纹规避** — `curl_cffi` Chrome TLS 指纹,降低搜狗反爬/验证码触发;先知文章走 Playwright 过 WAF JS 挑战
- 🧠 **智能召回** — 本地源 0 命中时自动剥离版本号/噪声词、拆中英连写并重搜一次(如 `fastjson1.2.80利用` → `fastjson`)
- 🧹 **结果整理** — 跨源按 URL 去重、摘要空白归一化与预览截断、可选按日期排序
- 📄 **文章全文提取** — 自动识别来源提取干净正文,保留代码块;未知来源回退 KimiCode 抓取
- ⚡ **并发搜索** — `search_all` 多源同时查询

## 📦 安装

```bash
pip install -e .
python -m playwright install chromium  # 先知文章获取需要
```

## ⚙️ MCP 配置

```json
{
  "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`,两者不通用。
  - 缺失时相关工具返回友好提示而非报错。

## 🛠️ 工具一览

| 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`。

### 返回格式

```json
{
  "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,三步搞定:

```python
# 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 通用全网搜索 / 抓取
```