create-mcp-use-app 0.4.5 → 0.4.6-canary.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 +2 -2
- package/dist/templates/apps-sdk/index.ts +38 -0
- package/dist/templates/apps-sdk/package.json +41 -0
- package/dist/templates/apps-sdk/resources/display-weather.tsx +89 -0
- package/dist/templates/apps-sdk/styles.css +12 -0
- package/dist/templates/{ui-resource → apps-sdk}/tsconfig.json +7 -2
- package/dist/templates/{ui-resource → mcp-ui}/README.md +3 -3
- package/dist/templates/{ui-resource/src/server.ts → mcp-ui/index.ts} +15 -41
- package/dist/templates/{ui-resource → mcp-ui}/package.json +7 -16
- package/dist/templates/{ui-resource → mcp-ui}/resources/kanban-board.tsx +1 -7
- package/dist/templates/{apps-sdk-demo → mcp-ui}/tsconfig.json +7 -2
- package/dist/templates/starter/index.ts +96 -7
- package/dist/templates/starter/package.json +7 -16
- package/dist/templates/starter/resources/display-weather.tsx +89 -0
- package/dist/templates/starter/resources/kanban-board.tsx +1 -7
- package/dist/templates/starter/styles.css +12 -0
- package/dist/templates/starter/tsconfig.json +6 -2
- package/package.json +3 -4
- package/dist/templates/apps-sdk-demo/README.md +0 -398
- package/dist/templates/apps-sdk-demo/index.ts +0 -11
- package/dist/templates/apps-sdk-demo/package.json +0 -42
- package/dist/templates/apps-sdk-demo/src/server.ts +0 -239
- package/dist/templates/apps-sdk-demo/src/widgets.ts +0 -153
- package/dist/templates/starter/src/remoteDom/index.ts +0 -93
- package/dist/templates/starter/src/server.ts +0 -195
- package/dist/templates/ui-resource/index.ts +0 -12
package/dist/index.js
CHANGED
|
@@ -351,8 +351,8 @@ async function copyTemplate(projectPath, template, versions, isDevelopment = fal
|
|
|
351
351
|
console.log("No templates directory found");
|
|
352
352
|
}
|
|
353
353
|
console.log('\u{1F4A1} Tip: Use "starter" template for a comprehensive MCP server with all features');
|
|
354
|
-
console.log('\u{1F4A1} Tip: Use "ui
|
|
355
|
-
console.log('\u{1F4A1} Tip: Use "apps-sdk
|
|
354
|
+
console.log('\u{1F4A1} Tip: Use "mcp-ui" template for a MCP server with mcp-ui resources');
|
|
355
|
+
console.log('\u{1F4A1} Tip: Use "apps-sdk" template for a MCP server with OpenAI Apps SDK integration');
|
|
356
356
|
process.exit(1);
|
|
357
357
|
}
|
|
358
358
|
copyDirectoryWithProcessing(templatePath, projectPath, versions, isDevelopment, useCanary);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createMCPServer } from 'mcp-use/server'
|
|
2
|
+
|
|
3
|
+
const server = createMCPServer('test-app', {
|
|
4
|
+
version: '1.0.0',
|
|
5
|
+
description: 'Test MCP server with automatic UI widget registration',
|
|
6
|
+
host: process.env.HOST || 'localhost',
|
|
7
|
+
baseUrl: process.env.MCP_URL, // Full base URL (e.g., https://myserver.com)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* AUTOMATIC UI WIDGET REGISTRATION
|
|
12
|
+
* All React components in the `resources/` folder are automatically registered as MCP tools and resources.
|
|
13
|
+
* Just export widgetMetadata with description and Zod schema, and mcp-use handles the rest!
|
|
14
|
+
*
|
|
15
|
+
* It will automatically add to your MCP server:
|
|
16
|
+
* - server.tool('display-weather')
|
|
17
|
+
* - server.resource('ui://widget/display-weather')
|
|
18
|
+
*
|
|
19
|
+
* See docs: https://docs.mcp-use.com/typescript/server/ui-widgets
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Add here yourtandard MCP tools, resources and prompts
|
|
25
|
+
*/
|
|
26
|
+
server.tool({
|
|
27
|
+
name: 'get-my-city',
|
|
28
|
+
description: 'Get my city',
|
|
29
|
+
cb: async () => {
|
|
30
|
+
return { content: [{ type: 'text', text: `My city is San Francisco` }] }
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000
|
|
36
|
+
const HOST = process.env.HOST || 'localhost'
|
|
37
|
+
server.listen(PORT)
|
|
38
|
+
console.log(`Server running at http://${HOST}:${PORT}`)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Weather App",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "MCP server with apps sdk integration",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"server",
|
|
11
|
+
"starter",
|
|
12
|
+
"tools",
|
|
13
|
+
"resources",
|
|
14
|
+
"prompts",
|
|
15
|
+
"uiresource",
|
|
16
|
+
"ui",
|
|
17
|
+
"react",
|
|
18
|
+
"widgets",
|
|
19
|
+
"mcp-ui",
|
|
20
|
+
"apps-sdk"
|
|
21
|
+
],
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "mcp-use build",
|
|
25
|
+
"dev": "mcp-use dev",
|
|
26
|
+
"start": "mcp-use start"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"cors": "^2.8.5",
|
|
30
|
+
"express": "^4.18.0",
|
|
31
|
+
"mcp-use": "workspace:*",
|
|
32
|
+
"react": "^19.2.0",
|
|
33
|
+
"react-dom": "^19.2.0",
|
|
34
|
+
"tailwindcss": "^4.0.0",
|
|
35
|
+
"zod": "^4.1.12"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "^19.2.2",
|
|
39
|
+
"@types/react-dom": "^19.2.2"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { useWidget } from 'mcp-use/react';
|
|
4
|
+
import '../styles.css';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Apps SDK widget
|
|
8
|
+
* Just export widgetMetadata with description and Zod schema, and mcp-use handles the rest!
|
|
9
|
+
* See docs: https://docs.mcp-use.com/typescript/server/ui-widgets
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const propSchema = z.object({
|
|
13
|
+
city: z.string().describe('The city to display weather for'),
|
|
14
|
+
weather: z.enum(['sunny', 'rain', 'snow', 'cloudy']).describe('The weather condition'),
|
|
15
|
+
temperature: z.number().min(-20).max(50).describe('The temperature in Celsius'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const widgetMetadata = {
|
|
19
|
+
description: 'Display weather for a city',
|
|
20
|
+
inputs: propSchema,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type WeatherProps = z.infer<typeof propSchema>;
|
|
24
|
+
|
|
25
|
+
const WeatherWidget: React.FC = () => {
|
|
26
|
+
// Use the useWidget hook to get props from OpenAI Apps SDK
|
|
27
|
+
const { props, theme, sendFollowUpMessage, callTool, requestDisplayMode } = useWidget<WeatherProps>();
|
|
28
|
+
|
|
29
|
+
console.log(props)
|
|
30
|
+
|
|
31
|
+
const { city, weather, temperature } = props;
|
|
32
|
+
const getWeatherIcon = (weatherType: string) => {
|
|
33
|
+
switch (weatherType?.toLowerCase()) {
|
|
34
|
+
case 'sunny':
|
|
35
|
+
return '☀️';
|
|
36
|
+
case 'rain':
|
|
37
|
+
return '🌧️';
|
|
38
|
+
case 'snow':
|
|
39
|
+
return '❄️';
|
|
40
|
+
case 'cloudy':
|
|
41
|
+
return '☁️';
|
|
42
|
+
default:
|
|
43
|
+
return '🌤️';
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getWeatherColor = (weatherType: string) => {
|
|
48
|
+
switch (weatherType?.toLowerCase()) {
|
|
49
|
+
case 'sunny':
|
|
50
|
+
return 'from-yellow-400 to-orange-500';
|
|
51
|
+
case 'rain':
|
|
52
|
+
return 'from-blue-400 to-blue-600';
|
|
53
|
+
case 'snow':
|
|
54
|
+
return 'from-blue-100 to-blue-300';
|
|
55
|
+
case 'cloudy':
|
|
56
|
+
return 'from-gray-400 to-gray-600';
|
|
57
|
+
default:
|
|
58
|
+
return 'from-gray-300 to-gray-500';
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Theme-aware styling
|
|
63
|
+
const bgColor = theme === 'dark' ? 'bg-gray-900' : 'bg-white';
|
|
64
|
+
const textColor = theme === 'dark' ? 'text-gray-100' : 'text-gray-800';
|
|
65
|
+
const subtextColor = theme === 'dark' ? 'text-gray-400' : 'text-gray-600';
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<div className={`max-w-sm mx-auto ${bgColor} rounded-xl shadow-lg overflow-hidden`}>
|
|
69
|
+
<div className={`h-32 bg-gradient-to-br ${getWeatherColor(weather)} flex items-center justify-center`}>
|
|
70
|
+
<div className="text-6xl">{getWeatherIcon(weather)}</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div className="p-6">
|
|
74
|
+
<div className="text-center">
|
|
75
|
+
<h2 className={`text-2xl font-bold ${textColor} mb-2`}>{city}</h2>
|
|
76
|
+
<div className="flex items-center justify-center space-x-4">
|
|
77
|
+
<span className={`text-4xl font-light ${textColor}`}>{temperature}°</span>
|
|
78
|
+
<div className="text-right">
|
|
79
|
+
<p className={`text-lg font-medium ${subtextColor} capitalize`}>{weather}</p>
|
|
80
|
+
<p className={`text-sm ${subtextColor}`}>Current</p>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default WeatherWidget;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Custom styles */
|
|
4
|
+
body {
|
|
5
|
+
margin: 0;
|
|
6
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
7
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
8
|
+
sans-serif;
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
-moz-osx-font-smoothing: grayscale;
|
|
11
|
+
}
|
|
12
|
+
|
|
@@ -13,8 +13,13 @@
|
|
|
13
13
|
"allowSyntheticDefaultImports": true,
|
|
14
14
|
"esModuleInterop": true,
|
|
15
15
|
"forceConsistentCasingInFileNames": true,
|
|
16
|
-
"skipLibCheck": true
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"baseUrl": ".",
|
|
18
|
+
"paths": {
|
|
19
|
+
"@/*": ["src/*"]
|
|
20
|
+
}
|
|
17
21
|
},
|
|
18
|
-
"include": ["index.ts", "src/**/*", "resources/**/*"],
|
|
22
|
+
"include": ["index.ts", "src/**/*", "resources/**/*", "server.ts"],
|
|
19
23
|
"exclude": ["node_modules", "dist"]
|
|
20
24
|
}
|
|
25
|
+
|
|
@@ -38,7 +38,7 @@ server.uiResource({
|
|
|
38
38
|
|
|
39
39
|
This automatically creates:
|
|
40
40
|
|
|
41
|
-
- **Tool**: `
|
|
41
|
+
- **Tool**: `kanban-board` - Accepts parameters and returns UIResource
|
|
42
42
|
- **Resource**: `ui://widget/kanban-board` - Static access with defaults
|
|
43
43
|
|
|
44
44
|
## Getting Started
|
|
@@ -205,7 +205,7 @@ server.uiResource({
|
|
|
205
205
|
|
|
206
206
|
When you call `uiResource`, it automatically creates a tool:
|
|
207
207
|
|
|
208
|
-
- Name: `
|
|
208
|
+
- Name: `[widget-name]`
|
|
209
209
|
- Accepts all props as parameters
|
|
210
210
|
- Returns both text description and UIResource object
|
|
211
211
|
|
|
@@ -323,7 +323,7 @@ Visit: `http://localhost:3000/mcp-use/widgets/[widget-name]`
|
|
|
323
323
|
|
|
324
324
|
```typescript
|
|
325
325
|
// Call as tool
|
|
326
|
-
const result = await client.callTool('
|
|
326
|
+
const result = await client.callTool('kanban-board', {
|
|
327
327
|
initialTasks: [...],
|
|
328
328
|
theme: 'dark'
|
|
329
329
|
})
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
RemoteDomUIResource
|
|
6
6
|
} from 'mcp-use/server'
|
|
7
7
|
|
|
8
|
-
// Create an MCP server with UIResource support
|
|
8
|
+
// Create an MCP server with MCP-UI UIResource support
|
|
9
9
|
const server = createMCPServer('uiresource-mcp-server', {
|
|
10
10
|
version: '1.0.0',
|
|
11
11
|
description: 'MCP server demonstrating all UIResource types',
|
|
@@ -15,42 +15,18 @@ const PORT = process.env.PORT || 3000
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* ════════════════════════════════════════════════════════════════════
|
|
18
|
-
* Type 1: External URL (Iframe Widget)
|
|
18
|
+
* Type 1: External URL (Iframe Widget from `resources/`)
|
|
19
19
|
* ════════════════════════════════════════════════════════════════════
|
|
20
20
|
*
|
|
21
21
|
* Serves a widget from your local filesystem via iframe.
|
|
22
|
-
*
|
|
22
|
+
* All React components in the `resources/` folder are automatically registered as MCP tools and resources.
|
|
23
23
|
*
|
|
24
24
|
* This automatically:
|
|
25
|
-
* 1. Creates a tool (
|
|
25
|
+
* 1. Creates a tool (kanban-board) that accepts parameters
|
|
26
26
|
* 2. Creates a resource (ui://widget/kanban-board) for static access
|
|
27
27
|
* 3. Serves the widget from dist/resources/mcp-use/widgets/kanban-board/
|
|
28
28
|
*/
|
|
29
|
-
|
|
30
|
-
type: 'externalUrl',
|
|
31
|
-
name: 'kanban-board',
|
|
32
|
-
widget: 'kanban-board',
|
|
33
|
-
title: 'Kanban Board',
|
|
34
|
-
description: 'Interactive task management board with drag-and-drop support',
|
|
35
|
-
props: {
|
|
36
|
-
initialTasks: {
|
|
37
|
-
type: 'array',
|
|
38
|
-
description: 'Initial tasks to display on the board',
|
|
39
|
-
required: false,
|
|
40
|
-
},
|
|
41
|
-
theme: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
description: 'Visual theme for the board (light/dark)',
|
|
44
|
-
required: false,
|
|
45
|
-
default: 'light'
|
|
46
|
-
},
|
|
47
|
-
columns: {
|
|
48
|
-
type: 'array',
|
|
49
|
-
description: 'Column configuration for the board',
|
|
50
|
-
required: false,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
} satisfies ExternalUrlUIResource)
|
|
29
|
+
|
|
54
30
|
|
|
55
31
|
/**
|
|
56
32
|
* ════════════════════════════════════════════════════════════════════
|
|
@@ -58,10 +34,9 @@ server.uiResource({
|
|
|
58
34
|
* ════════════════════════════════════════════════════════════════════
|
|
59
35
|
*
|
|
60
36
|
* Renders HTML content directly without an iframe.
|
|
61
|
-
* Best for: Simple visualizations, status displays, formatted text
|
|
62
37
|
*
|
|
63
38
|
* This creates:
|
|
64
|
-
* - Tool:
|
|
39
|
+
* - Tool: welcome-card
|
|
65
40
|
* - Resource: ui://widget/welcome-card
|
|
66
41
|
*/
|
|
67
42
|
server.uiResource({
|
|
@@ -157,10 +132,9 @@ server.uiResource({
|
|
|
157
132
|
* ════════════════════════════════════════════════════════════════════
|
|
158
133
|
*
|
|
159
134
|
* Uses Remote DOM to render interactive components.
|
|
160
|
-
* Best for: Lightweight interactive UIs using MCP-UI React components
|
|
161
135
|
*
|
|
162
136
|
* This creates:
|
|
163
|
-
* - Tool:
|
|
137
|
+
* - Tool: quick-poll
|
|
164
138
|
* - Resource: ui://widget/quick-poll
|
|
165
139
|
*/
|
|
166
140
|
server.uiResource({
|
|
@@ -294,20 +268,20 @@ server.tool({
|
|
|
294
268
|
{
|
|
295
269
|
name: 'kanban-board',
|
|
296
270
|
type: 'externalUrl',
|
|
297
|
-
tool: '
|
|
271
|
+
tool: 'kanban-board',
|
|
298
272
|
resource: 'ui://widget/kanban-board',
|
|
299
273
|
url: `http://localhost:${PORT}/mcp-use/widgets/kanban-board`
|
|
300
274
|
},
|
|
301
275
|
{
|
|
302
276
|
name: 'welcome-card',
|
|
303
277
|
type: 'rawHtml',
|
|
304
|
-
tool: '
|
|
278
|
+
tool: 'welcome-card',
|
|
305
279
|
resource: 'ui://widget/welcome-card'
|
|
306
280
|
},
|
|
307
281
|
{
|
|
308
282
|
name: 'quick-poll',
|
|
309
283
|
type: 'remoteDom',
|
|
310
|
-
tool: '
|
|
284
|
+
tool: 'quick-poll',
|
|
311
285
|
resource: 'ui://widget/quick-poll'
|
|
312
286
|
}
|
|
313
287
|
]
|
|
@@ -382,24 +356,24 @@ Server is running on port ${PORT}
|
|
|
382
356
|
|
|
383
357
|
1️⃣ External URL Widget (Iframe)
|
|
384
358
|
• kanban-board
|
|
385
|
-
Tool:
|
|
359
|
+
Tool: kanban-board
|
|
386
360
|
Resource: ui://widget/kanban-board
|
|
387
361
|
Browser: http://localhost:${PORT}/mcp-use/widgets/kanban-board
|
|
388
362
|
|
|
389
363
|
2️⃣ Raw HTML Widget (Direct Rendering)
|
|
390
364
|
• welcome-card
|
|
391
|
-
Tool:
|
|
365
|
+
Tool: welcome-card
|
|
392
366
|
Resource: ui://widget/welcome-card
|
|
393
367
|
|
|
394
368
|
3️⃣ Remote DOM Widget (React Components)
|
|
395
369
|
• quick-poll
|
|
396
|
-
Tool:
|
|
370
|
+
Tool: quick-poll
|
|
397
371
|
Resource: ui://widget/quick-poll
|
|
398
372
|
|
|
399
373
|
📝 Usage Examples:
|
|
400
374
|
|
|
401
375
|
// External URL - Call with dynamic parameters
|
|
402
|
-
await client.callTool('
|
|
376
|
+
await client.callTool('kanban-board', {
|
|
403
377
|
initialTasks: [{id: 1, title: 'Task 1'}],
|
|
404
378
|
theme: 'dark'
|
|
405
379
|
})
|
|
@@ -408,7 +382,7 @@ Server is running on port ${PORT}
|
|
|
408
382
|
await client.readResource('ui://widget/welcome-card')
|
|
409
383
|
|
|
410
384
|
// Remote DOM - Interactive component
|
|
411
|
-
await client.callTool('
|
|
385
|
+
await client.callTool('quick-poll', {
|
|
412
386
|
question: 'Favorite color?',
|
|
413
387
|
options: ['Red', 'Blue', 'Green']
|
|
414
388
|
})
|
|
@@ -23,25 +23,16 @@
|
|
|
23
23
|
"start": "mcp-use start"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@mcp-ui/server": "^5.11.0",
|
|
27
26
|
"cors": "^2.8.5",
|
|
28
27
|
"express": "^4.18.0",
|
|
29
|
-
"mcp-use": "workspace:*"
|
|
28
|
+
"mcp-use": "workspace:*",
|
|
29
|
+
"react": "^19.2.0",
|
|
30
|
+
"react-dom": "^19.2.0",
|
|
31
|
+
"tailwindcss": "^4.0.0",
|
|
32
|
+
"zod": "^4.1.12"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"@types/cors": "^2.8.0",
|
|
35
|
-
"@types/express": "^4.17.0",
|
|
36
|
-
"@types/node": "^20.0.0",
|
|
37
|
-
"@types/react": "^18.0.0",
|
|
38
|
-
"@types/react-dom": "^18.0.0",
|
|
39
|
-
"concurrently": "^8.0.0",
|
|
40
|
-
"esbuild": "^0.23.0",
|
|
41
|
-
"globby": "^14.0.2",
|
|
42
|
-
"react": "^18.0.0",
|
|
43
|
-
"react-dom": "^18.0.0",
|
|
44
|
-
"tsx": "^4.0.0",
|
|
45
|
-
"typescript": "^5.0.0"
|
|
35
|
+
"@types/react": "^19.2.2",
|
|
36
|
+
"@types/react-dom": "^19.2.2"
|
|
46
37
|
}
|
|
47
38
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
|
-
import { createRoot } from 'react-dom/client'
|
|
3
2
|
|
|
4
3
|
interface Task {
|
|
5
4
|
id: string
|
|
@@ -298,9 +297,4 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({ initialTasks = [] }) => {
|
|
|
298
297
|
)
|
|
299
298
|
}
|
|
300
299
|
|
|
301
|
-
|
|
302
|
-
const container = document.getElementById('widget-root')
|
|
303
|
-
if (container) {
|
|
304
|
-
const root = createRoot(container)
|
|
305
|
-
root.render(<KanbanBoard />)
|
|
306
|
-
}
|
|
300
|
+
export default KanbanBoard
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
|
+
"jsx": "react-jsx",
|
|
4
5
|
"module": "ESNext",
|
|
5
6
|
"moduleResolution": "bundler",
|
|
6
7
|
"allowJs": true,
|
|
@@ -12,9 +13,13 @@
|
|
|
12
13
|
"allowSyntheticDefaultImports": true,
|
|
13
14
|
"esModuleInterop": true,
|
|
14
15
|
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"skipLibCheck": true
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"baseUrl": ".",
|
|
18
|
+
"paths": {
|
|
19
|
+
"@/*": ["src/*"]
|
|
20
|
+
}
|
|
16
21
|
},
|
|
17
|
-
"include": ["index.ts", "src/**/*"],
|
|
22
|
+
"include": ["index.ts", "src/**/*", "resources/**/*", "server.ts"],
|
|
18
23
|
"exclude": ["node_modules", "dist"]
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -1,12 +1,101 @@
|
|
|
1
|
+
import { createMCPServer } from 'mcp-use/server'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Create MCP server instance
|
|
5
|
+
const server = createMCPServer('my-mcp-server', {
|
|
6
|
+
version: '1.0.0',
|
|
7
|
+
description: 'My first MCP server with all features',
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
|
-
*
|
|
12
|
+
* Define UI Widgets
|
|
13
|
+
* All React components in the `resources/` folder
|
|
14
|
+
* are automatically registered as MCP tools and resources.
|
|
3
15
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the CLI and other tools to locate and start the server.
|
|
16
|
+
* Just export widgetMetadata with description and Zod schema,
|
|
17
|
+
* and mcp-use handles the rest!
|
|
7
18
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
19
|
+
* It will automatically add to your MCP server:
|
|
20
|
+
* - server.tool('kanban-board')
|
|
21
|
+
* - server.tool('display-weather')
|
|
22
|
+
* - server.resource('ui://widget/kanban-board')
|
|
23
|
+
* - server.resource('ui://widget/display-weather')
|
|
24
|
+
*
|
|
25
|
+
* Docs: https://docs.mcp-use.com/typescript/server/ui-widgets
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Define MCP tools
|
|
31
|
+
* Docs: https://docs.mcp-use.com/typescript/server/tools
|
|
32
|
+
*/
|
|
33
|
+
server.tool({
|
|
34
|
+
name: 'fetch-weather',
|
|
35
|
+
description: 'Fetch the weather for a city',
|
|
36
|
+
inputs: [
|
|
37
|
+
{ name: 'city', type: 'string', required: true }
|
|
38
|
+
],
|
|
39
|
+
cb: async (params: Record<string, any>) => {
|
|
40
|
+
const city = params.city as string
|
|
41
|
+
const response = await fetch(`https://wttr.in/${city}?format=j1`)
|
|
42
|
+
const data: any = await response.json()
|
|
43
|
+
const current = data.current_condition[0]
|
|
44
|
+
return {
|
|
45
|
+
content: [{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: `The weather in ${city} is ${current.weatherDesc[0].value}. Temperature: ${current.temp_C}°C, Humidity: ${current.humidity}%`
|
|
48
|
+
}]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* Define MCP resources
|
|
56
|
+
* Docs: https://docs.mcp-use.com/typescript/server/resources
|
|
10
57
|
*/
|
|
11
|
-
|
|
58
|
+
server.resource({
|
|
59
|
+
name: 'config',
|
|
60
|
+
uri: 'config://settings',
|
|
61
|
+
mimeType: 'application/json',
|
|
62
|
+
description: 'Server configuration',
|
|
63
|
+
readCallback: async () => ({
|
|
64
|
+
contents: [{
|
|
65
|
+
uri: 'config://settings',
|
|
66
|
+
mimeType: 'application/json',
|
|
67
|
+
text: JSON.stringify({
|
|
68
|
+
theme: 'dark',
|
|
69
|
+
language: 'en'
|
|
70
|
+
})
|
|
71
|
+
}]
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* Define MCP prompts
|
|
78
|
+
* Docs: https://docs.mcp-use.com/typescript/server/prompts
|
|
79
|
+
*/
|
|
80
|
+
server.prompt({
|
|
81
|
+
name: 'review-code',
|
|
82
|
+
description: 'Review code for best practices and potential issues',
|
|
83
|
+
args: [
|
|
84
|
+
{ name: 'code', type: 'string', required: true }
|
|
85
|
+
],
|
|
86
|
+
cb: async (params: Record<string, any>) => {
|
|
87
|
+
const { code } = params
|
|
88
|
+
return {
|
|
89
|
+
messages: [{
|
|
90
|
+
role: 'user',
|
|
91
|
+
content: {type: 'text', text: `Please review this code:\n\n${code}`}
|
|
92
|
+
}]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
12
97
|
|
|
98
|
+
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000
|
|
99
|
+
console.log(`Server running on port ${PORT}`)
|
|
100
|
+
// Start the server
|
|
101
|
+
server.listen(PORT)
|
|
@@ -26,25 +26,16 @@
|
|
|
26
26
|
"start": "mcp-use start"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@mcp-ui/server": "^5.11.0",
|
|
30
29
|
"cors": "^2.8.5",
|
|
31
30
|
"express": "^4.18.0",
|
|
32
|
-
"mcp-use": "workspace:*"
|
|
31
|
+
"mcp-use": "workspace:*",
|
|
32
|
+
"react": "^19.2.0",
|
|
33
|
+
"react-dom": "^19.2.0",
|
|
34
|
+
"tailwindcss": "^4.0.0",
|
|
35
|
+
"zod": "^4.1.12"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@types/cors": "^2.8.0",
|
|
38
|
-
"@types/express": "^4.17.0",
|
|
39
|
-
"@types/node": "^20.0.0",
|
|
40
|
-
"@types/react": "^18.0.0",
|
|
41
|
-
"@types/react-dom": "^18.0.0",
|
|
42
|
-
"concurrently": "^8.0.0",
|
|
43
|
-
"esbuild": "^0.23.0",
|
|
44
|
-
"globby": "^14.0.2",
|
|
45
|
-
"react": "^18.0.0",
|
|
46
|
-
"react-dom": "^18.0.0",
|
|
47
|
-
"tsx": "^4.0.0",
|
|
48
|
-
"typescript": "^5.0.0"
|
|
38
|
+
"@types/react": "^19.2.2",
|
|
39
|
+
"@types/react-dom": "^19.2.2"
|
|
49
40
|
}
|
|
50
41
|
}
|