enterprise-scout-mcp
# enterprise-scout-mcp
[](https://github.com/LingerDavid/enterprise-scout-mcp/actions/workflows/test.yml)
企业工商/穿透情报 **MCP 服务**。Python 编排层(人设、风控路由、行为配额)+ 多通道采集,输出到 [EnterpriseLake](../EnterpriseLake) `G:/enterprise_lake/`。
与 `enterprise-mcp-server`(Handaas 单源 API)互补:工商主路径只走 ENScan_GO;Handaas 为可选付费补源。
## MCP 工具
| 工具 | 说明 |
|------|------|
| `enterprise_collect` | 按关键词采集(平台 / 深度 / fields / persona);股权请用 `aiqicha`,勿默认天眼查 |
| `enterprise_search` | 轻量搜索(depth=0) |
| `enterprise_collect_batch` | 批量采集(支持 checkpoint) |
| `enterprise_equity_tree` | 从湖边表本地 BFS 组穿透树(只读) |
| `enterprise_equity_expand` | 按需用 **aiqicha** 迭代补采缺失法人邻居(拒绝 tyc) |
| `scout_sessions` | 查看统一 cookie 注册表(GSXT / 爱企查 / ENScan) |
| `sync_enscan_cookies` | 把本地 cookie 写入 ENScan config |
| `scout_drain_retry` | 重跑 `raw/retry_queue`(成功则归档) |
| `scout_doctor` | 检查 ENScan / Handaas / 人设(可 probe sidecar) |
| `scout_sidecars` | 探活 ENScan / proxy_pool |
| `scout_import_neo4j` | warehouse parquet → Neo4j(默认 dry_run) |
## 快速启动
```powershell
cd E:\Project\enterprise-scout-mcp
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev,warehouse]"
# 浏览器回退(可选): pip install -e ".[browser]"
copy config.example.yaml config.yaml
enterprise-scout-mcp # stdio(Cursor / Hermes 默认)
enterprise-scout-mcp streamable-http # HTTP :8000
```
## Cursor / Hermes 配置
**stdio(推荐本地):**
```json
{
"mcpServers": {
"enterprise-scout-mcp": {
"command": "enterprise-scout-mcp",
"args": [],
"cwd": "E:/Project/enterprise-scout-mcp"
}
}
}
```
**streamable-http:**
```json
{
"mcpServers": {
"enterprise-scout-mcp": {
"type": "streamableHttp",
"url": "http://127.0.0.1:8000/mcp"
}
}
}
```
## 开发 CLI
编排层调试(非 MCP 面):
```powershell
escout doctor
escout personas
escout collect 小米 -p aiqicha
escout collect-batch --file keywords.txt -p aiqicha --checkpoint .state/batch.json
escout import-neo4j --dry-run # 统计 warehouse 行数
escout import-neo4j # 写入 Neo4j(需 pip install -e ".[graph]")
escout sessions list # 统一查看 cookie 路径与就绪状态
escout sessions import gsxt --from-file cookies.json
escout sessions import aiqicha --from-file ./secrets/aiqicha_cookies.txt
escout sessions cdp-hint # GSXT 瑞数:真实 Chrome CDP 接管步骤
escout sessions warmup gsxt # nodriver 刷新 cookie(需 .[browser])
escout sync-cookies --from-file ./secrets/aiqicha_cookies.txt # 兼容别名 → sessions import aiqicha
escout register-hermes # 写入 ~/.hermes/config.yaml
escout doctor --probe # 含 ENScan / proxy_pool 探活 + sessions
escout smoke-sidecars # 仅 sidecar 探活(CI/脚本用)
escout smoke-collect 小米 # 实机采集冒烟(需 ENScan 运行)
escout sync-gsxt-session --from-file cookies.json # 兼容别名 → sessions import gsxt
escout sync-gsxt-session --warmup # 兼容别名 → sessions warmup gsxt
escout collect 苏州挚途 --dims registry --prefer-tier l1 -p gsxt
escout smoke-registry-l1 苏州挚途 # L1 registry 穿通验收
escout drain-retry --dry-run # 列出 retry_queue 待重跑任务
escout drain-retry --limit 20 # 重跑 captcha 队列(成功 → .archive)
escout corpus init # 创建语料目录 + 示例 JSONL
escout corpus status # L3 / judicial 语料目录状态
```
语料格式见 [docs/corpus-schema.md](docs/corpus-schema.md)。
**采集策略(三级源):** 默认 `ensan_only` — 爱企查 / 天眼查等走 ENScan L2。L1 官方工商默认 **`integrations.gsxt.search_mode: browser`**:在**真实浏览器页面环境**内调用搜索 API(绕过瑞数 CT/瑞数对 httpx 的拦截),**不要**对 412/405 盲目重试或换 IP。
| 模式 | 配置 | 说明 |
|------|------|------|
| **CDP 接管(推荐)** | `browser_cdp_port: 9222` | 真实 Chrome → Playwright `connect_over_cdp` → **Method A**:DOM 触发站点 XHR(拦截响应)/ `pajax`·`$.ajax` / 页面内 fetch |
| nodriver 自建 | `browser_cdp_port: 0` | 持久 profile + 有头浏览器;NWAF 仍可能拦截自动化指纹 |
| httpx API | `search_mode: api` | 仅 JSL 可过;瑞数 Environment Checking 会 412 — **勿对 521/412 换 IP 硬刚** |
```powershell
pip install -e ".[browser]"
escout sessions cdp-hint # 打印 Chrome 启动命令与步骤
# 1) 按 hint 启动 Chrome,打开 gsxt.gov.cn 并完成验证
# 2) config.yaml: browser_cdp_port: 9222
escout sessions import gsxt --from-file .state/gsxt_browser_export.json
escout smoke-registry-l1 苏州挚途
```
VPN/Clash:`proxy_url: http://127.0.0.1:7897` 或 `$env:HTTPS_PROXY=...`(改善连通性,**不能**单独绕过瑞数环境检测)。`routing.l1_fallback_to_l2: true` 时 L1 仍失败则降级 ENScan(`degraded=true`)。
默认 `fields`:`enterprise_info,partner,holds,invest,branch`(写入实体 + 股权边)。可用 `-f` / MCP `fields` 覆盖。可选加 `supplier`(供给边 `relation=supply`)。
**股权穿透(本地树,非天眼查计费):**
```powershell
escout collect 示例公司 -p aiqicha
escout equity-tree 示例公司 --depth 2
escout equity-expand 示例公司 --depth 2 --min-ratio 20 # 强制 aqc;勿并行
```
树读 `warehouse/edges/equity/part.parquet` 做 BFS;expand 只补从未作为 `query_keyword` 采集过的**法人**邻居(跳过自然人与分支)。边写入按 `(src,dst,relation)` 去重。
`state_persist: true` 时,日配额与路由成功率写入 `state_dir`(默认 `./.state/`)。`collect-batch --checkpoint` 断点续跑:仅 `ok`/`partial` 记为 done,`error`/`captcha`/`blocked` 下次会重试。
`neo4j.enabled` + `neo4j.auto_import: true` 时,单采 / 批采结束 / drain 成功后会自动 merge warehouse → Neo4j(需 `pip install -e ".[graph]"`)。
## Warehouse 输出
`output.parquet_enabled: true` 时写入 EnterpriseLake:
| 路径 | 内容 |
|------|------|
| `warehouse/entities/part.parquet` | 企业实体行 |
| `warehouse/edges/equity/part.parquet` | 股权/投资/分支边(partner/holds/invest/branch) |
| `raw/` / `raw/retry_queue/` | partial / captcha 分级 JSON |
列定义见 [docs/warehouse-schema.md](docs/warehouse-schema.md)(与 EnterpriseLake layout 对齐)。
## 架构
```
MCP (enterprise-scout-mcp)
└─ CollectorScheduler
├─ PersonaEngine ← 人设 UA / locale / tz / OS
├─ RiskAwareRouter ← ensan_only default for aiqicha/tyc
├─ TierAwareRouter ← L1 GSXT / L2 ENScan (--prefer-tier)
├─ BehaviorOrchestrator ← 配额 / 冷却 / 延迟
├─ EnvironmentValidator ← UA/TLS/locale/语言/geo/时区/OS
├─ disguise egress ← curl_cffi [transport] · Camoufox [camoufox]
├─ CaptchaHandler ← rotate_ip | CapSolver API | OpenCV 滑块 [captcha]
├─ GsxtOfficialChannel ← L1 registry (CDP / nodriver)
├─ EnsanGoChannel ← L2 ENScan :31000
└─ HandaasChannel ← optional paid API
```
**维度路由**(`--dims` / MCP `dims`):`registry`(L1 GSXT / L2 ENScan)、`equity`(股东/投资/分支 → ENScan)、`digital`/`ip`(备案/小程序等 → ENScan)、`credit`(Handaas 凭证可用时走付费 API)/`judicial`(本地 corpus 或 stub)/`prefer-tier l3`(`corpus/l3` JSON/JSONL)、`prefer-tier l3`(academic stub)。多维度一次采集会自动合并 payload。
模块落地状态见 `escout doctor` → `architecture` / `tiers`。
**Neo4j:**
```powershell
escout doctor # warehouse.counts + neo4j.connectivity(enabled 时)
escout import-neo4j --dry-run
escout import-neo4j # Company / HOLDS / Supplement / Conflict
```
**Phase 3 — Fine UI**(参考 `E:/Project/fine-2.7.2/README_images`:设置 + 爱企查 + 多 Tab):
```powershell
# 首次(或 venv 损坏时)
.\setup-venv.ps1 -Ui
# 推荐:不依赖 PATH 里的 escout
.\serve-ui.ps1 # 自动 build ui/dist + API :8790
.\serve-ui-dev.ps1 # API :8790 + Vite :5179 热更新
# 或手动
.\.venv\Scripts\escout serve
cd ui && npm run dev # :5179,/api 代理到 8790
```
页面:**设置**(warehouse / Neo4j / 通道)、**爱企查**(查询 + 股东/投资/分支 Tab)、**状态**(verify checklist)。
**验收:**
```powershell
escout verify --summary
pytest -q
```
可选依赖:
```powershell
pip install -e ".[transport]" # curl_cffi TLS 伪装
pip install -e ".[camoufox]" # Camoufox 浏览器出口
pip install -e ".[captcha]" # OpenCV 滑块定位
```
## Sidecar
```powershell
docker compose up -d proxy_pool
# ENScan: cd ..\ENScan_GO && .\enscan.exe -api
```
## 测试
```powershell
pytest -q
```
CI: GitHub Actions workflow `.github/workflows/test.yml` runs the same suite on push/PR.
TDQS
Scored across 10 tools
enterprise_collect, enterprise_collect_batch, and enterprise_search overlap significantly — search is explicitly described as 'collect with depth=0', so an agent may struggle to pick the right entry point. scout_doctor and scout_sidecars also both probe sidecar availability with unclear boundaries, while the sync_* tools are distinct.
Two inconsistent prefixes (enterprise_* vs scout_*) are mixed with two verb styles: action-oriented names (enterprise_collect, sync_gsxt_session) coexist with noun-style names (scout_sessions, scout_doctor, scout_sidecars). Still readable, but no single predictable pattern.
Ten tools is a reasonable, well-scoped set for an enterprise collection pipeline covering collection, sessions, diagnostics, and export. Slightly heavy given that collect/search/batch and doctor/sidecars duplicate intent.
The surface covers collection, batch, search, session management, diagnostics, Neo4j import, and retry/drain, forming a coherent pipeline. Minor gaps exist around inspecting or deleting already-collected warehouse data and no explicit export/reporting operation.