1. 项目概述:为LLM构建一个本地化的电子元件文档搜索引擎
如果你是一名嵌入式工程师、硬件开发者,或者像我一样,经常需要和德州仪器(TI)、意法半导体(ST)、亚德诺(ADI)这些大厂的PDF文档打交道,那你一定体会过在几百页的Datasheet或技术参考手册(TRM)里大海捞针的痛苦。项目名、芯片型号、引脚定义、电气特性……这些信息散落在不同的PDF里,每次查资料都得手动打开、Ctrl+F、翻页,效率低下不说,还容易遗漏关键信息。
flaco-source/mcp-docs这个项目,就是为了解决这个痛点而生的。它本质上是一个MCP(Model Context Protocol)服务器,专门为大型语言模型(LLM)和AI智能体(比如Cursor、Claude Desktop里的AI助手)提供了一套工具,让它们能够直接、精准地查询官方PDF文档。它的核心思路非常巧妙:不是简单地把PDF扔给AI去“读”,而是先为所有文档建立一个本地的、全文检索的SQLite数据库(使用FTS5扩展和BM25排序算法),AI通过查询这个索引来定位信息,然后再按需读取具体的页面内容。这样一来,AI的回答就能“有据可查”,直接引用官方文档的原文,避免了幻觉和错误。
简单来说,这个项目把那些躺在你硬盘角落或者需要反复去官网下载的PDF,变成了一个可以被AI智能体高效、准确查询的“知识库”。无论你是想快速确认某个芯片的供电电压范围,还是想对比两款MCU的外设资源,都可以直接向你的AI助手提问,它会从经过索引的官方文档中找出最相关的段落告诉你。这不仅仅是节省了时间,更是改变了我们与技术文档交互的方式。
2. 核心架构与设计思路拆解
2.1 为什么选择MCP(Model Context Protocol)?
MCP是Anthropic提出的一套协议,旨在为AI模型提供一个标准化的方式来发现、调用外部工具和访问资源。你可以把它理解为AI世界的“插件系统”或“驱动程序”标准。对于这个项目而言,采用MCP有几个决定性优势:
- 客户端无关性:一旦实现了MCP服务器,任何兼容MCP的客户端(如Cursor、Claude Desktop、未来可能支持的其他IDE或AI平台)都可以无缝接入,无需为每个客户端单独开发适配。
- 协议标准化:MCP定义了清晰的JSON-RPC over stdio/HTTP通信规范、工具(Tools)和资源(Resources)的声明方式。开发者只需关注服务器端的业务逻辑实现,通信层的复杂性被协议抽象掉了。
- 动态能力发现:AI客户端在初始化连接时,会从服务器获取一份完整的工具和资源列表。这意味着我们可以在服务器端灵活地增加新的查询工具或支持新的芯片厂商,客户端无需更新就能自动获得新能力。
这个项目的设计正是基于MCP的“工具”模型。它将不同的文档操作(如搜索、索引、查询)封装成一个个独立的工具函数,暴露给AI调用。这种设计使得AI能够以结构化的、可控的方式与文档系统交互,而不是面对一堆原始的、难以处理的PDF文件。
2.2 本地全文检索索引:FTS5 + BM25 的技术选型
项目最核心的部分,是那个本地的SQLite全文检索索引。为什么不直接用云服务或者现成的搜索引擎库?这里面的考量非常实际:
- 隐私与离线能力:所有芯片文档都可能包含未公开的细节或项目敏感信息。本地化处理确保了数据不出本地,满足了企业对数据安全性的苛刻要求。同时,离线可用性对于网络环境不稳定或需要在隔离环境中工作的开发者至关重要。
- 性能与可控性:SQLite作为一个进程内数据库,读写速度极快,几乎没有网络延迟。FTS5是SQLite的全文检索扩展模块,成熟稳定。BM25是信息检索领域经典的排序算法,能根据词频(TF)和逆文档频率(IDF)等因素,对搜索结果进行相关性排序,比简单的关键词匹配精准得多。
- 轻量级与零依赖:整个索引就是一个
.db文件,易于备份、迁移和版本管理。相比于部署一个Elasticsearch或MeiliSearch实例,SQLite+FTS5的方案在资源消耗和运维复杂度上有着压倒性优势。
具体实现上,项目会在用户目录(如~/.electronics-docs-mcp/)下创建一个docs.db数据库。每当通过read_doc工具索引一个新的PDF时,服务器会:
- 下载PDF文件。
- 使用类似
pdf-parse的库提取每一页的文本内容。 - 将元数据(文档URL、厂商、部件号、标题)和每页的文本内容,插入到FTS5虚拟表中。
- 利用BM25算法,为文档中的词条计算权重,以便后续的
query_doc_content工具能返回按相关性排序的结果。
这个设计使得后续的文档查找,从“在文件系统中搜索文件名”变成了“在高度结构化的文本数据库中执行语义相关性查询”,精度和效率有了质的飞跃。
2.3 供应商(Vendor)抽象层的设计
项目目前支持TI、ST、ADI三家巨头,但它的架构是开放可扩展的。这得益于其清晰的供应商抽象层设计。在src/providers/目录下,有一个基础的VendorProvider抽象类,它定义了每个芯片文档供应商必须实现的接口:
searchDocs(part: string): 根据部件号,去厂商官网搜索相关的PDF文档链接列表(仅元数据,不下载)。readDoc(url: string, ...): 给定一个具体的PDF URL,下载并索引该文档到本地数据库。queryContent(query: string, ...): 在已索引的文档内容中执行BM25全文检索。lookupDoc(part: string, question?: string): 这是一个更高级的“智能查找”接口。它首先在本地索引中查找部件号,如果没找到,则调用searchDocs获取官网建议链接,并过滤掉无关链接(如PCN变更通知)。
TI、ST、ADI的提供商都是这个抽象类的具体实现。它们各自封装了对应官网的HTML结构解析、PDF链接发现逻辑以及网络请求的特殊处理(比如请求头、重试策略)。这种设计模式的好处非常明显:
- 高内聚低耦合:每个厂商的爬取和解析逻辑封装在自己的类里,互不干扰。修改ADI的解析器不会影响TI的功能。
- 易于扩展:要支持一个新的厂商(比如NXP或Microchip),你只需要创建一个新的
XxxProvider.ts文件,实现那几个核心方法,然后在工厂函数中注册即可。这就是项目中提到的“热插拔”能力。 - 统一对外接口:无论底层是TI复杂的Symlink系统还是ADI的产品页面,MCP服务器对外提供的工具(
lookup_doc,read_doc等)的调用方式是完全一致的,用户和AI无需关心背后的厂商差异。
3. 核心工具链详解与使用心法
项目通过MCP暴露了五个核心工具,理解它们各自的分工和协作流程,是高效使用的关键。这就像一套组合拳,用对了顺序,事半功倍。
3.1 工具职责与协作流程
| 工具 | 核心职责 | 输入 | 输出关键信息 | 使用场景与时机 |
|---|---|---|---|---|
lookup_doc | 智能查找与建议。先查本地索引,无结果则返回官网建议链接。 | part(部件号),question(可选问题) | indexedMatches(本地匹配结果),suggestedDocuments(官网建议链接) | 第一步,探路。当你有一个芯片型号但不确定是否有本地索引时。它告诉你“我知道什么”和“你可以去官网找什么”。 |
search_docs | 元数据搜索。仅向厂商官网查询某部件号相关的PDF列表。 | part(部件号),vendor(厂商ID) | 一组包含url,title的文档元数据对象。 | 当你明确需要知道官网提供了哪些关于此部件的文档(Datasheet, TRM, App Note等),且不关心本地索引时。 |
read_doc | 文档索引。下载指定URL的PDF并提取文本存入本地数据库。 | url(PDF直链),part,title(可选) | 成功索引的文档元数据。 | 第二步,建库。获得PDF链接后(通常来自lookup_doc的建议或search_docs的结果),用它来将文档“吸收”进本地知识库。对于TI的Symlink链接尤其必要。 |
query_doc_content | 内容检索。在已索引的所有文档中执行BM25全文搜索。 | query(搜索查询词),vendor(可选) | 一组搜索结果,每条包含docUrl(文档源地址) 和pageNum(命中页码)。 | 第三步,精查。当你有具体的技术问题(如“STM32F407的ADC采样率是多少?”)时,用此工具在所有已索引的文档中查找最相关的页面。 |
read_doc_page | 页面精读。获取指定文档特定页码或页码范围的全部文本内容。 | docUrl(来自query_doc_content),pageNum或pageRange | 指定页面的完整纯文本。 | 最后一步,获取答案。在query_doc_content找到相关页面后,用此工具获取该页的详细文本,作为AI回答的最终依据。 |
一个典型的高效工作流是这样的:
- 探索阶段:你对
TPS61021这个电源芯片的使能引脚电压有疑问。你让AI调用lookup_doc(part=“TPS61021”)。如果该芯片文档已索引,直接返回本地结果;如果未索引,工具会返回TI官网上的Datasheet链接作为suggestedDocuments。 - 建库阶段:你从建议中选取正确的Datasheet链接,调用
read_doc(url=“https://www.ti.com/lit/ds/symlink/tps61021.pdf”)将其索引到本地。 - 查询阶段:现在你可以提出具体问题:“TPS61021的EN引脚逻辑高电平最低电压是多少?”。AI调用
query_doc_content(query=“EN pin logic high threshold voltage”),BM25算法会在所有已索引页中搜索,返回最相关的文档URL和页码(比如tps61021.pdf的第8页)。 - 获取阶段:AI最后调用
read_doc_page(docUrl=“…tps61021.pdf”, pageNum=8),拿到该页的完整文本,从中提取出“Vih = 1.2V”这个准确信息来回答你。
实操心得:很多新手会跳过
lookup_doc直接去search_docs或read_doc,这往往效率不高。lookup_doc的设计精髓在于“本地优先”,它能避免不必要的网络请求。只有当本地确实没有时,它才告诉你“可以去这里找”。对于TI的文档,很多链接是Symlink(动态生成),read_doc是唯一能正确处理它们并建立索引的工具。
3.2 配置详解:本地Stdio vs. 远程HTTP
项目支持两种运行模式,对应不同的使用场景,配置上有些“坑”需要特别注意。
本地Stdio模式(用于Cursor/Claude Desktop)这是最常用、延迟最低的模式。AI客户端(如Cursor)直接在你的电脑上启动这个Node.js进程,通过标准输入输出(stdio)进行通信。配置的核心是告诉客户端启动这个服务器的命令。
Node直接运行:最简单。确保项目已经
npm run build编译好,然后在Cursor的MCP设置文件(~/.cursor/mcp.json)中配置绝对路径。{ "mcpServers": { "electronics-docs": { "command": "node", "args": ["/绝对/路径/到/mcp-docs/build/index.js"] } } }注意:路径必须是绝对路径。Windows用户注意盘符和反斜杠(建议使用正斜杠
/或双反斜杠\\)。修改配置后,必须重启Cursor或重载窗口才能生效。Docker运行:适合希望环境隔离的用户。需要先构建镜像
docker build -t electronics-docs-mcp .。配置时,关键参数是-i(保持stdin开放)和-v(持久化索引数据卷)。{ "mcpServers": { "electronics-docs": { "command": "docker", "args": [ "run", "-i", "--rm", "-v", "electronics-docs-mcp-data:/root/.electronics-docs-mcp", "electronics-docs-mcp" ] } } }这里的
-v将名为electronics-docs-mcp-data的Docker卷挂载到容器内的索引目录。如果你想清空索引重新开始,可以执行docker volume rm electronics-docs-mcp-data。
远程HTTP模式(用于团队共享或远程访问)这种模式下,服务器作为一个HTTP服务运行,允许多个客户端通过网络连接。这对于在团队内部署一个共享的文档索引服务器非常有用。
启动服务器:
npm run build npm run start:http # 开发模式,监听3000端口 # 或 npm run start:http:prod # 生产模式你可以通过环境变量
PORT和HOST改变监听设置,强烈建议设置MCP_AUTH_TOKEN环境变量来启用鉴权。配置Cursor连接远程服务器:这是最容易出错的地方。关键在于
mcp.json的配置。{ "mcpServers": { "electronics-docs-remote": { "type": "streamableHttp", // 必须明确指定类型! "url": "http://你的服务器IP:3000/mcp", // URL必须以/mcp结尾! "headers": { "Authorization": "Bearer YOUR_SECRET_TOKEN" // 如果服务器启用了鉴权 } } } }type: “streamableHttp”:这个字段必须存在且正确,它告诉Cursor使用HTTP传输协议。如果缺失,Cursor会默认使用错误的端点。url必须以/mcp结尾:服务器的MCP端点是在/mcp路径下。如果只写http://host:3000,请求会发到根路径/,导致404或Cannot POST /错误。headers:只有当你在启动服务器时设置了MCP_AUTH_TOKEN环境变量时才需要。格式必须是Bearer后面加一个空格,然后是令牌。
踩坑记录:我曾经在配置远程服务器时,因为漏写了
“type”: “streamableHttp”,Cursor一直连接失败,报错信息又不明显,排查了很久。另一个常见的坑是使用ngrok或Cloudflare Tunnel生成的临时域名,每次重启都会变,记得及时更新mcp.json中的url。
4. 部署方案选型与实战指南
根据你的使用场景和资源,项目提供了从轻量到高可用的多种部署方式。我将结合自己的经验,分析每种方案的适用场景和注意事项。
4.1 方案A:本地开发(Stdio模式)
这是绝大多数个人开发者的起点。直接在本地电脑上运行,数据完全私有,响应速度最快。
- 适用场景:个人学习、项目开发、离线环境。
- 优点:零延迟,配置简单,数据安全。
- 缺点:索引仅限本机,换设备工作无法同步。
- 实战步骤:
git clone项目源码。npm install安装依赖。npm run build编译TypeScript。- 按上述“本地Stdio模式”配置Cursor。
- 在Cursor中,尝试让AI助手调用
list_tools,确认连接成功。
4.2 方案B:内网HTTP服务器(Docker Compose)
如果你在一个小团队内,希望共享一个统一的文档索引,避免每个人重复下载和索引,这是性价比最高的方案。
- 适用场景:小型团队、实验室环境。
- 优点:索引共享,节省带宽和存储;一次索引,全员受益;利用内网高速。
- 缺点:需要一台长期开机的内网服务器(如NAS、旧电脑、树莓派)。
- 实战步骤:
- 在内网服务器上克隆项目。
- 创建
docker-compose.yml文件,内容参考项目文档,务必设置MCP_AUTH_TOKEN和持久化数据卷。 - 运行
docker compose up -d启动服务。 - 团队成员的Cursor配置中,
url指向这台服务器的内网IP和端口(如http://192.168.1.100:3000/mcp)。 - 关键技巧:可以在服务器上写一个简单的脚本,定期(如每周)用
search_docs和read_doc自动索引团队常用芯片的新版本文档,保持索引新鲜度。
4.3 方案C:云服务器部署(VPS)
适合分布式团队或需要从任何地方访问的场景。
- 适用场景:远程团队、个人云服务。
- 优点:随时随地访问;可利用云服务器的高带宽快速索引大量文档。
- 缺点:有云服务成本;需要关注网络安全(务必设置强
MCP_AUTH_TOKEN)。 - 实战步骤:以Ubuntu VPS为例:
- 通过SSH登录服务器,安装Node.js, npm, Docker。
- 克隆项目,构建Docker镜像。
- 使用Docker运行,并映射端口。强烈建议使用Nginx/Caddy作为反向代理,配置SSL证书(HTTPS),并在其后面设置一层HTTP Basic Auth或IP白名单,增加安全性。
- 在云服务商的安全组中,只开放必要的端口(如443)。
- 客户端配置中的
url使用https://你的域名/mcp。
4.4 方案D:Serverless函数部署(Vercel)
这是一个非常新颖且成本极低的方案,利用Vercel等Serverless平台的无服务器函数。
- 适用场景:轻量级、间歇性使用;尝鲜和演示。
- 优点:几乎零运维,按调用次数付费,自动扩展,自带HTTPS。
- 缺点:有严重限制。Serverless函数有执行时长限制(Vercel Hobby版10秒),PDF索引过程可能超时。此外,Serverless环境是无状态的,本地文件系统(如
/tmp)是临时的,SQLite数据库在函数冷启动后会丢失,索引无法持久化。 - 实战心法:
- 不要用它来建立大型或持久的索引。它更适合作为一个“只读”的查询端点,前提是你能通过其他方式(比如在CI/CD流程中)预先构建好索引数据库,并每次部署时将其作为构建产物打包进函数。
- 项目提供的Vercel配置更多是一个示例,证明了MCP over HTTP的可行性。对于生产环境,除非你能解决索引持久化和超时问题,否则不推荐。
个人建议:对于个人和大多数小团队,方案A(本地)和方案B(内网Docker)是最务实的选择。方案C提供了灵活性但增加了复杂度和成本。方案D很有趣,但当前更适合作为技术验证,而非生产主力。我自己的主力环境是本地Stdio模式,同时在办公室的迷你服务器上跑了一个Docker Compose服务供小组其他成员使用。
5. 高级技巧与故障排查实录
即使按照文档操作,在实际使用中也可能遇到各种问题。这里分享一些我踩过的坑和总结的技巧。
5.1 索引管理与优化
- 索引文件位置:本地索引默认位于
~/.electronics-docs-mcp/docs.db。你可以通过ELECTRONICS_DOCS_DB_DIR环境变量修改这个路径。定期备份这个文件是明智的。 - 重建索引:如果索引损坏或想彻底清空,直接删除
docs.db文件即可。下次启动服务器时会自动创建新库。 - 索引了什么?索引的是PDF的文本内容,不是文件本身。所以
docs.db文件的大小远小于原始PDF集合的大小,查询速度也很快。 - 内存与性能:对于数万页的文档库,SQLite索引依然能保持毫秒级响应。如果感觉查询变慢,可以尝试在SQLite中运行
ANALYZE;命令更新统计信息,或使用PRAGMA optimize;。
5.2 网络问题与供应商适配
不同厂商的网站反爬策略不同,可能导致read_doc失败。
- TI(德州仪器):其PDF链接多为
lit/ds/symlink/...格式的Symlink。项目中的TexasInstrumentsProvider已经做了适配。如果下载失败,检查网络是否能直接访问ti.com。有时需要添加特定的Referer或User-Agent请求头,这些逻辑已在Provider中实现。 - ST(意法半导体):网站结构相对稳定。
StMicroelectronicsProvider会从产品页面解析出Datasheet等链接。如果搜索不到,可能是部件号格式不匹配,尝试使用更通用的型号(如STM32F407而不是STM32F407VGT6)。 - ADI(亚德诺):这是v2.7.x新增的支持。
AnalogDevicesProvider会从analog.com/en/products/<slug>.html页面发现PDF。如果遇到404,Provider有回退机制尝试其他可能的slug格式。下载PDF时设置了较长的超时和Accept-Language头,以提高成功率。 - 通用网络问题:工具内部实现了对网络错误(502/503/504、超时)的重试机制。如果持续失败,请检查:
- 本地网络连接和代理设置。
- 目标厂商网站是否可正常访问。
- 是否触发了厂商网站的速率限制(可以尝试在请求间增加延迟)。
5.3 Cursor/Claude Desktop 连接失败排查
这是最常见的问题,通常出在配置环节。
- 检查服务器是否在运行:对于Stdio模式,在终端手动运行
node build/index.js,看是否有错误输出。对于HTTP模式,用浏览器或curl访问http://localhost:3000/health,应返回{“status”:“ok”}。 - 检查配置文件路径和格式:确保
mcp.json文件放在正确的用户目录下(Windows:%USERPROFILE%\.cursor\;Mac/Linux:~/.cursor/)。JSON格式必须正确,不能有注释(除非客户端支持)。 - 检查命令和路径(Stdio模式):
command和args必须能直接在终端中执行。对于Node,确保Node已在PATH中。对于Docker,确保Docker守护进程正在运行。 - 检查URL和类型(HTTP模式):确认
url末尾有/mcp。确认type字段是“streamableHttp”(大小写敏感)。如果服务器启用了鉴权,确认headers中的Authorization值正确,且令牌与服务器启动时设置的MCP_AUTH_TOKEN完全一致。 - 查看客户端日志:Cursor和Claude Desktop通常有输出日志的地方。在Cursor中,你可以打开“View” -> “Output”,选择“MCP”相关的输出通道,查看连接和通信的详细日志,里面往往有具体的错误信息。
- 重启客户端:任何配置更改后,必须完全重启Cursor或Claude Desktop,或者至少执行重载窗口的操作,新的MCP配置才会被加载。
5.4 扩展新供应商的实战经验
项目架构支持“热插拔”新厂商,这是一个非常强大的功能。以添加NXP为例,我分享一下大致步骤和注意事项:
- 创建Provider文件:在
src/providers/下创建NxpProvider.ts。首先研究NXP官网(www.nxp.com)的文档查找模式。通常是通过搜索API或解析产品页面。 - 实现核心方法:
searchDocs(part): 模拟浏览器搜索,从NXP官网获取该部件所有相关PDF的链接和标题。可能需要处理分页、AJAX请求。readDoc(url): 实现PDF下载和文本提取。注意NXP PDF的URL模式、可能的认证或会话要求。queryContent和getDocumentPageText通常可以继承基类的默认实现,除非NXP的PDF解析有特殊需求。lookupDoc也可以继承基类,它已经实现了“先本地后网络”的智能逻辑。
- 注册Provider:在
src/mcpServerFactory.ts文件中,找到vendors映射对象,添加一行,例如‘NXP’: new NxpProvider(config)。这一步是关键,注册后,工具的描述和供应商列表会自动更新。 - 测试:编写针对新Provider的单元测试。然后使用
npm run build编译,重启MCP服务器。在Cursor中让AI调用list_tools,确认NXP已经出现在支持的供应商列表中,然后尝试search_docs一个NXP的部件号进行测试。 - 处理反爬:厂商网站经常改版。一个健壮的Provider应该包含错误处理、请求重试、User-Agent轮换,以及从HTML中解析链接的容错逻辑。可以考虑使用
cheerio这样的库来稳健地解析HTML。
这个项目真正解放了开发者与海量数据手册之间的隔阂。它不是一个简单的文件搜索工具,而是一个为AI时代量身定做的、精准的硬件知识查询接口。从最初的本地索引构建,到多供应商支持,再到灵活的部署方式,每一个设计决策都透露着实用主义的考量。我最欣赏的是它对“本地优先”和“隐私安全”的坚持,以及通过MCP协议实现的优雅集成。无论你是独立开发者,还是团队的技术负责人,花点时间部署和熟悉这套工具,都能在未来与硬件文档的斗争中,为你赢得大量的时间和准确性。