AI Engineer World's Fair 2026

MCP Apps: Primitives, Discovery, and the Future of Software

Read the talk

MCP Apps: Primitives, Discovery, and the Future of Software

MCP Apps bring interactive interfaces into agent conversations, with explicit control over model context, tool calls, streaming updates, and distribution through client stores.

From a talk by Pietro Zullo

Before you start: Familiarity with MCP tool calls and basic React or TypeScript will help you follow the implementation examples.

You built an MCP server. How do people use it?

You know how an MCP server gives an agent access to tools. But can that server also deliver an interactive interface? And how do users discover and install it without editing configuration files? These are the gaps Pietro Zullo, who introduces himself as Manufact’s co-founder, starts with: developers increasingly recognize MCP, yet many do not realize they can build and distribute MCP Apps.

Introductory slide describing the knowledge gap around what MCP Apps are, how they work, and how to build and distribute them.Open full source frame
You know MCP. Do you know MCP Apps?

MCP had been around since 2024; interactive apps became more visible toward the end of 2025. Building the server is only part of the opportunity. The next steps are to make its results useful to people inside an agent conversation and make the integration easy to find. Zullo’s larger premise is that these agent clients will become a primary way people use software.

0:010:15
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:01 · section reference included

A development stack and two ecosystem changes

Manufact organizes its tools around building, testing, and shipping MCP integrations. Its open-source mcp-use SDKs abstract the official SDKs for servers, clients, and agents. Zullo reports more than eight million downloads across the SDKs and 10,000 GitHub stars. Those are his reported adoption totals, without a measurement window or download-counting methodology.

The open-source Inspector provides local testing for both servers and apps. Manufact Cloud then deploys servers from GitHub repositories, makes them available for immediate testing and team sharing, and adds evaluations and publishing checks. The sequence is straightforward: implement the integration, inspect its behavior locally, then deploy and prepare it for distribution.

The interface work began before the official extension. Zullo dates the start of MCP-UI to around late May 2025. Its creators, Ido Salomon and Liad Yosef, explored how servers could return UI components alongside tool interactions. OpenAI’s Apps SDK subsequently brought interactive MCP-based experiences into ChatGPT.

Distribution was changing too, although directory launches and access to developer submissions are different milestones. The Claude connectors directory launched in July 2025; OpenAI opened ChatGPT app submissions in December. Zullo describes the broader transition from directories populated through design partnerships toward a submission process more developers could use.

MCP Apps became an official protocol extension on January 26, 2026, building on MCP-UI and the Apps SDK; MCP-UI continued as a project. Together, the UI extension and expanding store access changed what a server could offer: richer interactions, plus vetted listings with one-click installation. Zullo points to OpenAI, Anthropic, and Cursor as participants in this distribution shift, with increasing acceptance of ChatGPT apps and Claude connectors.

1:381:50
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

1:38 · section reference included

How a tool call becomes a widget

An MCP App keeps the familiar arrangement: the model runs within a host application, and tools live on an MCP server. During a conversation, the model calls a tool and the host displays a widget beneath the streamed text. The widget runs in a sandboxed iframe, with a bidirectional channel connecting it to the host. That channel makes the UI interactive within the conversation rather than merely a rendered attachment.

The MCP Apps specification makes the rendering sequence more precise:

  1. The server declares UI resources and links the appropriate resource from tool metadata.
  2. The model calls the tool with arguments.
  3. The host fetches the linked resource through resources/read and forwards tool data to the app.
  4. The client renders the resource in its sandboxed iframe.

The UI does not replace the JSON-RPC transport. It adds a human-facing presentation to the tool interaction. Instead of translating a wall of text into a mental picture, the user can inspect organized cards, charts, or other controls directly.

6:016:09
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

6:01 · section reference included

Tell the model what changed in the UI

The host listens for messages from the widget, but the model cannot continuously inspect the widget’s state. A UI might display three items, let the user select one, and change its appearance without the model learning anything about that interaction. The application must deliberately communicate the relevant state.

Zullo demonstrates this with mcp-use’s setState syntax. At the protocol level, the relevant operation is ui/update-model-context: it makes context available for future turns rather than necessarily starting a new model response. The demo begins with nothing selected. After the user adds Trailblazer Pro, the widget marks it Added and the displayed model context includes it in the cart. A subsequent user message can therefore refer to the selection without restating it.

Slide titled ui/update-model-context with a code example and shopping widget showing Trailblazer Pro marked Added and included in the model context cart.Open full source frame
Adding Trailblazer Pro updates the displayed model context.

The state transition can be expressed with a small TypeScript handler using the demonstrated setState name:

typescript

type CartState = { cart: string[] };

export function addTrailblazerPro(
  state: CartState,
  setState: (next: CartState) => void,
): CartState {
  const product = "Trailblazer Pro";
  const next = {
    ...state,
    cart: state.cart.includes(product)
      ? state.cart
      : [...state.cart, product],
  };

  setState(next);
  return next;
}

Here the cart field is a simple representation of the same interaction: an empty selection becomes a selection containing Trailblazer Pro, and that state is explicitly shared. Updating a button’s appearance alone would not provide that context.

8:178:34
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

8:17 · section reference included

Messages, streaming inputs, and additional tool calls

A widget can also initiate a conversational follow-up. In the shoe example, the Learn More button beside Trailblazer Pro calls sendFollowUpMessage so the user does not have to type the product name and question again. Zullo describes different host behavior in the demonstration:

HostFollow-up behavior described
ClaudePlaces the message in the input for the user to send
ChatGPTSends the message and begins streaming a response

These are host-specific interaction choices; the protocol’s ui/message operation does not establish identical consent behavior everywhere.

The next primitive moves in the opposite direction: partial tool arguments can update the widget while the model is still generating them. Rather than waiting for complete input, the UI consumes successive partial inputs and progressively renders the result. This suits visual previews such as SVG. Manufact also built a Remotion MCP app that creates video with React and renders it inside the widget as tokens arrive. Partial-input notifications depend on host support; use them for incremental presentation, not as authorization to perform a critical operation on unfinished arguments.

Finally, a widget can request more server data directly. A button may call the original tool again or invoke another tool on the MCP server. That gives the user a conventional interface for fetching additional details without requiring a fresh natural-language request for every interaction. Zullo shows this through mcp-use primitives, completing three distinct paths: the widget can send a message, react to streaming tool input, or call a tool itself.

10:0110:12
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

10:01 · section reference included

Separate what the user sees from what the model receives

A server may need to show a person sensitive information without placing that information in the model’s context. Zullo introduces this as a limitation of returning private data through ordinary tool output: if the data enters the model-facing result, the model receives it whether or not it needs it. MCP Apps allow the interface and the model-facing response to carry different information.

The example is a card containing a person’s private information. The tool result supplies rich data for the widget and a separate, deliberately limited output for the model:

RecipientInformation supplied
WidgetDetails needed to render the private-information card
ModelSelected context about what the user is viewing

The model-facing text can simply explain that the user is seeing private information in the widget above, without reproducing those details. The model then has enough context to continue the interaction while the person can read the actual card.

Selective model context is not a guarantee of isolation from the hosting provider. The tool-result flow still passes through the host. The useful design boundary is narrower: choose which information enters model context, rather than assuming everything displayed must also be supplied to the model. That distinction matters in the privacy-sensitive workflows motivating the example.

13:0313:23
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

13:03 · section reference included

Give the widget enough room

The default widget appears inline with its tool call, but requestDisplayMode lets the app request a different presentation. Fullscreen is especially useful for a visual workspace: in Zullo’s video-editing example, the widget occupies the chat area and the chat input overlays it. The user asks for changes while looking at the video interface, and the model can stream updates into that same workspace.

The three modes serve different presentation needs:

  • Inline: Keep the widget within the conversational flow.
  • Picture-in-picture: Present the widget in a separate compact view.
  • Fullscreen: Give a visual task the main workspace.

Other host integration primitives open external links and expose the host theme so the app can match its surroundings.

Three diagrams labeled inline, pip, and fullscreen, with notes about opening links, theme and locale, and intrinsic size.Open full source frame
Inline, picture-in-picture, and fullscreen display modes.
15:2315:32
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

15:23 · section reference included

The same primitives across different clients

After the presentation mock-ups, Zullo switches to recorded application demonstrations. In Cursor, a Manufact MCP App displays analytics for the Remotion MCP server app. He connects this to his team’s use of Postgres MCP: people inspect the analytics visually while the model reads the relevant data and continues working on code. The chart and the tool result support different participants in the same task.

The Claude recording then shows the streaming pattern through an Excalidraw MCP server. Claude first reads instructions returned by the server, then calls the tool that displays a canvas. As Mermaid-style syntax streams into the tool arguments, the diagram updates on the canvas. The visible result develops alongside generation rather than appearing only after the tool input is complete.

A final recording shows the Manufact analytics widget in ChatGPT. Zullo comments that its rendering looks better there, leading into a practical constraint: clients support different portions of the app experience. He names Claude Cowork and Claude Desktop, ChatGPT and Codex, Cursor’s agent mode and side chat, and VS Code as supporting clients at the time of the talk. That list describes the ecosystem he is demonstrating, not identical feature coverage across versions.

A server therefore needs to account for whether the connected host can render its UI. Zullo discusses the client metadata exchanged through MCP and mcp-use’s support-detection helpers; the specified mechanism to rely on is capability negotiation, rather than client name alone. A client without app support may simply omit the widget. If essential information was supplied only to that widget, the remaining tool response can become incomplete, so the server may need a different model-facing output for that case.

16:3616:45
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

16:36 · section reference included

Build from an ordinary server and a React component

The mcp-use development model begins with the server constructor and tool definitions. Tools then return widgets. In the version shown in the talk, widget files placed in the resources folder automatically register as UI resources that tools can return. A widget is a React component, so existing UI components can be reused; the build compiles them into HTML and CSS and links the resulting resource to the tool. The current repository uses a different layout, such as views/weather-card/view.tsx with a view.name association, so preserve the demonstrated convention when following the recording and use the matching SDK version’s conventions when implementing.

Zullo also points to a supplied skill and starter template. His starter command is:

bash

npx create-mcp-use-app

The progression remains familiar: define the server’s tools, build the React interface, and connect the tool’s data to that interface. The SDK handles the registration and packaging work around those pieces.

20:3020:40
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

20:30 · section reference included

Prepare the server for store review

Store distribution applies to ordinary MCP servers as well as apps with UI. Zullo describes self-serve submission paths for ChatGPT, Claude, and Cursor, with Claude’s Team and Enterprise submission form newly available at the time. Eligibility, forms, and review processes differ by provider; returning a widget is not itself a prerequisite for submitting a server.

Zullo reports slower review on Claude and accelerating acceptance on ChatGPT during this period. The common submission sequence he describes is:

  1. Provide the remote MCP endpoint. The review process inspects the server’s exposed tools.
  2. Check tool definitions. Annotations and arguments need to describe the tools correctly.
  3. Declare and validate authentication. If the server requires authentication, reviewers need a working path through it.
  4. Supply test cases and prompts. Automated and manual checks exercise the integration before acceptance or rejection.
  5. Publish after acceptance. The listing becomes available through ChatGPT’s apps directory, Claude’s Connectors directory, or Cursor’s directory.

A successful local demonstration is therefore only one part of submission: the remotely accessible tools, authentication, and review materials must also work together.

Manufact’s publishing support attempts to run the checks clients will perform before submission. With its cloud connected to the MCP server, it also generates submission artifacts such as screenshots and test cases. This extends the earlier build–test–deploy workflow into preparation for review.

21:4121:50
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

21:41 · section reference included

Discovery begins with a user’s task

A listing first improves conventional discovery: users can search a store, or follow a shared installation link instead of receiving an MCP configuration JSON file. Zullo then describes a more consequential possibility: when Claude lacks a tool for an assigned task, it searches an MCP registry for a suitable connector. This is his recording-time account of dynamic discovery, a stronger behavior than merely browsing a directory or choosing among already connected tools.

Zullo claims more than one billion active users across the applications under discussion, without specifying an activity interval or deduplication method. That aggregate is not an individual connector’s reachable audience. His distribution argument instead rests on intent: a user describes a task, the model identifies an appropriate connector, and a listed product can be discovered at the moment it is useful. The opportunity depends on being selected for that task, not just appearing in the store. He presents Claude as offering this behavior at recording time and ChatGPT support as an expectation, not an already demonstrated capability.

24:4024:54
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

24:40 · section reference included

From meeting notes to a pull request

Zullo reports that store presence brought Manufact substantial traffic, without giving a numerical result. As a buyer, he now treats MCP availability as a basic product criterion. Much of his daily work happens in Claude Cowork or Claude Code because those environments let him share context between a codebase and multiple connectors.

His customer-feedback workflow makes that preference concrete:

  1. Pull meeting notes containing customer feedback through Granola’s MCP integration.
  2. Use that feedback to create Linear tickets for the team, with codebase context available in Claude Code.
  3. Have an agent retrieve a Linear ticket through MCP, implement the work, open a pull request, and close the ticket.

He imagines a further step—emailing the customer through MCP to say the issue is fixed—but explicitly leaves that as an aspiration. The described workflow reaches the code and ticketing systems; the customer notification is not presented as an accomplished part of it.

Zullo closes by invoking Paul Graham’s analogy that AI apps are becoming browsers, with Claude Code, Codex, and Claude Cowork as examples. If conversational systems already serve some of the role of search, connectors extend that shift from finding information to taking action. His corresponding analogy is that MCP servers become websites, and MCP Apps provide their interfaces.

Slide arguing that products need an MCP App version, beside a Paul Graham post reading “AI apps are the new browsers.”Open full source frame
Be there, or get bypassed.

That makes the dashboard part of the same workspace as the task. Zullo wants to inspect a product’s interface inside Claude or Claude Code, where the agent already has the relevant context, rather than leave the conversation to visit a separate dashboard. His closing invitation is to ship an MCP App: make the product’s actions available to the agent and its useful interface available to the person working beside it.

26:1526:29
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

26:15 · section reference included

Resources

From the talk

  • Framework with server tools, React views and an integrated Inspector; the README provides a working starter pattern.

  • MCP deployment platform with testing, analytics and app-publication preparation tools.

Transcript download
Read the transcript and explore slides

Loading transcript and slides…