How an app is wired together app-architecture
IMPORTANT
Adobe LLM Apps is currently in Beta.
Features, workflows, and UI shown here do not necessarily represent the final state of the product. To join the Beta, send an email to llm-apps-beta@adobe.com.
In one sentence
An LLM App is a set of Actions (each one a tool exposed over the Model Context Protocol, or MCP) that you publish to a single endpoint. A chat host like ChatGPT discovers those tools, calls them mid-conversation, and renders an interactive widget with the result — right inside the chat.
The whole wiring, build → run
Diagram 1 — build time. You own three separate surfaces; the platform fuses them into one deployable app.
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 1 LLM Apps UI │ │ 2 Action Handler │ │ 3 Widget repo │
│ │ │ repo │ │ │
│ Create, edit, and │ │ │ │ Each widget is an │
│ manage your action │ │ Business logic — │ │ EDS block, │
│ definitions here │ │ built from our │ │ published to a │
│ (metadata) │ │ boilerplate │ │ public URL on │
│ │ │ │ │ *.aem.page │
│ │ │ Returns content │ │ │
│ │ │ (for the LLM) + │ │ │
│ │ │ structuredContent │ │ │
│ │ │ (for the widget) │ │ │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
│ │ │
└─────────────────────────┼─────────────────────────┘
▼
┌─────────────────────────────┐
│ LLM Apps deploy pipeline │
│ Combines the 3 surfaces │
│ into one running app │
└─────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ ONE MCP server on Adobe I/O Runtime │
│ https://<ns>.adobeioruntime.net/.../mcp │
└─────────────────────────────────────────┘
- LLM Apps UI — where you create, edit, and manage each Action’s definition: its code identifier (a fixed slug you set once here, e.g.
my_action, that ties this same Action together across the UI, the handler, and the widget), description, input schema, widget choice, and CSP/visibility flags. No code. - Action Handler repo — the server-side repo (scaffolded from our boilerplate) where you write the business logic. Every handler function returns two things:
content(plain text the LLM reads) andstructuredContent(the data object the widget reads). - Widget repo — the EDS repo where each widget lives as a block and gets published to a public
*.aem.pageURL. Each block uses@adobe/llmapps-sdk, the bridge between the widget and the host/server. It implements the MCP Apps specification — the underlying protocol — behind a simple API, and it abstracts away the LLM host itself, so the same widget works unmodified in ChatGPT, Claude, Gemini, or any other MCP host.
Diagram 2 — runtime. What happens on every message the user sends, once that one server is live. Shown with ChatGPT as the example host — the same sequence plays out for any MCP host, such as Claude.
┌── ChatGPT (the MCP host) ──────────────────────────────────────────────┐
│ 1 tools/list > sees `my_action` + its description + input schema │
│ 2 user asks > "I need help with …" │
│ 3 model picks > the description matches -> calls this tool │
│ 4 tools/call > { name: "my_action", arguments: {situation, ...} } │
└─────────────────────────────────────────────────────────────────────────┘
│
routes by CODE IDENTIFIER -> my_action
▼
┌── Adobe I/O Runtime ────────────────────────────────────────────────────┐
│ actions/my_action/index.js -- your handler runs │
│ returns { content -> text for the model , structuredContent -> data } │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌── Rendered inside the conversation ─────────────────────────────────────┐
│ 5 render > ChatGPT renders the Widget repo's EDS block │
│ The EDS block reads the structuredContent the Action Handler repo │
│ returned, and draws the interactive card — live, inside the chat. │
└─────────────────────────────────────────────────────────────────────────┘
recommendation-more-help
llm-apps-help-main-toc