Skip to content

Commit 06c0838

Browse files
committed
finish instructions for 1 and 2
1 parent 6c8bed2 commit 06c0838

File tree

7 files changed

+223
-0
lines changed

7 files changed

+223
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,52 @@
11
# Raw HTML
2+
3+
👨‍💼 When users ask our AI assistant about specific tags or categories, they expect to see that information presented clearly and visually, not just as a wall of text. Think about it - when someone asks "What is the 'javascript' tag about?" they want to see a nicely formatted card with the tag name prominently displayed and a clear description, not just raw text that says "javascript: A programming language for web development."
4+
5+
The problem is that our current system only returns plain text responses, which makes it harder for users to quickly scan and understand the information. Users have to read through paragraphs of text to find what they're looking for, and important details can get lost in the noise.
6+
7+
To solve this, we need to transform our text-based responses into rich, visual interfaces that users can quickly scan and understand. This is where MCP UI comes in - it allows us to send HTML content that gets rendered as actual visual components instead of plain text.
8+
9+
Here's the example of a weather card again:
10+
11+
```ts
12+
import { createUIResource } from '@mcp-ui/server'
13+
14+
// Create a UI resource with raw HTML
15+
const resource = createUIResource({
16+
uri: 'ui://weather-card/lagos-nigeria',
17+
content: {
18+
type: 'rawHtml',
19+
htmlString: `
20+
<div style="padding: 20px; border: 1px solid #ccc; border-radius: 8px; background: linear-gradient(135deg, #74b9ff, #0984e3); color: white;">
21+
<h1>Lagos, Nigeria</h1>
22+
<p>85°F - Partly Cloudy</p>
23+
<p>Humidity: 78% | Wind: 12 mph</p>
24+
</div>
25+
`,
26+
},
27+
encoding: 'text',
28+
})
29+
```
30+
31+
The key difference is that instead of returning plain text content, we're returning a UI resource that clients can render as an actual visual component. This transforms the user experience from reading text descriptions to interacting with rich, visual interfaces.
32+
33+
<callout-info>
34+
The `createUIResource` function packages your HTML content into a format that
35+
MCP clients can understand and render. The `uri` parameter creates a unique
36+
identifier for your UI resource, while the `content` specifies what type of UI
37+
you're providing.
38+
</callout-info>
39+
40+
When there's no tag found, we should also provide a clear visual indication rather than just text:
41+
42+
<callout-info>
43+
The styling in these examples uses inline CSS for simplicity, but you can use
44+
any valid HTML markup. Consider using CSS classes or even external stylesheets
45+
for more complex designs.
46+
</callout-info>
47+
48+
The goal is to make tag information feel immediate and scannable for users, so they can quickly understand what each tag represents without having to parse through walls of text.
49+
50+
Now, let's implement this visual transformation by updating the `get_tag` tool to return a UI resource instead of plain text.
51+
52+
- 📜 [MCP UI Server Documentation](https://mcpui.dev/guide/server/typescript/usage-examples#metadata-configuration-examples).
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
# Raw HTML
2+
3+
👨‍💼 Great work! We've successfully transformed our tag information from plain text responses into rich, visual interfaces that users can quickly scan and understand. This is a game-changer for user experience - instead of users having to parse through walls of text to find tag information, they now get immediate, scannable visual cards that make the information feel accessible and professional.
4+
5+
This improvement means users get instant visual feedback when they ask about tags, making the AI assistant feel more like a modern application and less like a command-line tool. The visual presentation helps users quickly identify tag names and descriptions without having to read through paragraphs of text.
6+
7+
🧝‍♀️ I'm going to be doing more of what we just did and make it prettier. Feel free to do that yourself or just <NextDiffLink>check out my changes</NextDiffLink> if you're interested.

exercises/01.simple/FINISHED.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
# Simple
2+
3+
Congratulations! You've successfully implemented your first MCP UI feature. You've transformed a basic text-based MCP tool into a rich, visual interface that provides users with an immediately scannable and professional experience.
4+
5+
You learned how to use the `createUIResource` function from `@mcp-ui/server` to package HTML content into a format that MCP clients can understand and render. Instead of returning plain text like "javascript: A programming language for web development", your tool now returns a beautifully formatted HTML card that displays the tag name prominently and includes a clear description.
6+
7+
This transformation makes your AI assistant feel more like a modern application and less like a command-line tool. Users can now quickly scan tag information visually instead of parsing through walls of text, making the experience more engaging and professional.
8+
9+
Let's keep moving to continue making the user experience even better with more advanced UI capabilities!
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,55 @@
11
# Remote DOM
2+
3+
<callout-warning>
4+
As of the time of this writing, no popular AI Agent apps support MCP-UI with
5+
Remote DOM, so you'll need to use your imagination 🌈
6+
</callout-warning>
7+
8+
👨‍💼 When users interact with our journaling app, they expect a consistent, professional experience that feels native to the application they're using. Right now, our tag viewer uses raw HTML which means our UI is rendered in an iframe and cannot resemble the variety of agents using our MCP server because it can't integrate with the host application's design system. Users notice this inconsistency and it makes our app feel less polished and trustworthy.
9+
10+
The problem is that raw HTML gives us complete control but also complete responsibility for every aspect of the user interface. This leads to a fragmented user experience where each UI component feels like it belongs to a different application.
11+
12+
Instead, we can use Remote DOM to create UI components that automatically inherit the host application's design system. This means our tag viewer will look and feel like it belongs in whatever application the user is using, whether that's a chat interface, a dashboard, or a mobile app.
13+
14+
```ts
15+
// New approach: Remote DOM with consistent components
16+
const resource = createUIResource({
17+
uri: 'ui://weather-card/singapore',
18+
content: {
19+
type: 'remoteDom',
20+
framework: 'react',
21+
script: `
22+
const stack = document.createElement('ui-stack');
23+
stack.setAttribute('direction', 'vertical');
24+
stack.setAttribute('spacing', '20');
25+
stack.setAttribute('align', 'center');
26+
27+
const title = document.createElement('ui-text');
28+
title.setAttribute('content', 'Singapore');
29+
stack.appendChild(title);
30+
31+
const temperature = document.createElement('ui-text');
32+
temperature.setAttribute('content', '88°F - Partly Cloudy');
33+
stack.appendChild(temperature);
34+
35+
const details = document.createElement('ui-text');
36+
details.setAttribute('content', 'Humidity: 78% | Wind: 12 mph');
37+
stack.appendChild(details);
38+
39+
root.appendChild(stack);
40+
`,
41+
},
42+
encoding: 'text',
43+
})
44+
```
45+
46+
<callout-info>
47+
Remote DOM uses JavaScript to create and manipulate DOM elements using
48+
predefined UI components like `ui-stack`, `ui-text`, and `ui-button`. These
49+
components are automatically styled and provide consistent behavior across the
50+
host application.
51+
</callout-info>
52+
53+
📜 [MCP UI
54+
Server
55+
Documentation](https://mcpui.dev/guide/server/typescript/usage-examples#basic-usage).
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
# Remote DOM
2+
3+
👨‍💼 Excellent work! We've successfully transformed our tag viewer from raw HTML to Remote DOM, solving a critical user experience problem. Now our UI components automatically inherit the host application's design system, creating a consistent and professional experience that feels native to whatever application our users are using.
4+
5+
This transformation means users get a cohesive experience where our tag viewer looks and feels like it belongs in their chat interface, dashboard, or mobile app. Instead of a jarring iframe with custom styling that stands out, they now see beautifully integrated components that match their application's visual language.
6+
7+
The key improvement is that we've moved from writing static HTML with custom CSS to using JavaScript that creates DOM elements with predefined UI components. This provides automatic styling, built-in interactivity, and seamless integration with the host application's design system.
8+
9+
🧝‍♀️ We're going to change direction and take it up a notch by creating a web server that renders a custom-built React UI with React Router. This is a pretty big addition to our setup, so feel free to <NextDiffLink>check out my changes</NextDiffLink> if you're interested.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
11
# Consistent
2+
3+
Congratulations! You've successfully transformed your MCP UI from raw HTML to Remote DOM, solving a critical user experience problem. You've moved from writing static HTML with custom CSS to using JavaScript that creates DOM elements with predefined UI components.
4+
5+
<callout-success>
6+
The key improvement is that your UI components now automatically inherit the
7+
host application's design system, creating a consistent and professional
8+
experience that feels native to whatever application your users are using.
9+
</callout-success>
10+
11+
Instead of rendering in an iframe with custom styling that stands out, your tag viewer now uses `ui-stack`, `ui-text`, and `ui-button` components that seamlessly integrate with the host application's visual language. This means users get a cohesive experience whether they're using your MCP server in a chat interface, dashboard, or mobile app.
12+
13+
Let's keep moving to continue making the user experience even better with more advanced UI capabilities!

exercises/02.consistent/README.mdx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,85 @@
11
# Consistent
2+
3+
While raw HTML gives us visual interfaces, it has limitations when it comes to creating truly interactive and consistent user experiences. Raw HTML requires you to write all the styling from scratch, handle responsive design manually, and manage complex interactions through custom JavaScript. This leads to inconsistent designs across different UI components and makes it harder to maintain a cohesive user experience.
4+
5+
The solution is [**Remote DOM**](https://github.com/Shopify/remote-dom), a library from Shopify that people to safely render arbitrary HTML from an untrusted source. This is a powerful approach that lets you create UI components using a consistent set of web components that are automatically styled and interactive. Instead of writing raw HTML and CSS, you write JavaScript that creates and manipulates DOM elements using predefined UI components.
6+
7+
Example:
8+
9+
```ts
10+
import { createUIResource } from '@mcp-ui/server'
11+
12+
// Create a UI resource with Remote DOM
13+
const resource = createUIResource({
14+
uri: 'ui://tag-view/interactive',
15+
content: {
16+
type: 'remoteDom',
17+
framework: 'react',
18+
script: `
19+
const stack = document.createElement('ui-stack');
20+
stack.setAttribute('direction', 'vertical');
21+
stack.setAttribute('spacing', '20');
22+
stack.setAttribute('align', 'center');
23+
24+
const title = document.createElement('ui-text');
25+
title.setAttribute('content', 'JavaScript');
26+
stack.appendChild(title);
27+
28+
const description = document.createElement('ui-text');
29+
description.setAttribute('content', 'A programming language for web development');
30+
stack.appendChild(description);
31+
32+
const deleteButton = document.createElement('ui-button');
33+
deleteButton.setAttribute('content', 'Delete Tag');
34+
deleteButton.addEventListener('press', () => {
35+
window.parent.postMessage({
36+
type: 'tool',
37+
payload: {
38+
toolName: 'deleteTag',
39+
params: { tagId: '1' }
40+
}
41+
}, '*');
42+
});
43+
stack.appendChild(deleteButton);
44+
45+
root.appendChild(stack);
46+
`,
47+
},
48+
encoding: 'text',
49+
})
50+
```
51+
52+
<callout-info>
53+
Remote DOM uses JavaScript to create and manipulate DOM elements using
54+
predefined UI components like `ui-stack`, `ui-text`, and `ui-button`. These
55+
components are automatically styled and provide consistent behavior across the
56+
host application.
57+
</callout-info>
58+
59+
The key advantages of Remote DOM over raw HTML are:
60+
61+
1. **Consistent Design System**: All UI components use the same styling and behavior patterns
62+
2. **Built-in Interactivity**: Components like `ui-button` come with built-in event handling
63+
3. **Responsive by Default**: Components automatically adapt to different screen sizes
64+
4. **Tool Integration**: Easy integration with MCP tools through `postMessage` API
65+
5. **Framework Agnostic**: Works with React, Vue, or any other framework
66+
67+
<callout-success>
68+
From [the MCP UI
69+
documentation](https://mcpui.dev/guide/server/typescript/usage-examples#basic-usage):
70+
Remote DOM content is delivered as
71+
`application/vnd.mcp-ui.remote-dom+javascript` MIME type and allows you to
72+
create interactive UI components using JavaScript that manipulates the DOM
73+
with predefined UI elements.
74+
</callout-success>
75+
76+
The Remote DOM approach transforms your UI from static HTML into dynamic, interactive components. Instead of writing CSS and managing complex interactions manually, you use a consistent set of UI components that handle styling and behavior automatically.
77+
78+
<callout-warning>
79+
It is a bit clunky to write, but the benefit of being able to use "native" UI
80+
components to the host application is powerful.
81+
</callout-warning>
82+
83+
The key difference from raw HTML is that instead of writing static markup, you're writing JavaScript that creates and manipulates DOM elements using a consistent component system. This provides a much more consistent user experience.
84+
85+
- 📜 [MCP UI Server Documentation](https://mcpui.dev/guide/server/typescript/usage-examples#basic-usage)

0 commit comments

Comments
 (0)