You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -28,6 +28,8 @@ cd A2UI/samples/mcp/a2ui-over-mcp-recipe
28
28
uv run .
29
29
```
30
30
31
+
### Option A: Interacting via the MCP Inspector
32
+
31
33
In a separate terminal, launch the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to interact with the server:
32
34
33
35
```bash
@@ -38,8 +40,10 @@ In the Inspector:
38
40
39
41
1. Set **Transport Type** to `SSE`
40
42
2. Connect to `http://localhost:8000/sse`
41
-
3. Click **List Tools** → you'll see `get_recipe_a2ui`
42
-
4. Run the tool → the response contains A2UI JSON that renders a recipe card
43
+
3. Click **List Resources** → you'll see "Recipe Form" resource.
44
+
4. Read the `a2ui://recipe-form` resource → the resource content is the A2UI JSON that renders the simple form.
45
+
5. Click **List Tools** → you'll see `get_recipe_a2ui`
46
+
6. Run the tool → the response contains A2UI JSON that renders a recipe card
43
47
44
48
> NOTE: Note
45
49
>
@@ -49,11 +53,57 @@ In the Inspector:
49
53
> pip install a2ui-agent-sdk
50
54
>```
51
55
56
+
### Option B: Running the Recipe Client Web App
57
+
58
+
For a fully rendered interactive experience that visually demonstrates A2UI over MCP, run the included web application:
59
+
60
+
1. In a new terminal window, navigate to the client directory:
61
+
```bash
62
+
cd client
63
+
```
64
+
2. Install Node.js dependencies:
65
+
```bash
66
+
npm install
67
+
```
68
+
3. Start the Vite development server:
69
+
```bash
70
+
npm run dev
71
+
```
72
+
4. Open your browser to the URL displayed in your terminal (usually `http://localhost:5173`).
73
+
74
+
You will see a premium, responsive dual-column interface where the left column renders the Selection Form from MCP Resource (`a2ui://recipe-form`). Picking options and clicking **"Get Recipe"** executes the MCP Tool (`get_recipe_a2ui`), dynamically rendering the returned custom A2UI recipe card in the right column.
75
+
76
+

77
+
52
78
See all samples at [`samples/mcp/`](https://github.com/google/A2UI/tree/main/samples/mcp).
53
79
54
80
## How It Works
55
81
56
-
An MCP server returns A2UI content as **Embedded Resources** inside tool responses. The client detects the `application/json+a2ui` MIME type and routes the payload to an A2UI renderer.
82
+
There are two primary ways an MCP server can deliver A2UI content to a client:
83
+
84
+
1. **Via Reading a Resource (`resources/read`)**: The client reads an MCP resource directly (e.g., `a2ui://recipe-form`). The server returns the A2UI JSON payload directly.
85
+
2. **Via Calling a Tool (`tools/call`)**: The client calls an MCP tool (e.g., `get_recipe_a2ui`). The server returns the A2UI JSON payload wrapped as an **Embedded Resource** inside the tool response.
86
+
87
+
In both cases, the client detects the `application/json+a2ui` MIME type and routes the payload to an A2UI renderer.
88
+
89
+
> [!IMPORTANT]
90
+
>**MIME Type Uniformity**
91
+
> Regardless of the delivery channel (whether fetched directly as a Resource or returned inside a Tool's `CallToolResult`), the A2UI JSON payload is always identified by the `application/json+a2ui` MIME type. In Tool responses, the payload must be wrapped inside an `EmbeddedResource` carrying this MIME type. This uniform identification allows client-side middleware to seamlessly intercept and route both static resources and dynamic tool responses to A2UI.
@@ -68,6 +118,83 @@ Client ← CallToolResult ← MCP Server
68
118
A2UI Renderer displays UI
69
119
```
70
120
121
+
## Resources vs. Tools: Separation of Utility Focus
122
+
123
+
When designing an A2UI integration over MCP, you should choose between **Resources** and **Tools** depending on whether the UI payload is static or dynamic.
124
+
125
+
### 1. Static UI via MCP Resources (`resources/read`)
126
+
127
+
For simple, static user interfaces that do not depend on user prompt inputs or conversation history, you should serve A2UI directly as an MCP Resource.
128
+
129
+
- **Concept**: The client reads a pre-defined A2UI resource using a standard resource URI (e.g., `a2ui://recipe-form`).
130
+
- **Use Case**: Ideal for static configuration forms, selection screens, settings dashboards, or stable layouts.
131
+
- **Benefit**: Extremely simple to implement, low overhead, and doesn't require the LLM/Agent to make a tool call to fetch the structure.
For user interfaces that need to be generated dynamically based on the conversational context, user parameters, or real-time data, you should serve A2UI inside an MCP Tool's response.
162
+
163
+
- **Concept**: The client/Agent calls a tool with specific arguments (e.g., chosen ingredients, preferences), and the server returns a customized A2UI JSON wrapped inside an `EmbeddedResource` in the `CallToolResult`.
164
+
- **Use Case**: Ideal for content that depends on live database queries, previous inputs, interactive step-by-step wizard state, or personalized recommendations (e.g., a customized recipe card).
165
+
- **Benefit**: Maximizes flexibility, context-awareness, and supports highly dynamic flows.
166
+
- **Best Practice (Fallback Text)**: Always include a `TextContent` alongside your `EmbeddedResource` in the `CallToolResult`. Clients that don't support A2UI will fall back to displaying this text to the user.
# Return customized recipe card as EmbeddedResource
186
+
return types.CallToolResult(content=[
187
+
types.EmbeddedResource(
188
+
type="resource",
189
+
resource=types.TextResourceContents(
190
+
uri="a2ui://recipe-card",
191
+
mimeType="application/json+a2ui",
192
+
text=json.dumps(custom_recipe_json),
193
+
)
194
+
)
195
+
])
196
+
```
197
+
71
198
## Catalog Negotiation
72
199
73
200
Before a server can send A2UI to a client, they must establish which catalogs are available. Depending on your architecture, this can happen in one of two ways.
@@ -132,68 +259,6 @@ If your server must remain stateless, the client can pass A2UI capabilities in t
132
259
}
133
260
```
134
261
135
-
## Returning A2UI Content
136
-
137
-
A2UI content is returned as **Embedded Resources** inside a `CallToolResult`. Key rules:
138
-
139
-
-**URI**: Must use the `a2ui://` prefix with a descriptive name (e.g., `a2ui://training-plan-page`)
140
-
-**MIME Type**: Must be `application/json+a2ui` — this tells the client to route the payload to an A2UI renderer
141
-
142
-
### Python Example
143
-
144
-
```python
145
-
import json
146
-
import mcp.types as types
147
-
148
-
@self.tool()
149
-
defget_hello_world_ui():
150
-
"""Returns a simple A2UI hello world interface."""
Copy file name to clipboardExpand all lines: renderers/angular/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,6 @@
1
1
## Unreleased
2
2
3
+
- (v0_9) Fix null de-referencing TypeError in `ComponentBinder` when `children` property is null or undefined. [#1472](https://github.com/google/A2UI/pull/1472)
3
4
- (v0_8) Fix Icon component to handle camelCase and TitleCase names by converting them to snake_case for `g-icon`.
4
5
- (v0_8) Fix Modal component styling and position fixed for overlay.
5
6
- (v0_9) Remove `placeholder` prop support from the `TextField` component, since it was not part of the v0_9 basic catalog schema. [#1372](https://github.com/google/A2UI/pull/1372)
0 commit comments