内容
# websearch-mcp
基于代理的网页信息获取系统,集成了多引擎搜索和内容抓取功能,提供统一的接口。通过 MCP 服务器和 LLM 友好的 CLI 公开,使其能够为下游 LLM 工作流提供结构化、多源的网页数据检索。
## 功能特点
- **多引擎网页搜索** — DuckDuckGo 和 Tavily,可按查询选择
- **内容抓取** — 通过 URL 抓取完整页面内容(直接 HTTP 或基于 CDP)
- **双接口** — MCP 服务器用于基于协议的集成,CLI 用于直接调用
## 快速开始
### MCP 服务器
```bash
go build -o websearch-mcp ./cmd/server/
./websearch-mcp
```
服务器监听端口 `8848`(可通过 `PORT` 环境变量或 `--port` 标志配置)。
### CLI
```bash
go build -o websearch-cli ./cmd/cli/
```
```bash
# 搜索
websearch-cli search <查询> [--engine duckduckgo|tavily]
# 抓取
websearch-cli fetch <网址> [--method direct|cdp] [--cdp-mode connect|system|bundled] [--mode full|summary|title] [--no-cache]
```
输出 LLM 友好的文本到 stdout。成功退出代码为 0,失败为非零。
## 环境变量
| 变量 | 默认值 | 描述 |
| --- | --- | --- |
| `PORT` | `8848` | 服务器监听端口 |
| `SEARCH_ENGINE` | `duckduckgo` | 默认搜索引擎(`duckduckgo` 或 `tavily`) |
| `TAVILY_API_KEY` | — | Tavily 搜索 API 密钥 |
| `TAVILY_SEARCH_DEPTH` | `basic` | Tavily 搜索深度:`basic`、`advanced`、`fast` 或 `ultra-fast` |
| `TAVILY_MAX_RESULTS` | `7` | Tavily 搜索最大结果数(1-20) |
| `TAVILY_TOPIC` | `general` | Tavily 搜索主题:`general`、`news` 或 `finance` |
| `FETCH_METHOD` | `direct` | 默认抓取方法(`direct` 或 `cdp`) |
| `CHROME_DEBUG_ADDR` | `localhost:9222` | Chrome DevTools WebSocket 地址(用于 `cdp` `connect` 模式) |
| `CDP_MODE` | `connect` | `cdp` 方法的浏览器来源:`connect`、`system` 或 `bundled` |
| `CHROME_BIN` | — | 重写 Chrome/Chromium 二进制文件路径(用于 `CDP_MODE=system`) |
| `CACHE_MAX_ENTRIES` | `128` | 最大抓取缓存条目数 |
| `CACHE_TTL` | `5m` | 缓存生存时间(例如 `30s`、`5m`、`1h`) |
| `CACHE_MAX_ENTRY_SIZE` | `524288` | 每个缓存条目的最大字节数(默认 512KB) |
优先级:显式请求参数 > CLI 标志 > 环境变量 > 默认值。
所有参数都验证其值。传递未知值(例如 `--method=foobar`、`engine: "saki"`)会产生一个错误,列出有效的选择。省略参数时使用默认值。
## 代理配置
Go 的 `net/http` 默认使用 `ProxyFromEnvironment`,它从环境变量 (`HTTP_PROXY`、`HTTPS_PROXY`、`NO_PROXY`) 读取代理设置。它不会自动与操作系统级别的代理设置集成(例如 Windows Internet 选项或 macOS 网络偏好设置)。
如果您在代理后面,请在运行之前设置这些:
```bash
# Linux / macOS
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
# Windows (PowerShell)
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
# Windows (Command Prompt)
set HTTP_PROXY=http://127.0.0.1:7890
set HTTPS_PROXY=http://127.0.0.1:7890
```
用您的代理地址替换 `127.0.0.1:7890`。使用 `NO_PROXY` 排除主机(例如 `NO_PROXY=localhost,127.0.0.1,::1,.local`)。
对于 `cdp` 抓取方法,Chrome 浏览器不使用 `HTTP_PROXY` / `HTTPS_PROXY`。相反,Chrome 依赖于:
- 操作系统系统代理设置(Windows Internet 选项,macOS 网络偏好设置)
- 或显式 `--proxy-server` 标志
`CDP_MODE` 选项都不默认传递 `--proxy-server`。在 `connect` 模式下,在启动 Chrome 时添加它:
```bash
chrome --remote-debugging-port=9222 --proxy-server=http://127.0.0.1:7890
```
在 `system` 或 `bundled` 模式下,Chrome 可能仍然通过操作系统系统代理工作(例如,Clash on Windows 自动设置此项),但这取决于操作系统,不由工具控制。
## CDP 浏览器模式
当 `FETCH_METHOD=cdp` 时,`CDP_MODE` 环境变量控制 Chrome/Chromium 浏览器的获取方式:
| 模式 | 行为 | 首次使用 | 清理 |
| --- | --- | --- | --- |
| `connect`(默认) | 连接到已运行的 Chrome,地址为 `CHROME_DEBUG_ADDR` | 无 | 永不杀死浏览器 |
| `system` | 查找并启动系统安装的 Chrome/Chromium/Edge | 无;如果未找到则报错(提示使用 `bundled`) | 退出时杀死浏览器 |
| `bundled` | 自动下载 rod 自带的 Chromium | 下载约 150MB | 退出时杀死浏览器 |
### `connect` 模式
默认模式。需要事先启动 Chrome 并启用调试端口:
```bash
# 必须使用 --user-data-dir 如果 Chrome 已经运行,否则该标志将被忽略
chrome --remote-debugging-port=9222 --user-data-dir=<临时目录>
```
**常见陷阱:** 运行 `chrome --remote-debugging-port=9222` 而 Chrome 已经打开时 **无效** — 现有进程会静默忽略该标志。始终传递 `--user-data-dir` 以强制启动新实例,或改用 `system`/`bundled` 模式。
### `system` 模式
自动查找系统浏览器。首先检查 `CHROME_BIN` 环境变量,然后在 `PATH` 上查找 `google-chrome`、`chromium`、`chrome`、`msedge`、`brave`。如果未找到任何,报错并建议切换到 `CDP_MODE=bundled`。
### `bundled` 模式
无需手动设置。首次运行时,rod 会下载其自己的 Chromium 二进制文件(约 150MB)。后续运行会重用缓存的二进制文件。无需系统浏览器。
## MCP 工具
### `search`
搜索网页并返回结果,包含网址、标题和摘要。
| 参数 | 类型 | 必需 | 描述 |
| --- | --- | --- | --- |
| `query` | 字符串 | 是 | 搜索查询 |
| `engine` | 字符串 | 否 | `duckduckgo` 或 `tavily`(默认:`SEARCH_ENGINE` 环境变量或 `duckduckgo`) |
### `fetch_content`
抓取网址,将 HTML 转换为可读文本并返回内容。`mode` 参数控制返回的内容量:`"full"` 代表完整内容,`"summary"` 代表较长的预览,`"title"` 代表较短的预览(默认 900 字符预览)。
`cdp` 方法通过 Chrome DevTools Protocol 渲染 JavaScript。使用 `cdp_mode` 参数控制浏览器获取方式:`connect`(默认,需要预先启动 Chrome),`system`(查找系统浏览器),或 `bundled`(自动下载 Chromium)。当 Chrome 不可用时,使用 `direct`(纯 HTTP,剥离 HTML)。
| 参数 | 类型 | 必需 | 描述 |
| --- | --- | --- | --- |
| `url` | 字符串 | 是 | 要抓取的页面网址 |
| `mode` | 字符串 | 否 | 内容长度 — `"full"`(完整),`"summary"`(较长预览),`"title"`(较短预览)。默认:900 字符预览 |
| `method` | 字符串 | 否 | `direct` 或 `cdp`(默认:`FETCH_METHOD` 环境变量或 `direct`)。当 `cdp` 时,使用 `cdp_mode` 选择浏览器来源。 |
| `cdp_mode` | 字符串 | 否 | 当 `method=cdp` 时:`connect`(默认,需要预先启动 Chrome),`system`(查找系统浏览器),或 `bundled`(自动下载 Chromium)。默认为 `CDP_MODE` 环境变量或 `connect`。 |
| `no_cache` | 布尔值 | 否 | 如果 `true`,绕过缓存并强制刷新请求(默认:`false`) |
## MCP 协议示例
服务器在 `POST /mcp` 上使用 JSON-RPC 2.0 进行通信。初始化后获取会话。
### 初始化
请求:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "test",
"version": "1.0"
}
}
}
```
响应(`Mcp-Session-Id` 也在头部):
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "websearch-mcp",
"version": "0.1.0"
}
}
}
```
### `search`
请求:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "tenmasaki",
"engine": "duckduckgo"
}
}
}
```
响应:
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Search results for \"tenmasaki\". Include a Sources section in the final answer.\n- [Tenma Saki](https://example_1.com/)\n- [SEGA copyright](https://example_2.com/)"
}
]
}
}
```
### `fetch_content`
请求(直接):
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "fetch_content",
"arguments": {
"url": "https://example.com",
"mode": "summary",
"method": "direct",
"no_cache": false
}
}
}
```
请求(cdp 搭配 bundled 浏览器):
```json
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "fetch_content",
"arguments": {
"url": "https://example.com",
"mode": "full",
"method": "cdp",
"cdp_mode": "bundled",
"no_cache": true
}
}
}
```
注意:`cdp` 方法渲染 JavaScript。使用 `cdp_mode` 控制浏览器获取方式:`connect`(默认),`system` 或 `bundled`。省略 `cdp_mode` 时,默认为 `CDP_MODE` 环境变量。
响应:
```json
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Title: Example Domain\nURL: https://example.com\n\nThis domain is for use in illustrative examples in documents..."
}
]
}
}
```
连接信息
猜你喜欢
暂无推荐服务器