{
  "video": {
    "id": "lbaXnx0KLA8",
    "title": "MCP Apps: Give the Model Data, Give the User a UI — Dustin Mihalik, Indeed",
    "duration": 934,
    "upload_date": null,
    "channel": "AI Engineer",
    "source": "AI Engineer"
  },
  "analysis": {
    "video_id": "lbaXnx0KLA8",
    "title": "MCP Apps: Give the Model Data, Give the User a UI — Dustin Mihalik, Indeed",
    "one_liner": "Indeed's lessons from shipping MCP apps to Claude, ChatGPT and its own Career Scout agent: everything you render must also be handed to the model as data, and — rule three, which supersedes the rest — you must split data-processing tools from UI-rendering tools or the model stops doing the multi-search work you actually wanted.",
    "summary": "Dustin Mihalik works on Indeed's AI platform team (guardrails, gateways, compliance) and walks through the practical failure modes his team hit turning job search into an MCP app. He argues an MCP app that just injects HTML and calls your existing APIs is a black box to the model — so anything shown to the user must also come back as structured content, user interactions must be pushed back via update model context, and tool descriptions must tell the model that results are already displayed. The core lesson is that a single search+render tool makes Claude call it once and skip the deep multi-search exploration that text-based MCP does brilliantly; the fix is a text-only search tool plus a separate render tool that takes a list of IDs.",
    "key_points": [
      "Getting Claude or ChatGPT to reliably link out is genuinely hard because the hosts don't want users leaving their environment — Indeed spent 'a ridiculous number of hours and evals' just to make Claude link consistently; MCP apps solve this with an in-app apply button and a view-details modal so the user never leaves the chat.",
      "Rule 1: anything you show the user must also be provided as data to the model. You return both structured content (what a text-based MCP tool would already return) and a resource URI pointing at the HTML, and you keep the two in sync — add a field to the API, add it to the structured content too.",
      "Rule 2: once the model has the data, it will still narrate it as it normally would, so you get the widget plus a redundant text dump. Putting something as simple as 'results were automatically displayed to the user as UI components' at the top of the tool description 'covers quite a bit of the cases'.",
      "User interactions are invisible to the model — return 10 jobs, the user clicks one, and the model has no idea which. MCP Apps' update model context method fixes this, but it takes a single string, so tracking multiple events over time means appending to that string. The docs' example is a shopping cart passing total cost and line items.",
      "The failure that motivates rule three: a combined search+render tool makes Claude call it once and conclude 'the results are already displayed' — killing the 10–15 parallel searches, filtering and cherry-picking that text-based MCP does well for a query like 'this title, willing to relocate across many cities, highest-paying, not these industries'. Nobody wants ten carousels either.",
      "Rule 3, which supersedes the others (wording taken from OpenAI's Apps SDK docs): separate data processing from UI rendering. Indeed split search jobs (text-only, returns no UI, callable as many times as the model likes) from a render jobs widget that takes a list of job IDs, so Claude can search 100 jobs, filter to five, and render those five.",
      "Render tools are a place to let the model be creative: pass an ID plus the reason the model thinks it's a good fit, or an ID plus a section of the job description to highlight — injecting the model's judgement into your branded UI."
    ],
    "takeaways": [
      "Design the data contract before the UI: decide what data the model should be able to explore, and treat rendering as a result or side effect of that exploration, not the starting point.",
      "Always return structured content alongside the resource URI, and pipe user interactions (clicks, modal opens, cart state) back through update model context — appending to the single string if you need multiple events.",
      "Split every search/browse tool from its render tool, and use tool descriptions to enforce the ordering ('always call one of these three tools first' to get the data used for rendering), plus a line stating that results are already shown as UI.",
      "Prefer many small composable tools — two or three search variants, plus a render-a-list and a render-one-highlighted tool — so descriptions stay simple and don't overload the model while leaving it flexibility.",
      "Look for the data/render split in your own domain: e-commerce options, or a map tool where the model derives five addresses and passes those addresses in to be rendered."
    ],
    "topics": [
      "mcp",
      "mcp-apps",
      "apps-sdk",
      "tool-design",
      "agents",
      "ui",
      "evals"
    ],
    "tools": [
      "Indeed",
      "MCP (Model Context Protocol)",
      "MCP Apps",
      "OpenAI Apps SDK",
      "Claude",
      "ChatGPT",
      "OpenAI",
      "Career Scout (Indeed's job-seeker agent)",
      "Sonnet 5"
    ],
    "quotes": [
      {
        "text": "it's really hard to get Claude or ChatGPT to link to things cuz they don't want you to leave their environment. It makes complete sense, but uh if you get back, here's five jobs that are somewhere on the internet uh without any links, that's a terrible user experience.",
        "at": "02:07",
        "url": "https://www.youtube.com/watch?v=lbaXnx0KLA8&t=127s"
      },
      {
        "text": "anything that you show to the user also needs to be provided as data to the model.",
        "at": "04:13",
        "url": "https://www.youtube.com/watch?v=lbaXnx0KLA8&t=253s"
      },
      {
        "text": "I don't give Claude my easy problems to solve. I give Claude my really hard problems to solve, right? Like if I just wanted to do one search, I would go to the web and do one search.",
        "at": "08:29",
        "url": "https://www.youtube.com/watch?v=lbaXnx0KLA8&t=509s"
      },
      {
        "text": "this is rule three, this like supersedes all the other rules, uh which is basically you want to separate your data processing from your UI rendering.",
        "at": "10:07",
        "url": "https://www.youtube.com/watch?v=lbaXnx0KLA8&t=607s"
      }
    ],
    "words": 3022
  },
  "summary_url": "/#lbaXnx0KLA8",
  "transcript": {
    "html": "/transcripts/lbaXnx0KLA8.html",
    "txt": "/transcripts/lbaXnx0KLA8.txt",
    "vtt": "/transcripts/lbaXnx0KLA8.vtt"
  }
}