[控场AI]
· 6 分钟阅读· 3,218 字

一天将图书推荐器变成AI应用:MCP开发踩坑实录

一天将图书推荐器变成AI应用:MCP开发踩坑实录

开发者一天内将 BookDNA 改造为 MCP 服务器,两个离奇 bug 揭示真实部署环境的隐藏陷阱。

一位开发者将自己原有的图书推荐工具 BookDNA 改造为 MCP 服务器,用 mcp-use 框架部署在 Manufact Cloud 上,让任何支持 MCP 的 AI 聊天工具都能调用,支持搜索、DNA 提取与推荐四个工具接口。在一天的开发中,两个 bug 提供了关键教训:其一,Open Library 旧封面重定向到 archive.org,但 MCP 组件的安全策略只放行了 Open Library,导致封面被静默拦截,修复需允许整条重定向链;其二,平台代理重写用户标识请求头,使所有用户共享同一个限流额度,只有对真实部署环境测试才能发现。作者以 Claude Code 为主要构建工具,坚持人类决策与验证,最终开源项目并总结出核心教训:本地与线上基础设施差异是 MCP 应用开发的最大隐患。

一位开发者为了满足自己对“fae court 背景下的 enemies to lovers”这类奇幻浪漫小说的个性化需求,用一天时间将原本的图书推荐工具 BookDNA 改造为一个AI应用,并部署为MCP服务器。在这个过程中,两个看似离奇的bug给他上了宝贵的一课。

从图书推荐到MCP应用:BookDNA的诞生

BookDNA 的核心思路是提取图书的“DNA”——包括其中的套路(tropes)、背景设定和基调,然后根据这些特征推荐匹配的书籍。最关键的是,每一条推荐都会通过 Open Library 进行真实性校验,确保不会推荐不存在的书。

这次改造使用 mcp-use 框架,并将服务部署在 Manufact Cloud 上,使其成为一个 MCP(Model Context Protocol)服务器。任何支持 MCP 的 AI 聊天工具都能调用它。作者提供了四个工具接口:search_book、get_book_dna、recommend 和 recommend_by_tropes。推荐工具会直接在聊天界面中返回一个小型应用——一个羊皮纸风格的书架,每本书的封面下方附有一句话推荐理由。

最让作者兴奋的是,在 Manufact 的 Inspector 聊天中使用 GPT 模型(而非 Claude)测试时,一切完美运行。同一个服务器,适配任何AI——这正是 MCP 协议所承诺的愿景,亲眼见证它实现令人满足。

BookDNA MCP应用界面

MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 于 2024 年底提出并开源的通信标准,旨在让 AI 应用以统一方式连接外部工具与数据源。在 MCP 出现之前,开发者若想让不同 AI 助手(如 Claude、GPT、各类 IDE 插件)调用同一个工具,往往需要为每家平台分别适配接口。MCP 通过定义标准化的服务器端协议——包括工具(tools)、资源(resources)和提示(prompts)三类原语——将能力提供方与调用方解耦。任何实现了 MCP 客户端的 AI 聊天工具,都能发现并调用符合协议的服务器,无需改代码。文中 BookDNA 正是把图书推荐能力封装成 MCP 服务器,因此才能在 Claude 之外的 GPT 模型中即插即用。

mcp-use 则是一个基于 Python 的 MCP 开发框架,简化了工具的声明、参数校验与服务器部署流程。它提供的 Inspector 聊天界面可以实时调试 MCP 工具调用,是开发阶段验证行为的重要工具。

Bug 1:只有一张封面正常显示

第一次测试时,书架上只有一张封面正常加载,其余四张全部显示为破损图片。但检查数据后发现,每一本书的封面链接都是有效的,问题并不在数据层面。

经过排查,原因浮出水面:旧版 Open Library 封面会重定向到 archive.org 上的另一台服务器。而 MCP App 组件运行在严格的安全策略下,只允许从白名单中的站点加载图片,作者只放行了 Open Library,导致重定向后的图片被静默拦截。唯一成功加载的那张封面恰好是较新的、没有重定向的链接。

修复方法是将 archive.org 也加入允许列表。同时作者还添加了降级方案:如果封面加载失败,卡片会显示一张羊皮纸风格的“标题页”,上面写着书名和作者,而不是一块破损图片。

启示:如果你的组件需要加载图片,务必允许重定向链中的每一个站点,而不仅仅是第一个。

MCP App 组件通常运行在沙箱化的 iframe 或受控 WebView 中,会强制执行内容安全策略(CSP)。CSP 的 img-src 指令通过白名单限制可加载图片的来源域名,未列入的域名会被浏览器静默拦截——请求根本不会发出,开发者只能在控制台看到拦截日志,前端则表现为破损图片。这里更隐蔽的一点是重定向链:浏览器对图片加载的重定向校验,会检查最终落地页的域名是否也在白名单中,中间跳转的域名同样需要放行。Open Library 的旧封面链接往往会 302 到 archive.org,所以只白名单 openlibrary.org 是不够的。实践中,允许列表应覆盖整条重定向链,或改用代理转发图片以收敛域名。文中提到的“羊皮纸降级卡片”是更稳妥的策略:即使加载失败,用户仍能看到书名与作者,避免出现破损图标破坏体验。

Bug 2:所有用户共享同一个限流额度

由于服务器是公开的,作者添加了限流机制来保护自己的AI调用预算,其中包括按用户区分的限流。但在对线上部署进行测试时,出现了意料之外的情况:平台的代理会重写标识用户的请求头,而代码中读取到的地址实际上是代理的地址,而非真实用户的地址。结果就是所有用户共用同一个限流额度。

改动很小,但问题的发现完全依赖于对真实部署环境的测试,而不是信任本地开发环境。

启示:任何依赖请求头的功能,都必须对真实部署环境进行测试。

在反向代理或云平台(如 Manufact Cloud、Vercel 等)后面运行的服务器,看到的直接连接方通常是代理本身,而非终端用户。为此 HTTP 协议约定了一系列转发头:X-Forwarded-For 记录原始客户端 IP,X-Forwarded-Proto 记录原始协议,X-Real-IP 则常用于保存单值客户端地址。不同平台对这些头的处理策略不同:有的会追加、有的会重写、有的会剥离。若代码直接读取 request.client.host 或错误的转发头字段,就会把所有用户识别成同一个来源,导致按用户限流、风控、灰度等功能全部失效。稳妥做法是优先使用平台官方提供的身份标识(如认证后的用户 ID),或在文档中确认代理会保留哪个头,并在真实部署环境中用多个出口 IP 验证识别结果是否正确。

开发方式与工具链

整个项目使用 Claude Code 构建。作者强调自己负责所有决策、审查每一处改动并亲自测试,同时维护了一份“摩擦日志”,记录开发过程中所有令人困惑的地方。

这种开发模式体现了当前AI辅助编程的一个务实方向:AI负责加速实现,人类负责判断和验证。

“摩擦日志”(friction log)是产品与工程团队常用的一种实践:开发者以第一视角记录使用自家工具时每一处令人困惑、卡顿或反直觉的环节,作为改进依据。它源自内部“吃自己的狗粮”(dogfooding)文化,Google、Stripe 等公司都有类似机制。在 AI 辅助编程时代,摩擦日志的价值被进一步放大:AI 可以快速生成大量代码,但人类开发者走过的每一步真实体验——包括哪些提示词反复失败、哪些改动需要多次回退——才是判断工具链是否可用的关键数据。作者维护摩擦日志,本质上是在为“AI 加速实现、人类负责判断”这一分工建立反馈闭环,让模糊的不适感变成可追踪、可修复的具体条目。

如何体验

项目已在 GitHub 开源:github.com/ksaivarsha/bookdna,MCP 服务器地址为 https://calm-wave-h30fs.run.mcp-use.com/mcp。如果你也在构建 MCP 应用,作者很想听听你遇到了哪些坑。

这两个bug揭示了一个共同的教训:在 MCP 和 AI 应用开发中,本地环境与真实部署之间的差异往往就是问题所在。安全策略、代理行为、请求头改写——这些基础设施层面的细节,只有在对线上环境进行完整测试时才会暴露。对于正在进入 MCP 生态的开发者来说,这是一份高价值的实战参考。

#MCP#AI应用开发#BookDNA#图书推荐#mcp-use#Open Library#AI编程#限流
分享:

相关推荐