create-mcp-use-app 0.3.5 ā 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +153 -73
- package/dist/templates/apps_sdk/README.md +398 -0
- package/dist/templates/apps_sdk/index.ts +11 -0
- package/dist/templates/apps_sdk/package.json +42 -0
- package/dist/templates/apps_sdk/src/server.ts +239 -0
- package/dist/templates/apps_sdk/src/widgets.ts +180 -0
- package/dist/templates/apps_sdk/tsconfig.json +20 -0
- package/dist/templates/ui/README.md +21 -26
- package/dist/templates/ui/src/server.ts +2 -2
- package/dist/templates/uiresource/README.md +54 -34
- package/dist/templates/uiresource/src/server.ts +6 -6
- package/package.json +5 -2
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# Pizzaz MCP Server - OpenAI Apps SDK Reference
|
|
2
|
+
|
|
3
|
+
An MCP server demonstrating OpenAI Apps SDK integration using `mcp-use`. This implementation showcases the **pizzaz reference widgets** that demonstrate Apps SDK best practices.
|
|
4
|
+
|
|
5
|
+
## š Features
|
|
6
|
+
|
|
7
|
+
- **š Pizzaz Widgets**: 5 reference widgets from OpenAI's Apps SDK examples
|
|
8
|
+
- **š Apps SDK Integration**: Full OpenAI Apps SDK metadata support
|
|
9
|
+
- **š¦ Automatic Registration**: Tools and resources created automatically
|
|
10
|
+
- **š Content Security Policy**: Proper CSP configuration for external resources
|
|
11
|
+
- **ā” Tool Invocation Status**: Real-time status messages during tool execution
|
|
12
|
+
- **šØ External Resources**: Load scripts and styles from OpenAI's CDN
|
|
13
|
+
- **š ļø TypeScript Support**: Complete type safety and IntelliSense
|
|
14
|
+
|
|
15
|
+
## š What's Included
|
|
16
|
+
|
|
17
|
+
### Pizzaz Widgets
|
|
18
|
+
|
|
19
|
+
This server includes all 5 pizzaz reference widgets:
|
|
20
|
+
|
|
21
|
+
1. **pizza-map** - Interactive map widget
|
|
22
|
+
2. **pizza-carousel** - Carousel browsing widget
|
|
23
|
+
3. **pizza-albums** - Album gallery widget
|
|
24
|
+
4. **pizza-list** - List view widget
|
|
25
|
+
5. **pizza-video** - Video player widget
|
|
26
|
+
|
|
27
|
+
Each widget demonstrates:
|
|
28
|
+
|
|
29
|
+
- External resource loading from OpenAI CDN
|
|
30
|
+
- Apps SDK metadata configuration
|
|
31
|
+
- Structured content injection
|
|
32
|
+
- Tool invocation status messages
|
|
33
|
+
|
|
34
|
+
## š Getting Started
|
|
35
|
+
|
|
36
|
+
### Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Install dependencies
|
|
40
|
+
npm install
|
|
41
|
+
|
|
42
|
+
# Start development server with hot reloading
|
|
43
|
+
npm run dev
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This will start:
|
|
47
|
+
|
|
48
|
+
- MCP server on port 8000
|
|
49
|
+
- Inspector UI at `/inspector`
|
|
50
|
+
- SSE endpoint at `/mcp`
|
|
51
|
+
|
|
52
|
+
### Production
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Build the server
|
|
56
|
+
npm run build
|
|
57
|
+
|
|
58
|
+
# Run the built server
|
|
59
|
+
npm start
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## š Usage
|
|
63
|
+
|
|
64
|
+
### Via MCP Client
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createMCPClient } from 'mcp-use/client'
|
|
68
|
+
|
|
69
|
+
const client = createMCPClient({
|
|
70
|
+
serverUrl: 'http://localhost:8000/mcp',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Call a pizzaz widget tool
|
|
74
|
+
const result = await client.callTool('ui_pizza-map', {
|
|
75
|
+
pizzaTopping: 'pepperoni',
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Access widget template as resource
|
|
79
|
+
const resource = await client.readResource('ui://widget/pizza-map.html')
|
|
80
|
+
|
|
81
|
+
// List all available widgets
|
|
82
|
+
const widgetList = await client.callTool('list-widgets', {})
|
|
83
|
+
|
|
84
|
+
// Get info about a specific widget
|
|
85
|
+
const widgetInfo = await client.callTool('get-widget-info', {
|
|
86
|
+
widgetId: 'pizza-carousel',
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Via Inspector UI
|
|
91
|
+
|
|
92
|
+
1. Start the server: `npm run dev`
|
|
93
|
+
2. Open: `http://localhost:8000/inspector`
|
|
94
|
+
3. Test tools and resources interactively
|
|
95
|
+
|
|
96
|
+
### Direct HTTP Access
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# SSE connection
|
|
100
|
+
curl -N http://localhost:8000/mcp
|
|
101
|
+
|
|
102
|
+
# Post message (requires sessionId)
|
|
103
|
+
curl -X POST http://localhost:8000/mcp/messages?sessionId=<session-id> \
|
|
104
|
+
-H "Content-Type: application/json" \
|
|
105
|
+
-d '{"method": "tools/list"}'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## šÆ How It Works
|
|
109
|
+
|
|
110
|
+
### Apps SDK Integration
|
|
111
|
+
|
|
112
|
+
The server uses `mcp-use`'s `AppsSdkUIResource` type to create Apps SDK compatible widgets:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import type { AppsSdkUIResource } from 'mcp-use/server'
|
|
116
|
+
|
|
117
|
+
const widget: AppsSdkUIResource = {
|
|
118
|
+
type: 'appsSdk',
|
|
119
|
+
name: 'pizza-map',
|
|
120
|
+
title: 'Show Pizza Map',
|
|
121
|
+
description: 'Interactive map widget',
|
|
122
|
+
htmlTemplate: `
|
|
123
|
+
<div id="pizzaz-root"></div>
|
|
124
|
+
<link rel="stylesheet" href="https://persistent.oaistatic.com/...">
|
|
125
|
+
<script type="module" src="https://persistent.oaistatic.com/..."></script>
|
|
126
|
+
`,
|
|
127
|
+
props: {
|
|
128
|
+
pizzaTopping: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: 'Topping to mention',
|
|
131
|
+
required: true,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
appsSdkMetadata: {
|
|
135
|
+
'openai/widgetDescription': 'Interactive map widget',
|
|
136
|
+
'openai/toolInvocation/invoking': 'Hand-tossing a map',
|
|
137
|
+
'openai/toolInvocation/invoked': 'Served a fresh map',
|
|
138
|
+
'openai/widgetAccessible': true,
|
|
139
|
+
'openai/widgetCSP': {
|
|
140
|
+
connect_domains: [],
|
|
141
|
+
resource_domains: ['https://persistent.oaistatic.com'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
server.uiResource(widget)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This automatically:
|
|
150
|
+
|
|
151
|
+
1. Creates a tool (`ui_pizza-map`)
|
|
152
|
+
2. Creates a resource (`ui://widget/pizza-map.html`)
|
|
153
|
+
3. Sets MIME type to `text/html+skybridge`
|
|
154
|
+
4. Injects Apps SDK metadata
|
|
155
|
+
5. Handles structured content injection
|
|
156
|
+
|
|
157
|
+
### Widget Registration
|
|
158
|
+
|
|
159
|
+
Widgets are defined in `src/widgets.ts` and registered in `src/server.ts`:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { getPizzazUIResources } from './widgets.js'
|
|
163
|
+
|
|
164
|
+
const pizzazWidgets = getPizzazUIResources()
|
|
165
|
+
|
|
166
|
+
pizzazWidgets.forEach((widget) => {
|
|
167
|
+
server.uiResource(widget)
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Structured Content
|
|
172
|
+
|
|
173
|
+
When a tool is called, the `structuredContent` is automatically injected as `window.openai.toolOutput`:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// In your tool handler
|
|
177
|
+
return {
|
|
178
|
+
content: [
|
|
179
|
+
{
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: 'Rendered a pizza map!',
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
structuredContent: {
|
|
185
|
+
pizzaTopping: params.pizzaTopping,
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Widget can access it via:
|
|
190
|
+
// window.openai.toolOutput.pizzaTopping
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## š Apps SDK Metadata
|
|
194
|
+
|
|
195
|
+
Each widget includes rich Apps SDK metadata:
|
|
196
|
+
|
|
197
|
+
### Widget Description
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
'openai/widgetDescription': 'Interactive map widget for displaying pizza locations'
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Tool Invocation Status
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
'openai/toolInvocation/invoking': 'Hand-tossing a map'
|
|
207
|
+
'openai/toolInvocation/invoked': 'Served a fresh map'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Content Security Policy
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
'openai/widgetCSP': {
|
|
214
|
+
connect_domains: [], // Domains widget can connect to
|
|
215
|
+
resource_domains: ['https://persistent.oaistatic.com'] // CDN domains
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Accessibility
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
'openai/widgetAccessible': true
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Output Template
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
'openai/outputTemplate': 'ui://widget/pizza-map.html'
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## š§ Configuration
|
|
232
|
+
|
|
233
|
+
### Port Configuration
|
|
234
|
+
|
|
235
|
+
Set the port via environment variable:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
PORT=3000 npm start
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Default port is `8000`.
|
|
242
|
+
|
|
243
|
+
### Widget Customization
|
|
244
|
+
|
|
245
|
+
To add or modify widgets, edit `src/widgets.ts`:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
export const pizzazWidgets: PizzazWidgetDefinition[] = [
|
|
249
|
+
{
|
|
250
|
+
id: 'my-widget',
|
|
251
|
+
title: 'My Custom Widget',
|
|
252
|
+
description: 'A custom widget',
|
|
253
|
+
templateUri: 'ui://widget/my-widget.html',
|
|
254
|
+
invoking: 'Loading widget...',
|
|
255
|
+
invoked: 'Widget ready!',
|
|
256
|
+
html: `
|
|
257
|
+
<div id="widget-root"></div>
|
|
258
|
+
<script>
|
|
259
|
+
// Your widget code
|
|
260
|
+
</script>
|
|
261
|
+
`,
|
|
262
|
+
responseText: 'Widget rendered!',
|
|
263
|
+
},
|
|
264
|
+
// ... other widgets
|
|
265
|
+
]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## šØ Widget Structure
|
|
269
|
+
|
|
270
|
+
Each pizzaz widget follows this structure:
|
|
271
|
+
|
|
272
|
+
```html
|
|
273
|
+
<!-- Container div with specific ID -->
|
|
274
|
+
<div id="pizzaz-root"></div>
|
|
275
|
+
|
|
276
|
+
<!-- External stylesheet -->
|
|
277
|
+
<link rel="stylesheet" href="https://persistent.oaistatic.com/..." />
|
|
278
|
+
|
|
279
|
+
<!-- External script (type="module") -->
|
|
280
|
+
<script type="module" src="https://persistent.oaistatic.com/..."></script>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The external scripts:
|
|
284
|
+
|
|
285
|
+
- Render interactive components into the container
|
|
286
|
+
- Access structured content via `window.openai.toolOutput`
|
|
287
|
+
- Handle user interactions
|
|
288
|
+
- Communicate with parent via postMessage
|
|
289
|
+
|
|
290
|
+
## š ļø Available Tools
|
|
291
|
+
|
|
292
|
+
### Widget Tools
|
|
293
|
+
|
|
294
|
+
Each pizzaz widget creates a tool:
|
|
295
|
+
|
|
296
|
+
- `ui_pizza-map` - Display interactive map
|
|
297
|
+
- `ui_pizza-carousel` - Browse in carousel format
|
|
298
|
+
- `ui_pizza-albums` - Show album gallery
|
|
299
|
+
- `ui_pizza-list` - Display list view
|
|
300
|
+
- `ui_pizza-video` - Play video content
|
|
301
|
+
|
|
302
|
+
All accept a `pizzaTopping` parameter:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
await client.callTool('ui_pizza-map', {
|
|
306
|
+
pizzaTopping: 'pepperoni',
|
|
307
|
+
})
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Helper Tools
|
|
311
|
+
|
|
312
|
+
- `list-widgets` - Get list of all available widgets
|
|
313
|
+
- `get-widget-info` - Get detailed info about a specific widget
|
|
314
|
+
|
|
315
|
+
## š¦ Available Resources
|
|
316
|
+
|
|
317
|
+
Each widget template is available as a resource:
|
|
318
|
+
|
|
319
|
+
- `ui://widget/pizza-map.html`
|
|
320
|
+
- `ui://widget/pizza-carousel.html`
|
|
321
|
+
- `ui://widget/pizza-albums.html`
|
|
322
|
+
- `ui://widget/pizza-list.html`
|
|
323
|
+
- `ui://widget/pizza-video.html`
|
|
324
|
+
|
|
325
|
+
Plus:
|
|
326
|
+
|
|
327
|
+
- `config://server` - Server configuration (JSON)
|
|
328
|
+
|
|
329
|
+
## š Testing
|
|
330
|
+
|
|
331
|
+
### Test with Inspector
|
|
332
|
+
|
|
333
|
+
1. Start server: `npm run dev`
|
|
334
|
+
2. Open inspector: `http://localhost:8000/inspector`
|
|
335
|
+
3. Click on any widget tool
|
|
336
|
+
4. Enter a pizza topping
|
|
337
|
+
5. Execute and view the result
|
|
338
|
+
|
|
339
|
+
### Test with MCP Client
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import { createMCPClient } from 'mcp-use/client'
|
|
343
|
+
|
|
344
|
+
const client = createMCPClient({
|
|
345
|
+
serverUrl: 'http://localhost:8000/mcp',
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
// Test listing tools
|
|
349
|
+
const tools = await client.listTools()
|
|
350
|
+
console.log('Available tools:', tools)
|
|
351
|
+
|
|
352
|
+
// Test calling a widget
|
|
353
|
+
const result = await client.callTool('ui_pizza-map', {
|
|
354
|
+
pizzaTopping: 'mushroom',
|
|
355
|
+
})
|
|
356
|
+
console.log('Result:', result)
|
|
357
|
+
|
|
358
|
+
// Test reading resource
|
|
359
|
+
const resource = await client.readResource('ui://widget/pizza-map.html')
|
|
360
|
+
console.log('Resource:', resource)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## š Project Structure
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
apps_sdk/
|
|
367
|
+
āāā index.ts # Entry point
|
|
368
|
+
āāā package.json # Dependencies
|
|
369
|
+
āāā tsconfig.json # TypeScript config
|
|
370
|
+
āāā README.md # This file
|
|
371
|
+
āāā src/
|
|
372
|
+
āāā server.ts # Main server implementation
|
|
373
|
+
āāā widgets.ts # Pizzaz widget definitions
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## š Related Documentation
|
|
377
|
+
|
|
378
|
+
- [MCP Documentation](https://modelcontextprotocol.io)
|
|
379
|
+
- [MCP-UI Apps SDK Guide](https://mcpui.dev/guide/apps-sdk)
|
|
380
|
+
- [mcp-use Documentation](https://github.com/pyroprompt/mcp-use)
|
|
381
|
+
- [OpenAI Apps SDK](https://platform.openai.com/docs/guides/apps)
|
|
382
|
+
|
|
383
|
+
## š¤ Contributing
|
|
384
|
+
|
|
385
|
+
This is a reference implementation demonstrating Apps SDK integration patterns. Feel free to:
|
|
386
|
+
|
|
387
|
+
- Add new widget types
|
|
388
|
+
- Customize existing widgets
|
|
389
|
+
- Extend Apps SDK metadata
|
|
390
|
+
- Add additional tools and resources
|
|
391
|
+
|
|
392
|
+
## š License
|
|
393
|
+
|
|
394
|
+
MIT
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
Built with ā¤ļø using [mcp-use](https://github.com/pyroprompt/mcp-use) and [OpenAI Apps SDK](https://platform.openai.com/docs/guides/apps)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Apps SDK Server Entry Point
|
|
3
|
+
*
|
|
4
|
+
* This file serves as the main entry point for the MCP server with Apps SDK support.
|
|
5
|
+
* It re-exports all functionality from the server implementation, allowing
|
|
6
|
+
* the CLI and other tools to locate and start the server.
|
|
7
|
+
*
|
|
8
|
+
* The server demonstrates OpenAI Apps SDK integration using mcp-use's uiResource method.
|
|
9
|
+
*/
|
|
10
|
+
export * from './src/server.js'
|
|
11
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-apps-sdk-server",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "MCP server with OpenAI Apps SDK integration using mcp-use",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"server",
|
|
11
|
+
"apps-sdk",
|
|
12
|
+
"openai",
|
|
13
|
+
"chatgpt",
|
|
14
|
+
"widgets",
|
|
15
|
+
"pizzaz",
|
|
16
|
+
"ai",
|
|
17
|
+
"tools"
|
|
18
|
+
],
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "mcp-use build",
|
|
22
|
+
"dev": "mcp-use dev",
|
|
23
|
+
"start": "mcp-use start"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@mcp-ui/server": "^5.11.0",
|
|
27
|
+
"cors": "^2.8.5",
|
|
28
|
+
"express": "^4.18.0",
|
|
29
|
+
"mcp-use": "workspace:*",
|
|
30
|
+
"zod": "^3.23.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@mcp-use/cli": "workspace:*",
|
|
34
|
+
"@mcp-use/inspector": "workspace:*",
|
|
35
|
+
"@types/cors": "^2.8.0",
|
|
36
|
+
"@types/express": "^4.17.0",
|
|
37
|
+
"@types/node": "^20.0.0",
|
|
38
|
+
"tsx": "^4.0.0",
|
|
39
|
+
"typescript": "^5.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { createMCPServer } from 'mcp-use/server'
|
|
2
|
+
import { getPizzazUIResources, getPizzazWidgetsSummary } from './widgets.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
6
|
+
* Pizzaz MCP Server - OpenAI Apps SDK Reference Implementation
|
|
7
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
8
|
+
*
|
|
9
|
+
* This server demonstrates OpenAI Apps SDK integration using mcp-use's
|
|
10
|
+
* uiResource method. It implements the pizzaz reference widgets that
|
|
11
|
+
* showcase best practices for Apps SDK widgets.
|
|
12
|
+
*
|
|
13
|
+
* Key Features:
|
|
14
|
+
* - Apps SDK metadata (CSP, tool invocation status, widget description)
|
|
15
|
+
* - External resource loading (OpenAI CDN assets)
|
|
16
|
+
* - Structured content injection via window.openai.toolOutput
|
|
17
|
+
* - text/html+skybridge MIME type for Apps SDK compatibility
|
|
18
|
+
* - Automatic tool and resource registration
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// Create the MCP server
|
|
22
|
+
const server = createMCPServer('pizzaz-node', {
|
|
23
|
+
version: '0.1.0',
|
|
24
|
+
description: 'OpenAI Apps SDK reference implementation with pizzaz widgets',
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const PORT = process.env.PORT || 8000
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
31
|
+
* Register Pizzaz Widgets
|
|
32
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
33
|
+
*
|
|
34
|
+
* Using mcp-use's uiResource method with AppsSdkUIResource type:
|
|
35
|
+
*
|
|
36
|
+
* This automatically:
|
|
37
|
+
* 1. Creates tools (ui_pizza-map, ui_pizza-carousel, etc.)
|
|
38
|
+
* 2. Creates resources (ui://widget/pizza-map.html, etc.)
|
|
39
|
+
* 3. Sets MIME type to text/html+skybridge
|
|
40
|
+
* 4. Injects Apps SDK metadata
|
|
41
|
+
* 5. Handles structuredContent injection
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
const pizzazWidgets = getPizzazUIResources()
|
|
45
|
+
|
|
46
|
+
pizzazWidgets.forEach(widget => {
|
|
47
|
+
server.uiResource(widget)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
52
|
+
* Helper Tools
|
|
53
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
54
|
+
*
|
|
55
|
+
* Additional tools for discovering and testing widgets
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
server.tool({
|
|
59
|
+
name: 'list-widgets',
|
|
60
|
+
title: 'List Available Widgets',
|
|
61
|
+
description: 'Get a list of all available pizzaz widgets',
|
|
62
|
+
cb: async () => {
|
|
63
|
+
const widgets = getPizzazWidgetsSummary()
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
content: [{
|
|
67
|
+
type: 'text',
|
|
68
|
+
text: `Available Pizzaz Widgets (${widgets.length} total):\n\n${widgets.map(w =>
|
|
69
|
+
`š ${w.title}\n` +
|
|
70
|
+
` ID: ${w.id}\n` +
|
|
71
|
+
` Tool: ${w.tool}\n` +
|
|
72
|
+
` Resource: ${w.resource}\n` +
|
|
73
|
+
` Description: ${w.description}\n`
|
|
74
|
+
).join('\n')}\n` +
|
|
75
|
+
`\nUsage:\n` +
|
|
76
|
+
`await client.callTool('ui_${widgets[0].id}', { pizzaTopping: 'pepperoni' })\n` +
|
|
77
|
+
`await client.readResource('${widgets[0].resource}')`
|
|
78
|
+
}]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
server.tool({
|
|
84
|
+
name: 'get-widget-info',
|
|
85
|
+
title: 'Get Widget Information',
|
|
86
|
+
description: 'Get detailed information about a specific widget',
|
|
87
|
+
inputs: [{
|
|
88
|
+
name: 'widgetId',
|
|
89
|
+
type: 'string',
|
|
90
|
+
description: 'Widget ID (e.g., pizza-map, pizza-carousel)',
|
|
91
|
+
required: true
|
|
92
|
+
}],
|
|
93
|
+
cb: async (params) => {
|
|
94
|
+
const widgets = getPizzazWidgetsSummary()
|
|
95
|
+
const widget = widgets.find(w => w.id === params.widgetId)
|
|
96
|
+
|
|
97
|
+
if (!widget) {
|
|
98
|
+
return {
|
|
99
|
+
content: [{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: `Widget '${params.widgetId}' not found. Available widgets: ${widgets.map(w => w.id).join(', ')}`
|
|
102
|
+
}]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
content: [{
|
|
108
|
+
type: 'text',
|
|
109
|
+
text: `Widget Information:\n\n` +
|
|
110
|
+
`ID: ${widget.id}\n` +
|
|
111
|
+
`Title: ${widget.title}\n` +
|
|
112
|
+
`Description: ${widget.description}\n` +
|
|
113
|
+
`Tool Name: ${widget.tool}\n` +
|
|
114
|
+
`Resource URI: ${widget.resource}\n` +
|
|
115
|
+
`Response Text: ${widget.responseText}\n\n` +
|
|
116
|
+
`Usage:\n` +
|
|
117
|
+
`await client.callTool('${widget.tool}', { pizzaTopping: 'mushroom' })\n` +
|
|
118
|
+
`await client.readResource('${widget.resource}')`
|
|
119
|
+
}]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
126
|
+
* Server Configuration Resource
|
|
127
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
server.resource({
|
|
131
|
+
name: 'server-config',
|
|
132
|
+
uri: 'config://server',
|
|
133
|
+
title: 'Server Configuration',
|
|
134
|
+
description: 'Current server configuration and capabilities',
|
|
135
|
+
mimeType: 'application/json',
|
|
136
|
+
readCallback: async () => ({
|
|
137
|
+
contents: [{
|
|
138
|
+
uri: 'config://server',
|
|
139
|
+
mimeType: 'application/json',
|
|
140
|
+
text: JSON.stringify({
|
|
141
|
+
name: 'pizzaz-node',
|
|
142
|
+
version: '0.1.0',
|
|
143
|
+
port: PORT,
|
|
144
|
+
widgets: {
|
|
145
|
+
total: pizzazWidgets.length,
|
|
146
|
+
ids: pizzazWidgets.map(w => w.name)
|
|
147
|
+
},
|
|
148
|
+
endpoints: {
|
|
149
|
+
mcp: `http://localhost:${PORT}/mcp`,
|
|
150
|
+
inspector: `http://localhost:${PORT}/inspector`,
|
|
151
|
+
},
|
|
152
|
+
features: {
|
|
153
|
+
appsSdk: true,
|
|
154
|
+
externalResources: true,
|
|
155
|
+
structuredContent: true,
|
|
156
|
+
pizzazWidgets: true
|
|
157
|
+
},
|
|
158
|
+
appsSdk: {
|
|
159
|
+
mimeType: 'text/html+skybridge',
|
|
160
|
+
metadata: [
|
|
161
|
+
'openai/widgetDescription',
|
|
162
|
+
'openai/widgetCSP',
|
|
163
|
+
'openai/widgetAccessible',
|
|
164
|
+
'openai/outputTemplate',
|
|
165
|
+
'openai/toolInvocation/invoking',
|
|
166
|
+
'openai/toolInvocation/invoked',
|
|
167
|
+
'openai/resultCanProduceWidget'
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
}, null, 2)
|
|
171
|
+
}]
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
177
|
+
* Start the Server
|
|
178
|
+
* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
server.listen(PORT)
|
|
182
|
+
|
|
183
|
+
// Display helpful startup message
|
|
184
|
+
console.log(`
|
|
185
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
186
|
+
ā š Pizzaz MCP Server - Apps SDK Reference ā
|
|
187
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
188
|
+
|
|
189
|
+
Server is running on port ${PORT}
|
|
190
|
+
|
|
191
|
+
š Endpoints:
|
|
192
|
+
MCP Protocol: http://localhost:${PORT}/mcp
|
|
193
|
+
Inspector UI: http://localhost:${PORT}/inspector
|
|
194
|
+
|
|
195
|
+
š Available Pizzaz Widgets (${pizzazWidgets.length} total):
|
|
196
|
+
|
|
197
|
+
${pizzazWidgets.map((w, i) => ` ${i + 1}. ${w.name}
|
|
198
|
+
Tool: ui_${w.name}
|
|
199
|
+
Resource: ${w.appsSdkMetadata?.['openai/outputTemplate'] || 'N/A'}
|
|
200
|
+
`).join('\n')}
|
|
201
|
+
|
|
202
|
+
š Usage Examples:
|
|
203
|
+
|
|
204
|
+
// Call a widget tool with parameters
|
|
205
|
+
await client.callTool('ui_pizza-map', {
|
|
206
|
+
pizzaTopping: 'pepperoni'
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// Access widget template as resource
|
|
210
|
+
await client.readResource('ui://widget/pizza-map.html')
|
|
211
|
+
|
|
212
|
+
// List all widgets
|
|
213
|
+
await client.callTool('list-widgets', {})
|
|
214
|
+
|
|
215
|
+
// Get widget info
|
|
216
|
+
await client.callTool('get-widget-info', {
|
|
217
|
+
widgetId: 'pizza-map'
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
š§ Apps SDK Features:
|
|
221
|
+
ā text/html+skybridge MIME type
|
|
222
|
+
ā External resource loading (OpenAI CDN)
|
|
223
|
+
ā Structured content injection
|
|
224
|
+
ā Tool invocation status messages
|
|
225
|
+
ā Content Security Policy (CSP)
|
|
226
|
+
ā Widget accessibility metadata
|
|
227
|
+
|
|
228
|
+
š” Tip: Open the Inspector UI to test all widgets interactively!
|
|
229
|
+
šØ These widgets demonstrate OpenAI's Apps SDK best practices.
|
|
230
|
+
`)
|
|
231
|
+
|
|
232
|
+
// Handle graceful shutdown
|
|
233
|
+
process.on('SIGINT', () => {
|
|
234
|
+
console.log('\n\nš Shutting down pizzaz server...')
|
|
235
|
+
process.exit(0)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
export default server
|
|
239
|
+
|