- 人工智能
- MCP 服务
【免费下载链接】web-search-mcp
A simple, locally hosted Web Search MCP server for use with Local LLMs
web-search-mcp 是一个运行在本地的网页搜索 MCP 服务器,基于 TypeScript 与 MCP SDK 构建,无需任何 API 密钥,即可为本地 LLM 提供 Bing、Brave、DuckDuckGo 三引擎搜索和网页正文抓取能力。如果你想给本地 AI 助手接入真实的互联网知识,又不依赖第三方付费接口,这份代码就是非常值得精读的样本。本文带你逐层读懂它的模块分工、多引擎降级策略与浏览器自动化设计 🧭。
🧩 项目速览:本地网页搜索 MCP 服务器能做什么
MCP(Model Context Protocol)是连接大模型与外部工具的通信协议,LM Studio、LibreChat 等本地推理客户端都支持通过它挂载扩展工具。web-search-mcp 就是这个协议下的一个搜索服务器,对外暴露 3 个专用工具:
| MCP 工具 | 用途 | 特点 |
|---|---|---|
full-web-search | 搜索 + 抓取完整正文 | 主力工具,多引擎 + 并发提取 |
get-web-search-summaries | 仅返回结果摘要片段 | 轻量快速,适合快速调研 |
get-single-web-page-content | 提取单个 URL 的正文 | 无需搜索,直达内容 |
它的核心卖点在于"直连":不走 Google Search API 等付费渠道,而是用 Playwright 无头浏览器模拟真人访问搜索引擎,再用 axios 或浏览器抓取结果页正文——整套流程完全在本地完成。
🚀 快速上手:3 步搭建本地搜索服务器
环境要求:Node.js 18+、npm 8+。
# 1. 克隆仓库 git clone https://gitcode.com/gh_mirrors/we/web-search-mcp cd web-search-mcp # 2. 安装依赖并下载 Playwright 浏览器内核 npm install npx playwright install # 3. 编译 TypeScript 源码 npm run build编译完成后,在客户端的mcp.json中指向产物dist/index.js即可:
{ "mcpServers": { "web-search": { "command": "node", "args": ["/path/to/web-search-mcp/dist/index.js"] } } }完整参数说明可查阅项目文档 docs/API.md。
🗂️ 源码架构总览:核心模块分工一览
整个src/目录只有 7 个源文件,结构非常清晰,按职责可以分成四层:
| 文件 | 职责 | 所属层 |
|---|---|---|
| src/index.ts | 服务器入口:注册工具、参数校验、优雅退出 | MCP 协议层 |
| src/search-engine.ts | 多引擎搜索调度、HTML 解析、质量评分 | 搜索层 |
| src/browser-pool.ts | Playwright 浏览器实例池与健康检查 | 资源层 |
| src/enhanced-content-extractor.ts | 网页正文提取(axios + 浏览器双路) | 提取层 |
| src/content-extractor.ts | 纯 axios 的简化版提取器 | 提取层 |
| src/rate-limiter.ts | 每分钟请求数限流 | 防护层 |
| src/types.ts、src/utils.ts | 类型定义与文本清洗等工具函数 | 基础设施 |
依赖方面(见 package.json):@modelcontextprotocol/sdk提供协议能力,playwright负责浏览器自动化,axios做高速 HTTP 请求,cheerio解析 HTML,zod校验参数,p-limit控制并发——每个库都对应一个明确的架构职责,没有冗余依赖。
🔍 入口文件解读:MCP 服务器如何注册 3 个搜索工具
入口文件 src/index.ts 中的WebSearchMCPServer类是整个服务器的骨架,构造函数里做了两件关键事:
this.server = new McpServer({ name: 'web-search-mcp', version: '0.3.1' }); this.searchEngine = new SearchEngine(); this.contentExtractor = new EnhancedContentExtractor();随后setupTools()(L30)依次注册 3 个工具。值得注意的设计细节:
- zod 参数校验:每个工具的参数都用 zod 声明,并容忍字符串形式的数字和布尔值(L37-L49)。因为不同本地模型传参类型不一致,这种宽容式校验是"兼容各种模型"的关键。
- 模型自适应:代码会根据参数类型"猜"模型——发现 Llama 常发字符串参数,就自动把正文长度限制到 2000 字符,防止大响应把它"撑爆"(L66-L91)。
- 通信方式:
run()使用StdioServerTransport(L513-L522),即通过标准输入/输出与客户端交换 JSON-RPC 消息,这也是 MCP 服务器的标准做法。 - 优雅退出:监听
SIGINT/SIGTERM信号,退出前统一关闭所有浏览器实例,避免内存泄漏(L472-L511)。
⚡ 多引擎搜索策略:Bing、Brave、DuckDuckGo 的降级原理
src/search-engine.ts 是最核心的模块。search()方法把三种搜索途径排成数组,按可靠性从高到低依次尝试(L36-L40):
- Browser Bing(主引擎):用 Playwright 启动 Chromium,模拟真人"打开主页 → 填写搜索框 → 点击搜索"的完整流程,而不是直接拼 URL,以降低被反爬识别的概率;
- Browser Brave(备引擎):用 Firefox 访问 Brave 搜索,同样带重试机制(L120-L160);
- Axios DuckDuckGo(兜底):直接用 HTTP 请求 HTML 版 DuckDuckGo,速度最快。
每个引擎的 HTML 都由 cheerio 解析,且为标题、摘要各准备了一组备选 CSS 选择器——搜索引擎改版时,只要其中一组选择器还能命中,解析就不会挂掉。
更有意思的是质量评分机制(assessResultQuality):它提取查询词,统计每条结果的标题/描述/URL 中的关键词命中率和短语匹配加分,再对"菜谱、天气、购物"等明显跑题的内容做扣分。评分 ≥ 0.8 直接采用,低于阈值则继续降级到下一个引擎。这套逻辑让服务器不会"搜到就跑",而是追求真正相关的结果。
🌐 浏览器池设计:Playwright 实例管理与健康检查
无头浏览器很吃内存,src/browser-pool.ts 的BrowserPool类因此承担了"资源管家"的角色:
- 按类型复用:用
Map缓存 chromium / firefox / webkit 实例,超过MAX_BROWSERS(默认 3)时自动淘汰最旧的(L96-L106); - 健康检查:每次取用前会新建一个测试 context 再关闭,验证浏览器是否还活着,不健康就销毁重建(L29-L53);
- 启动参数隐身:带上
--disable-blink-features=AutomationControlled等参数,去掉自动化特征。
📄 内容提取:从 axios 到无头浏览器的双路策略
src/enhanced-content-extractor.ts 是"先快后稳"的典型实现:
- 首选 axios(extractWithAxios):毫秒级拿到 HTML;
- 失败且判定浏览器能救场时(如被反爬拦截、JS 渲染页面),自动切换到 Playwright 浏览器提取(L33-L61);
- 浏览器模式注入隐身脚本:覆写
navigator.webdriver、伪装 plugins/languages 等指纹(L120-L150),并拦截图片、字体等无关资源以提速; - 正文清洗:用 cheerio 批量移除
nav、footer、广告、弹窗等噪声节点,再用article/main等优先级选择器锁定正文(parseContent)。
批量抓取时,extractContentForResults 用Promise.all并发提取多个页面,并给每页套上Promise.race超时保护(8 秒),单个页面卡死不会拖垮整次搜索;失败结果也会返回并标注错误原因,供上层汇总。
🛡️ 限流器与工具函数:稳定运行的细节
- 限流:src/rate-limiter.ts 用
p-limit限制并发(5 路),并以"每分钟最多 10 次请求"为窗口计数,超限直接抛错让调用方稍候——避免高频请求把搜索引擎的访问封掉; - 工具函数:src/utils.ts 提供文本清洗(
cleanText)、词数统计、随机 User-Agent、isPdfUrl等小函数。主流程会先多要一倍搜索结果、跳过 PDF 链接,保证最终交付的条数足够(index.ts L373)。
⚙️ 环境变量速查表:自定义你的搜索行为
服务器行为可通过环境变量调节(在mcp.json的env字段中设置):
| 变量 | 默认值 | 作用 |
|---|---|---|
MAX_CONTENT_LENGTH | 500000 | 单页最大正文字符数 |
DEFAULT_TIMEOUT | 6000 | 单次请求超时(毫秒) |
MAX_BROWSERS | 3 | 浏览器实例上限 |
BROWSER_TYPES | chromium,firefox | 启用的浏览器内核 |
RELEVANCE_THRESHOLD | 0.3 | 结果相关性评分阈值 |
FORCE_MULTI_ENGINE_SEARCH | false | 强制尝试全部引擎取最优 |
💡 内存紧张时把MAX_BROWSERS调成 1;追求更快响应可把DEFAULT_TIMEOUT设为 4000。
📦 构建与测试:TypeScript 编译与 esbuild 打包
日常开发用几条 npm 脚本就够了(package.json):
npm run dev # tsx 热重载模式运行 npm run build # tsc 编译到 dist/ npm run lint # ESLint 检查此外 scripts/bundle.js 用 esbuild 把所有模块打包为单文件dist/bundle.js,方便分发给不想装node_modules的用户。tests/目录提供了 test-bing.js、test-brave.js、test-duckduckgo.js 等针对各引擎的独立测试脚本,npm run build后可直接运行验证某个引擎是否可用。
💡 总结:这套架构值得借鉴的 3 点
- 分层清晰:协议层(index.ts)、搜索层(search-engine)、资源层(browser-pool)、提取层(extractor)各司其职,新人 10 分钟就能看懂数据流;
- 处处降级:引擎降级、请求降级(axios → 浏览器)、选择器多选一,任何单点故障都有后路;
- 面向真实模型调优:参数宽容校验、按模型自适应截断、质量评分,都是为本地 LLM 的不稳定性做的针对性设计。
如果你正在用 LM Studio 或 LibreChat 搭建本地 AI 工作流,web-search-mcp 是一个零密钥成本就能让模型"上网查证"的实用方案,而其源码结构也是学习 MCP SDK 开发的一手教程。
- 人工智能
- MCP 服务
【免费下载链接】web-search-mcp
A simple, locally hosted Web Search MCP server for use with Local LLMs
相关推荐
MCP stdio 服务器实战:基于 TypeScript 与 MCP SDK 构建本地工具服务器
MCP stdio 服务器实战:基于 TypeScript 与 MCP SDK 构建本地工具服务器 本指南以 mcp for beginners 课程中 05
教程文档人工智能mcp-for-beginners 实战:用 FastMCP 与 SerpAPI 构建 Web Search MCP 服务器
mcp for beginners 实战:用 FastMCP 与 SerpAPI 构建 Web Search MCP 服务器 本教程基于 mcp for beg
教程文档人工智能better-icons源码解析:用TypeScript构建MCP服务器的完整架构
better icons源码解析:用TypeScript构建MCP服务器的完整架构 better icons 是一个用 TypeScript 构建的图标搜索工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考