把网站装进 ChatGPT:Indeed 的 MCP Apps 实战三条铁律
关联
公司 Indeed
概念 MCP Apps · MCP · CareerScout · Claude · ChatGPT · 结构化内容 · update model context
把自家网站塞进 ChatGPT 或 Claude 的聊天窗口里,听起来像拖拽一下就完事——Indeed(全球排名第一的求职网站)做 AI 平台的 Dustin Mahalik 告诉你:不是。他和团队在为 Claude、ChatGPT 和自家求职智能体 CareerScout 构建 MCP Apps(让第三方应用以 UI 组件形式嵌入聊天界面的规范)时踩过一堆坑,总结出几条铁律 。
第一个坑:聊天窗口容不下「品牌」
最基本的文本版 MCP 调用效果其实不错——搜「Austin 的咖啡师」,Claude 能给出像样的职位列表。但问题很明显:没有 Indeed 的品牌、没有申请按钮、没有详情页,Claude 只是说「这些是 Austin 的一些工作」。
更反直觉的是:要让 Claude 或 ChatGPT 输出链接非常难,因为它们不想让用户离开自己的环境。这说得通,但结果是「这是互联网上某处的五份工作,没有链接」——糟糕的用户体验。
他们花了「荒谬的小时数」跑 evals(评估测试)才让 Claude 稳定地带链接。有了 MCP Apps 和 apps SDK,这些就能自己控制了:申请按钮、置顶要突出的内容、点「查看详情」弹出职位信息的弹窗,用户不用离开聊天环境,对双方都是双赢 。
铁律一:给用户看的,也要给模型看
最朴素的接法是:继续调用现有 API 加载数据,把界面塞进聊天框。这会让 UI 变成模型的黑盒——模型调用了一个工具,工具展示了些东西,但模型完全不知道展示的是什么。用户追问「讲讲第一个结果」或「给这些公司排名」时,模型一脸懵 。
所以第一条规则:任何展示给用户的内容,也必须作为数据提供给模型。他见过不少 MCP Apps 只是往页面注入 HTML 再调 API,结果就是给模型造了个大黑盒。具体做法靠 MCP 规范里的结构化内容(structured content,做纯文本 MCP 时本来就会返回的那部分)加资源 URI(指向 HTML 所在位置),两者都要返回、且必须保持同步——API 加了新字段,给模型的数据也要跟着加 。
铁律二:用户的每次交互,也要告诉模型
做到第一条还不够。模型拿到了数据,但仍会像平时那样用文字把内容复述一遍,和你的 UI 重复。
解法是更新工具描述,开头写一句「结果已作为 UI 组件自动展示给用户」——就这么简单一句,就能覆盖相当多的情况,让模型只给个简短摘要,而不是整套文字版展示。当然,UI 里显示什么、模型显示什么之间总有点拉锯,只能靠描述去引导 。
紧接着的坑是可交互部件:用户点了「查看详情」弹出大段职位描述,或者从返回的 10 个职位里点了某一个——模型照样不知道你在看什么,「给这个职位写封求职信」这种请求就无从下手 。
解法是 MCP Apps 规范里的 update model context 方法:把用户交互信息以字符串形式传给模型。它只支持单个字符串,要追踪多个事件就得往里追加。官方文档的购物车例子就是这么做:把总价和所有商品写进去,用户才能问「我购物车里有什么」。
铁律三(优先级最高):数据处理与 UI 渲染分离
做到前两条,模型「看得见」了,但还有个致命问题。他举了个硬核搜索的例子:找某职位、愿搬去多个城市、只看薪资最高的、排除某些行业——这类任务文本版 MCP 表现极好,Claude 会做十几次搜索、过滤、汇总成一张漂亮的表格。但一旦声明「结果会显示在 UI 里」,Claude 就只调用一次工具,心想「结果已经展示了」,不再深挖——用户不想要 10 个轮播组件,Claude 也注意到已经展示过,就不肯再调了 。
所以规则三,优先于其他所有规则:把数据处理和 UI 渲染分开(这个措辞他直接从 OpenAI Apps SDK 文档里「偷」来的)。具体做法:职位搜索做成纯文本 MCP,Claude 想调多少次调多少次;另做一个渲染工具(render jobs widget),接受一列职位 ID。
Claude 可以搜出 100 个职位、过滤到 5 个,再只把这 5 个交给渲染。工具描述里写明「必须始终先调用搜索工具之一拿到数据再渲染」即可 。
这套「探索数据 → 选择渲染」的拆分思路几乎能套进任何行业:电商的应用场景、地图(先找出五个地址再传入渲染)等等 。
渲染工具还能让模型发挥创造力
文本版交互里模型常会说「我选这个是因为……
」,这可以搬进 UI:给渲染工具加个参数,让模型传入 ID 外加一个「为什么这是好匹配」的理由,或者让它高亮职位描述里最值得看的一段。渲染工具设计得越有想象力,模型能注入的个性就越多,用户体验就越好 。
总原则:数据先行,UI 是副作用
关键要点听起来和直觉相反:构建 MCP Apps 时,先想数据、再想 UI。不是「我怎么把 UI 塞进 ChatGPT」,而是「我想给模型什么数据、想让它能对这些数据做什么」——渲染只是模型探索数据的副产品 。
工具设计上走「小而可组合」路线:两三种搜索方式就做两三个搜索工具,渲染工具也可以拆成一个渲染职位列表、一个高亮单个职位。描述保持简单以免模型过载,但给了模型自由探索、自由组合的灵活性 。
本集带走
- 别只调老 API 塞 UI:模型看不到你的界面就是黑盒,追问必翻车。展示给用户的每个数据,都要同步给模型(结构化内容 + 资源 URI,且保持同步)。
- 用工具描述划清分工:写明「结果已作为 UI 自动展示」,模型就不会再用文字复述一遍。
- 交互状态也要上报:用户点了哪条、弹窗里是什么,用 update model context 传给模型——它只收一个字符串,多事件靠追加。
- 数据和渲染必须拆开:搜索工具纯文本、随便多调;渲染工具只收 ID。否则模型调一次就收工,不再深挖。
- 先数据后 UI:想清楚给模型什么数据、让它能做什么,渲染是探索的副产品。
- 小工具 + 简单描述:多个窄搜索工具配一两个渲染工具,给模型组合自由,又不让它过载。
- 让渲染工具有个性:让模型传入推荐理由或高亮段落,UI 体验立刻上一档。
除非你自己试过,否则你会惊讶:要让 Claude 或 ChatGPT 输出链接真的很难,因为它们不想让你离开它们的环境。
you’d actually be surprised, unless you’ve tried to do this yourself, that it’s really hard to get Claude or ChatGPT to link to things, because they don’t want you to leave their environment.
—— Dustin Mihalik · [02:02]
任何你展示给用户的东西,也需要作为数据提供给模型。
anything that you show to the user also needs to be provided as data to the model.
—— Dustin Mihalik · [04:13]
我不会把简单的问题丢给 Claude 去解决,我把真正难的问题丢给 Claude 去解决。
I don’t give Claude my easy problems to solve. I give Claude my really hard problems to solve.
—— Dustin Mihalik · [08:26]
你要在关注 UI 之前先关注数据
you want to focus on the data before you focus on the UI
—— Dustin Mihalik · [13:39]
顺着「智能体」挖下去
- 当 AI 决定买什么软件:G2 的「信任层」生意同概念:ChatGPT、Claude、MCP
- 把互联网装进智能体:FastMCP 作者用 Python 造 UI 的古怪实验同概念:MCP、MCP Apps、Claude
- 产品经理驾驭 Claude 生态:用五层架构打造专属 AI 幕僚长同概念:Claude、MCP
换个口味
- 一封邮件睡出一万七千美金:Every 的 Builder Pack 内幕同概念:Claude、MCP
- Axios CEO Jim VandeHei:直面、删除、放大——AI 时代的简化生存法同概念:ChatGPT、Claude
- Dan Shipper:15人零手写代码,AI原生公司怎么运转同概念:ChatGPT、Claude
