Dustin Mihalik is a software engineer working on language-model applications and AI-platform infrastructure at Indeed. In his talk on MCP apps, he described working on Indeed’s AI-platform team, with responsibilities spanning guardrails, gateways, and compliance. His team’s conversational job-search integrations illustrate a practical design problem: an interface can show useful results while leaving the assistant unable to understand them or continue searching.
API widgets, component documentation, and prompt evaluation
A 2012 Platform API tutorial announcement credited to Dustin Mihalik identifies its author as a former senior software engineer at Bazaarvoice; the supplied evidence does not independently establish that this author is the Indeed speaker. Published on April 4, 2012, the post introduces a tutorial for building a JavaScript widget that retrieves Bazaarvoice content through JSONP and displays it using templates. The described example separates retrieving structured information from presenting it on a webpage.
The open-source React Storybook Docgen Addon, published under the GitHub account mihalik, brings generated component documentation into Storybook, putting information about components alongside the environment developers use to work with them. The repository states that the module is no longer actively developed. The supplied evidence does not establish that this GitHub account belongs to the speaker.
The same account’s experimental command-line tool LLMStat addresses another part of the development process: generating language-model responses, evaluating prompts against datasets, and comparing runs. It uses JSON-based configuration and output and delegates assertions to Promptfoo. Its support for evaluating saved responses separates generation from evaluation, so developers can inspect an existing run without generating every answer again.
Keeping job-search widgets and assistants in sync
At the time of his MCP-apps talk, Mihalik’s team had worked on integrations for Claude, ChatGPT, and Career Scout, Indeed’s job-seeker agent. He described the effort required to make text-based assistants consistently include usable job links. Widgets gave the team control over application buttons, highlighted details, and a modal containing the full job description. Those controls made results easier to act on, but introduced a new problem: information visible to the user could remain invisible to the model.
Displayed records: Mihalik argues that displayed data and model context must stay aligned. If a widget retrieves records through its own APIs, the assistant may be unable to answer a follow-up such as “tell me about the first result” or rank the companies on screen. His approach returns both structured content for the model and a resource URI pointing to the widget’s HTML, keeping the data supplied to the model synchronized with what the interface displays.
User selections: User interactions require the same care. Opening a job-details modal tells the interface which position the user selected, but does not automatically tell the assistant. Passing the selected job and its details into model context gives a subsequent request for a summary or cover letter the information it needs. In the talk, Mihalik described using the MCP-apps context-update method to communicate these changes.
Interface behavior: Tool descriptions also need to explain the interface’s behavior. Even with access to the underlying records, an assistant can repeat the widget’s contents in a long text response because it does not understand that results are already visible. Mihalik recommends stating that the tool displays results as UI components, allowing the assistant to provide a brief introduction or useful commentary rather than duplicate the display.
Separating search from rendering
His most consequential recommendation is to separate search from rendering, a principle he explicitly credits to OpenAI’s Apps SDK documentation. Text-based job-search tools allowed Claude to make repeated searches and combine their results. A tool that immediately displayed a carousel could instead encourage the assistant to stop after one call; repeated calls would also leave the user with multiple carousels rather than a considered shortlist.
The distinction matters for a job seeker willing to relocate, seeking higher pay, and excluding particular industries. That request requires searching across cities, comparing opportunities, and filtering results before deciding what to show. His team separated a search tool that returned data without UI from a rendering tool that accepted selected job IDs. In Mihalik’s illustrative example, the assistant could gather a hundred candidates, choose five, and display those five. Rendering-tool descriptions explained which tools supplied the inputs and what format those inputs required.
Mihalik favors small composable tools that give the model flexibility without overloading individual descriptions: several ways to search, a tool to display a list, or another to highlight one job. He also proposed extending rendering inputs with a reason a position fits or a passage from the job description worth emphasizing. These were possibilities for carrying the assistant’s judgment into the widget alongside the job record.
A personal MCP server for professional information
ME-MCP, another project published under the unbridged GitHub account mihalik, applies MCP to professional information and communication. Designed for Cloudflare Workers, the lightweight Streamable HTTP server lets agents retrieve résumé information and send messages through Discord webhooks. It gives those agents explicit operations for accessing information and contacting the configured server owner, illustrating how data can become usable within the tools where an interaction takes place.
Dustin Mihalik’s lessons from Indeed show why an attractive widget can weaken an agent—and how separating search, selection, rendering, and interaction context preserves both model capability and a useful interface.
Anything visible in an MCP App must also be available as model-readable data, or follow-up questions encounter a black box.