AllSearch MCP
by Windrunner20
README.md
# AllSearch MCP
面向 AI Agent 的 **Grok-first 多源搜索 MCP**:先用 Grok 建立答案与引用基线,再按任务需要调用 Tavily、AnySearch 和 Firecrawl 补充证据。
AllSearch 适合接入 Pi、OpenClaw 或其他 MCP Host。它提供统一的搜索结果结构、Provider 路由记录、引用去重、垂直领域检索和网页正文抓取,并附带一个防止搜索结果撑爆上下文的 Pi Extension。
> **项目状态:** `v0.2.0`,已完成真实 Provider 与 MCP stdio 调用验证,适合本地使用和边用边调。搜索质量策略仍会继续迭代。
## 它解决什么问题
一个 Agent 的外部搜索通常不是“选一个搜索 API”这么简单:
- Grok 擅长搜索、理解问题并生成带引用的初步答案;
- Tavily 适合补充网页结果和做独立交叉验证;
- AnySearch 对 CVE、金融、学术、法律等垂直领域更有结构化优势;
- Firecrawl 适合在已经发现 URL 后抓取完整正文。
AllSearch 将这些能力收进一个 MCP,并保持明确的优先级:
```mermaid
flowchart LR
A[Agent / MCP Host] --> B[AllSearch search]
B --> C[Grok primary search]
C --> D{Coverage & query signals}
D -->|Need web corroboration| E[Tavily]
D -->|Vertical domain| F[AnySearch]
C --> G[Merge, rank, deduplicate]
E --> G
F --> G
G --> H{Need full content?}
H -->|Yes| I[Firecrawl]
H -->|No| J[Structured evidence]
I --> J
```
### Provider 职责
| Provider | 在 AllSearch 中的职责 |
| --- | --- |
| Grok / xAI-compatible Responses | 默认主搜索、答案与引用基线 |
| Tavily | 网页补充、官方来源发现、`verify` / `deep` 交叉验证 |
| AnySearch | CVE、金融、学术、法律、健康、代码等垂直领域检索 |
| Firecrawl | 已知 URL 的正文抓取,不作为默认发现引擎 |
## 快速开始
### 1. 安装
要求:
- Python 3.11+
- 至少一个支持 `web_search` 的 OpenAI Responses-compatible Grok 端点
- Tavily、AnySearch、Firecrawl 按需配置
```bash
git clone https://github.com/Windrunner20/allsearch.git
cd allsearch
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
cp .env.example .env
chmod 600 .env
```
### 2. 配置 Provider
编辑 `.env`。下面是最常用的配置项:
```env
# Grok primary search
ALLSEARCH_XAI_API_KEY=
ALLSEARCH_XAI_BASE_URL=https://your-responses-compatible-endpoint/v1
ALLSEARCH_XAI_RESPONSES_PATH=/responses
ALLSEARCH_XAI_MODEL=grok-4.5
# Optional same-endpoint model fallback. Set to none to go straight to the
# endpoint-level fallback below when the primary model fails.
ALLSEARCH_XAI_FALLBACK_MODELS=grok-4.3
ALLSEARCH_XAI_REASONING_EFFORT=low
ALLSEARCH_XAI_MAX_TOOL_CALLS=4
# Optional endpoint-level fallback (OpenAI-compatible chat gateway; used on 402/429/5xx).
# protocol is openai-only (chat completions); the "responses" protocol is rejected at load.
# ALLSEARCH_XAI_FALLBACK_BASE_URL=https://fallback.example/v1
# ALLSEARCH_XAI_FALLBACK_API_KEY=
# ALLSEARCH_XAI_FALLBACK_MODEL=grok-4.3-fast
# ALLSEARCH_XAI_FALLBACK_PROTOCOL=openai
# Supplements
ALLSEARCH_TAVILY_API_KEY=
# Optional Tavily key pool (comma-separated extra keys; round-robin + quota failover):
# ALLSEARCH_TAVILY_API_KEYS=key2,key3,key4
ALLSEARCH_ANYSEARCH_API_KEY=
ALLSEARCH_FIRECRAWL_API_KEY=
```
`.env.example` 包含所有可配置项。进程或 MCP Host 注入的环境变量优先于 `.env`。
<details>
<summary>Responses-compatible 端点配置</summary>
官方 xAI:
```env
ALLSEARCH_XAI_BASE_URL=https://api.x.ai/v1
```
使用其他 OpenAI Responses-compatible 网关时,只需替换 base URL、模型名称和 API key:
```env
ALLSEARCH_XAI_BASE_URL=https://your-gateway.example/v1
ALLSEARCH_XAI_RESPONSES_PATH=/responses
ALLSEARCH_XAI_MODEL=your-primary-model
ALLSEARCH_XAI_FALLBACK_MODELS=your-fallback-model
ALLSEARCH_XAI_REASONING_EFFORT=low
```
Responses 推理参数使用嵌套格式:
```json
{
"reasoning": {
"effort": "low"
}
}
```
兼容网关会接收你的查询和凭据。请仅使用你信任的服务,并自行确认其隐私、计费和数据保留政策。
> 端点级 fallback 仅支持 `openai`(chat completions)协议;配置为 `responses` 会在加载配置时直接报错。
</details>
### 3. 运行健康检查
```bash
python - <<'PY'
import asyncio
from allsearch.config import load_config
from allsearch.orchestrator import Orchestrator
async def main():
app = Orchestrator(load_config())
try:
health = await app.health()
for provider in health.providers:
print(provider.name, provider.configured, provider.state)
finally:
await app.aclose()
asyncio.run(main())
PY
```
预期能看到已配置 Provider,例如:
```text
xai True idle
tavily True idle
anysearch True idle
firecrawl True idle
```
### 4. 启动 MCP
stdio:
```bash
python -m allsearch --transport stdio
```
Streamable HTTP:
```bash
python -m allsearch \
--transport streamable-http \
--host 127.0.0.1 \
--port 8000 \
--path /mcp
```
MCP Host 的通用 stdio 配置大致如下;配置键名可能因 Host 而异:
```json
{
"mcpServers": {
"allsearch": {
"command": "/absolute/path/to/allsearch/.venv/bin/python",
"args": ["-m", "allsearch", "--transport", "stdio"],
"cwd": "/absolute/path/to/allsearch"
}
}
}
```
密钥可以继续留在仓库目录的 gitignored `.env` 中,不需要复制到 Host 配置文件。
## MCP 工具
### `search`
统一搜索入口。
```json
{
"query": "核实 Python 当前最新稳定版本和发布日期",
"mode": "auto",
"depth": "verify",
"max_results": 8,
"include_domains": ["python.org"],
"fresh": true
}
```
返回包含:
- `answer`:Grok 主答案;
- `results` / `citations`:去重后的证据与引用;
- `route.stages`:实际调用了哪些 Provider、原因和延迟;
- `evidence`:唯一 URL、独立域名、跨 Provider 命中、抓取页数;
- `warnings` / `errors`:模型 fallback、Provider 错误和降级状态。
### `fetch`
通过 Firecrawl 抓取已知公共 URL 的正文,并进行 SSRF 目标检查。
```json
{
"url": "https://example.com/article",
"max_chars": 30000,
"fresh": true
}
```
### `health`
查看 Provider 配置、熔断和缓存状态,不返回密钥内容。
```json
{
"probe": false
}
```
## 搜索深度
| Depth | 行为 | 适合场景 |
| --- | --- | --- |
| `fast` | Grok 优先;证据不足时才补 Tavily;不自动抓正文 | 普通查询、当前版本、低延迟任务 |
| `balanced` | Grok 优先;按需 Tavily;高置信度垂直问题使用 AnySearch | 默认日常研究 |
| `verify` | Grok 后强制 Tavily 交叉验证;垂直问题加 AnySearch;有限 Firecrawl | 事实核验、多个来源、官方依据 |
| `deep` | 更完整的补充搜索与正文抓取 | 深度研究、需要原文的任务 |
所有深度都保持 Grok 先执行。Tavily 与 AnySearch 属于后续补充阶段,Firecrawl 只在发现 URL 后工作。
## AnySearch 垂直检索
AllSearch 会先读取目标领域的能力目录,再选择 `sub_domain` 和必填参数。
例如:
```text
CVE-2024-1234 的影响范围和修复建议
```
会被路由为:
```json
{
"domain": "security",
"sub_domain": "security.vuln",
"sub_domain_params": {
"type": "cve",
"value": "CVE-2024-1234"
}
}
```
适配器同时兼容 AnySearch 的旧版表格目录和当前分节 Markdown 目录,并会过滤非法 URL。
## Pi 集成:防止搜索撑爆上下文
仓库自带 Pi Extension:
```bash
mkdir -p ~/.pi/agent/extensions
ln -s "$(pwd)/integrations/pi" ~/.pi/agent/extensions/allsearch
```
重启 Pi,或在当前会话执行:
```text
/reload
```
检查状态:
```text
/allsearch-status
```
Pi 中会出现:
```text
allsearch_search
allsearch_fetch
allsearch_health
```
### 上下文预算
Pi Extension 不会把完整 MCP JSON 和网页正文直接放入模型上下文。
| 工具 | 单次摘要上限 | 单轮共享上限 |
| --- | ---: | ---: |
| `allsearch_search` | 8KB | 16KB |
| `allsearch_fetch` | 6KB | 16KB |
| `allsearch_health` | 4KB | 16KB |
当 Pi 当前上下文使用率超过 75% / 90% 时,单次摘要会自动收紧到 4KB / 2KB。
完整 MCP 响应保存到私有临时文件:
```text
/tmp/pi-allsearch-*/search.json
```
文件权限为 `0600`,目录权限为 `0700`。摘要不足时,Agent 可以通过 `read` 的 `offset` / `limit` 增量查看,而不是一次吞入完整结果。会话关闭时临时文件会自动清理。
> Pi Extension 与所有本地 Extension 一样,使用当前用户权限执行。只从你信任的仓库版本加载它。
## 运行与安全边界
- `.env`、虚拟环境、缓存和 Agent 临时文件均被 Git 忽略;
- Provider 错误在返回给 Agent 前会进行常见密钥模式脱敏;
- `fetch` 会拒绝 localhost、私有 IP、嵌入凭据和非 HTTP(S) URL,并且自动抓取(auto-scrape)和显式 `fetch` 都会对原始 URL 与最终重定向 URL(`final_url`)做同样的 SSRF 校验;
- URL 合并会去除常见追踪参数并按规范化 URL 去重;
- 搜索和网页内容始终被标记为不可信外部数据;
- 最终的结构化结果、引用与证据会按 `include_domains` / `exclude_domains` 做大小写不敏感、真实子域匹配的过滤(exclude 优先);自然语言 `answer` 不会被改写;
- 自动抓取每页正文有内部 30000 字符上限(截断时会加 warning),并拒绝空内容 / 过短 / 反爬壳页面(拒绝的页面不计入 `pages_fetched`);
- 搜索整体受硬总截止时间约束(`ALLSEARCH_TOTAL_BUDGET_SECONDS`):超时后不再启动后续阶段并取消未完成任务,超时响应不缓存;若主搜索已完成则返回 `partial`,严格模式下主搜索未完成则返回 `error`;
- `health` 在 xAI 处于 `idle` / `healthy` 时报告 `ok`,处于 `degraded` / `half_open` / `open` 时报告 `degraded`(熔断打开时附加 `primary_circuit_open` warning);
- `ALLSEARCH_ALLOW_DEGRADED_SEARCH=false` 时,Grok 不可用会在任何补充源(Tavily/AnySearch)执行前直接返回明确错误,而不是悄悄改成其他搜索结果。
## 测试
```bash
source .venv/bin/activate
pytest -q
```
当前测试覆盖(默认全离线,不调用外网 Provider):
- Provider 请求与响应契约(respx mock);
- Grok 模型 fallback、reasoning 参数和端点级 fallback(OpenAI chat);
- Tavily 多 Key 轮换与配额故障切换;
- AnySearch 两种 Markdown 格式;
- 路由、合并、缓存、熔断和 SSRF 检查;
- 严格模式下的主搜索门禁(补充源零调用)、group1 并发与确定顺序、单源失败不阻塞;
- 硬总截止时间:阶段不悬挂、超时不缓存、不重复报错、取消不触发熔断计数;
- 最终域过滤(大小写不敏感、真实子域、exclude 优先);
- 自动抓取的原 URL / final URL DNS 校验、低质量拒绝与 30000 字符截断;
- 配置脱敏、fallback 协议校验、Tavily pool-only 配置;
- health 的熔断到 degraded / primary_circuit_open 映射;
- MCP 工具注册与 Pi bridge 的严格字节预算和 artifact 路径保留。
真实 Provider 测试只是占位模板,默认不在 CI / 普通测试中运行,以避免消耗额度和依赖外部网络。
## 已知限制
- 搜索排序和查询改写仍需要根据真实任务持续调优;
- Responses-compatible 网关的模型可用性、延迟和计费可能随时变化;
- 当前缓存仅为进程内存缓存,没有 Redis 或跨进程共享;
- 搜索整体已有硬总截止时间,但 Provider 内部的重试与响应解析仍可能占用全部预算,极端情况下留给后续阶段的时间会变少;
- 当前没有 Docker 镜像、管理 UI 或第二次模型综合层。
## 参与贡献
欢迎提交 Issue 或 Pull Request。涉及 Provider 契约变化时,请附上脱敏后的响应结构或 fixture,不要提交真实 API key、完整私密查询或用户数据。
## License
项目元数据当前声明为 MIT。仓库尚未加入独立的 `LICENSE` 文件;正式分发或二次使用前,请先确认许可证文本。
TDQS
A3.7/5.0
Scored across 3 tools
Disambiguation5/5
Each tool has a distinct purpose: health checks service status, search performs web queries, and fetch retrieves a specific URL. No overlap or ambiguity between them.
Naming Consistency5/5
All tool names are single lowercase words (health, search, fetch), following a simple and consistent pattern. Though not verb_noun, the style is uniform across the set.
Tool Count5/5
Three tools is an ideal scope for a search service with a health check and content fetching. Each tool serves a clear, non-redundant role.
Completeness5/5
The tool set covers the full lifecycle of a search workflow: verify service health, execute a search, and fetch full content for follow-up. No obvious missing operations for the stated purpose.
Maintenance
ActivityMaintained
ResponsivenessUnresponsive