Skip to content

Commit d4bd152

Browse files
authored
feat: support adapters (#127)
1 parent 061686c commit d4bd152

35 files changed

+3356
-26
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ jobs:
2323
example_files: ${{ steps.filter.outputs.example_files }}
2424
steps:
2525
- uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
2628
- uses: dorny/paths-filter@v2
2729
id: filter
2830
with:
31+
base: ${{ github.event_name == 'push' && github.event.before || github.base_ref }}
2932
filters: |
3033
ts_client_files:
3134
- 'sdks/typescript/client/**'
@@ -152,6 +155,8 @@ jobs:
152155
steps:
153156
- uses: actions/checkout@v4
154157
with: { fetch-depth: 0 }
158+
- name: Fetch all tags
159+
run: git fetch --tags --force
155160
- name: Setup pnpm
156161
uses: pnpm/action-setup@v2
157162
with: { version: 10 }
@@ -184,6 +189,8 @@ jobs:
184189
with: { fetch-depth: 0 }
185190
- name: Pull latest changes
186191
run: git pull --rebase origin ${{ github.ref_name }}
192+
- name: Fetch all tags
193+
run: git fetch --tags --force
187194
- name: Setup pnpm
188195
uses: pnpm/action-setup@v2
189196
with: { version: 10 }
@@ -201,7 +208,7 @@ jobs:
201208

202209
release_ruby_sdk:
203210
name: Release Ruby SDK
204-
needs: [ruby_sdk_test, release_ts_server, filter_changed_paths]
211+
needs: [ruby_sdk_test, filter_changed_paths, release_ts_server]
205212
if: >
206213
always() &&
207214
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/alpha') &&
@@ -244,7 +251,7 @@ jobs:
244251

245252
release_python_sdk:
246253
name: Release Python SDK
247-
needs: [python_sdk_test, release_ruby_sdk, filter_changed_paths]
254+
needs: [python_sdk_test, filter_changed_paths, release_ruby_sdk]
248255
if: >
249256
always() &&
250257
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/alpha') &&

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,7 @@ __pycache__/
193193

194194
# Husky
195195
.husky/_/
196-
.husky/.gitignore
196+
.husky/.gitignore
197+
198+
# Auto-generated files
199+
adapter-runtime.bundled.ts

README.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
## 💡 What's `mcp-ui`?
4141

42-
`mcp-ui` is a collection of SDKs comprising:
42+
`mcp-ui` is a playground for the open spec of UI over MCP. It offers a collection of community SDKs comprising:
4343

4444
* **`@mcp-ui/server` (TypeScript)**: Utilities to generate UI resources (`UIResource`) on your MCP server.
4545
* **`@mcp-ui/client` (TypeScript)**: UI components (e.g., `<UIResourceRenderer />`) to render the UI resources and handle their events.
@@ -143,6 +143,82 @@ Rendered using the internal `<RemoteDOMResourceRenderer />` component, which uti
143143

144144
UI snippets must be able to interact with the agent. In `mcp-ui`, this is done by hooking into events sent from the UI snippet and reacting to them in the host (see `onUIAction` prop). For example, an HTML may trigger a tool call when a button is clicked by sending an event which will be caught handled by the client.
145145

146+
147+
### Platform Adapters
148+
149+
MCP-UI SDKs includes adapter support for host-specific implementations, enabling your open MCP-UI widgets to work seamlessly regardless of host. Adapters automatically translate between MCP-UI's `postMessage` protocol and host-specific APIs. Over time, as hosts become compatible with the open spec, these adapters wouldn't be needed.
150+
151+
#### Available Adapters
152+
153+
##### Apps SDK Adapter
154+
155+
For Apps SDK environments (e.g., ChatGPT), this adapter translates MCP-UI protocol to Apps SDK API calls (e.g., `window.openai`).
156+
157+
**How it Works:**
158+
- Intercepts MCP-UI `postMessage` calls from your widgets
159+
- Translates them to appropriate Apps SDK API calls
160+
- Handles bidirectional communication (tools, prompts, state management)
161+
- Works transparently - your existing MCP-UI code continues to work without changes
162+
163+
**Usage:**
164+
165+
```ts
166+
import { createUIResource } from '@mcp-ui/server';
167+
168+
const htmlResource = createUIResource({
169+
uri: 'ui://greeting/1',
170+
content: {
171+
type: 'rawHtml',
172+
htmlString: `
173+
<button onclick="window.parent.postMessage({ type: 'tool', payload: { toolName: 'myTool', params: {} } }, '*')">
174+
Call Tool
175+
</button>
176+
`
177+
},
178+
encoding: 'text',
179+
// Enable adapters
180+
adapters: {
181+
appsSdk: {
182+
enabled: true,
183+
config: ...
184+
}
185+
// Future adapters can be enabled here
186+
}
187+
});
188+
```
189+
190+
The adapter scripts are automatically injected into your HTML content and handle all protocol translation.
191+
192+
**Supported Actions:**
193+
-**Tool calls** - `{ type: 'tool', payload: { toolName, params } }`
194+
-**Prompts** - `{ type: 'prompt', payload: { prompt } }`
195+
-**Intents** - `{ type: 'intent', payload: { intent, params } }` (converted to prompts)
196+
-**Notifications** - `{ type: 'notify', payload: { message } }`
197+
-**Render data** - Access to `toolInput`, `toolOutput`, `widgetState`, `theme`, `locale`
198+
- ⚠️ **Links** - `{ type: 'link', payload: { url } }` (may not be supported, returns error in some environments)
199+
200+
#### Advanced Usage
201+
202+
You can manually wrap HTML with adapters or access adapter scripts directly:
203+
204+
```ts
205+
import { wrapHtmlWithAdapters, getAppsSdkAdapterScript } from '@mcp-ui/server';
206+
207+
// Manually wrap HTML with adapters
208+
const wrappedHtml = wrapHtmlWithAdapters(
209+
'<button>Click me</button>',
210+
{
211+
appsSdk: {
212+
enabled: true,
213+
config: { intentHandling: 'ignore' }
214+
}
215+
}
216+
);
217+
218+
// Get a specific adapter script
219+
const appsSdkScript = getAppsSdkAdapterScript({ timeout: 60000 });
220+
```
221+
146222
## 🏗️ Installation
147223

148224
### TypeScript

docs/src/guide/apps-sdk.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# OpenAI Apps SDK Integration
2+
3+
The Apps SDK adapter in `@mcp-ui/server` ensures your MCP-UI HTML runs inside ChatGPT. However, for now, you still need to manually wire the resource according to the Apps SDK resource pattern. This guide walks through the manual flow the adapter expects today.
4+
5+
## Why two resources?
6+
7+
- **Static template for Apps SDK** – referenced from your tool descriptor via `_meta["openai/outputTemplate"]`. This version must enable the Apps SDK adapter so ChatGPT injects the bridge script and uses the `text/html+skybridge` MIME type.
8+
- **Embedded resource in tool results** – returned each time your tool runs. This version should *not* enable the adapter so MCP-native hosts continue to receive standard MCP-UI HTML.
9+
10+
## Step-by-step workflow
11+
12+
### 1. Register the Apps SDK template
13+
14+
Use `createUIResource` with `adapters.appsSdk.enabled: true` and expose it through the MCP Resources API so both Apps SDK and traditional MCP hosts can fetch it.
15+
16+
```ts
17+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
18+
import { createUIResource } from '@mcp-ui/server';
19+
20+
const server = new McpServer({ name: 'weather-bot', version: '1.0.0' });
21+
const TEMPLATE_URI = 'ui://widgets/weather';
22+
23+
const appsSdkTemplate = createUIResource({
24+
uri: TEMPLATE_URI,
25+
encoding: 'text',
26+
adapters: {
27+
appsSdk: {
28+
enabled: true,
29+
config: { intentHandling: 'prompt' },
30+
},
31+
},
32+
content: {
33+
type: 'rawHtml',
34+
htmlString: renderInitialShell(),
35+
},
36+
});
37+
38+
server.registerResource(TEMPLATE_URI, async () => appsSdkTemplate.resource);
39+
```
40+
41+
> **Note:** The adapter switches the MIME type to `text/html+skybridge` and injects the Apps bridge script automatically. No extra HTML changes are required.
42+
43+
### 2. Reference the template in your tool descriptor
44+
45+
The Apps SDK looks for `_meta["openai/outputTemplate"]` to know which resource to render. Mirror the rest of the Apps-specific metadata you need (status text, accessibility hints, security schemes, etc.).
46+
47+
```ts
48+
server.registerTool(
49+
'forecast',
50+
{
51+
title: 'Get the forecast',
52+
description: 'Returns a UI that displays the current weather.',
53+
inputSchema: {
54+
type: 'object',
55+
properties: { city: { type: 'string' } },
56+
required: ['city'],
57+
},
58+
_meta: {
59+
'openai/outputTemplate': TEMPLATE_URI,
60+
'openai/toolInvocation/invoking': 'Fetching forecast…',
61+
'openai/toolInvocation/invoked': 'Forecast ready',
62+
'openai/widgetAccessible': true,
63+
},
64+
},
65+
async ({ city }) => {
66+
const forecast = await fetchForecast(city);
67+
68+
// Step 3 happens inside the handler.
69+
return {
70+
content: [
71+
{
72+
type: 'text',
73+
text: `Forecast prepared for ${city}.`,
74+
},
75+
],
76+
structuredContent: {
77+
forecast,
78+
},
79+
};
80+
},
81+
);
82+
```
83+
84+
For the complete list of supported metadata fields, refer to the official documentation. [Apps SDK Reference](https://developers.openai.com/apps-sdk/reference)
85+

docs/src/guide/introduction.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,5 @@ This project is an experimental playground for MCP-UI ideas, that aims to test o
156156
- [Client SDK](./client/overview.md) - Learn to render UI resources
157157
- [Typescript Server SDK](./server/typescript/overview.md) - Learn to create UI resources in Typescript
158158
- [Ruby Server SDK](./server/ruby/overview.md) - Learn to create UI resources in Ruby
159+
- [Apps SDK Integration](./apps-sdk.md) - Wire the existing adapter into ChatGPT's Apps SDK
159160
- [Protocol Details](./protocol-details.md) - Understand the underlying protocol

docs/src/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ hero:
2424
link: /about
2525

2626
features:
27+
- title: 🌐 Open Protocol
28+
details: MCP-UI is an open spec to standardize UI over MCP. Write once, run everywhere!
2729
- title: ⚛️ Client SDK
2830
details: Provides a React component and Web Component for easy frontend integration. Render interactive UI resources and handle UI actions effortlessly.
2931
- title: 🛠️ Server SDKs

0 commit comments

Comments
 (0)