1- import { existsSync , readdirSync } from 'node:fs'
2- import { join } from 'node:path'
3- import cors from 'cors'
4- import express from 'express'
51import { createMCPServer } from 'mcp-use'
62
7- // Create an MCP server with UI support
8- const mcp = createMCPServer ( 'ui-mcp-server' , {
3+ // Create an MCP server (which is also an Express app)
4+ const server = createMCPServer ( 'ui-mcp-server' , {
95 version : '1.0.0' ,
106 description : 'An MCP server with React UI widgets' ,
117} )
128
13- // Express server for serving UI resources
14- const app = express ( )
15- app . use ( cors ( ) )
16- app . use ( express . json ( ) )
17-
18- // Serve UI widgets using file-based routing
19- // Serve static assets (JS, CSS) from the assets directory
20- app . get ( '/mcp-use/widgets/:widget/assets/*' , ( req , res , next ) => {
21- const widget = req . params . widget
22- const assetFile = ( req . params as any ) [ 0 ]
23- const assetPath = join ( process . cwd ( ) , 'dist' , 'resources' , 'mcp-use' , 'widgets' , widget , 'assets' , assetFile )
24- res . sendFile ( assetPath , err => ( err ? next ( ) : undefined ) )
25- } )
26-
27- // Handle assets served from the wrong path (browser resolves ./assets/ relative to /mcp-use/widgets/)
28- app . get ( '/mcp-use/widgets/assets/*' , ( req , res , next ) => {
29- const assetFile = ( req . params as any ) [ 0 ]
30- // Try to find which widget this asset belongs to by checking all widget directories
31- const widgetsDir = join ( process . cwd ( ) , 'dist' , 'resources' , 'mcp-use' , 'widgets' )
32-
33- try {
34- const widgets = readdirSync ( widgetsDir )
35- for ( const widget of widgets ) {
36- const assetPath = join ( widgetsDir , widget , 'assets' , assetFile )
37- if ( existsSync ( assetPath ) ) {
38- return res . sendFile ( assetPath )
39- }
40- }
41- next ( )
42- }
43- catch {
44- next ( )
45- }
46- } )
47-
48- // Serve each widget's index.html at its route
49- // e.g. GET /mcp-use/widgets/kanban-board -> dist/resources/mcp-use/widgets/kanban-board/index.html
50- app . get ( '/mcp-use/widgets/:widget' , ( req , res , next ) => {
51- const filePath = join ( process . cwd ( ) , 'dist' , 'resources' , 'mcp-use' , 'widgets' , req . params . widget , 'index.html' )
52- res . sendFile ( filePath , err => ( err ? next ( ) : undefined ) )
53- } )
54-
55- // Pass the Express app to MCP for SSE transport
56- mcp . setExpressApp ( app )
57-
58- // Start Express server
599const PORT = process . env . PORT || 3000
60- app . listen ( PORT , ( ) => {
61- console . log ( `🌐 UI server running on http://localhost:${ PORT } ` )
62- } )
6310
6411// MCP Resource for server status
65- mcp . resource ( {
12+ server . resource ( {
6613 uri : 'ui://status' ,
6714 name : 'UI Server Status' ,
6815 description : 'Status of the UI MCP server' ,
@@ -82,7 +29,7 @@ mcp.resource({
8229} )
8330
8431// MCP Resource for Kanban Board widget
85- mcp . resource ( {
32+ server . resource ( {
8633 uri : 'ui://widget/kanban-board' ,
8734 name : 'Kanban Board Widget' ,
8835 description : 'Interactive Kanban board widget' ,
@@ -97,7 +44,7 @@ mcp.resource({
9744} )
9845
9946// MCP Resource for Todo List widget
100- mcp . resource ( {
47+ server . resource ( {
10148 uri : 'ui://widget/todo-list' ,
10249 name : 'Todo List Widget' ,
10350 description : 'Interactive todo list widget' ,
@@ -112,7 +59,7 @@ mcp.resource({
11259} )
11360
11461// MCP Resource for Data Visualization widget
115- mcp . resource ( {
62+ server . resource ( {
11663 uri : 'ui://widget/data-visualization' ,
11764 name : 'Data Visualization Widget' ,
11865 description : 'Interactive data visualization widget' ,
@@ -127,7 +74,7 @@ mcp.resource({
12774} )
12875
12976// Tool for showing Kanban Board
130- mcp . tool ( {
77+ server . tool ( {
13178 name : 'show-kanban' ,
13279 description : 'Display an interactive Kanban board' ,
13380 inputs : [
@@ -151,7 +98,7 @@ mcp.tool({
15198} )
15299
153100// Tool for showing Todo List
154- mcp . tool ( {
101+ server . tool ( {
155102 name : 'show-todo-list' ,
156103 description : 'Display an interactive todo list' ,
157104 inputs : [
@@ -175,7 +122,7 @@ mcp.tool({
175122} )
176123
177124// Tool for showing Data Visualization
178- mcp . tool ( {
125+ server . tool ( {
179126 name : 'show-data-viz' ,
180127 description : 'Display an interactive data visualization' ,
181128 inputs : [
@@ -205,7 +152,7 @@ mcp.tool({
205152} )
206153
207154// Prompt for UI development
208- mcp . prompt ( {
155+ server . prompt ( {
209156 name : 'ui-development' ,
210157 description : 'Generate UI development prompts' ,
211158 args : [
@@ -251,24 +198,9 @@ mcp.prompt({
251198
252199console . log ( '🚀 Starting UI MCP Server...' )
253200console . log ( '📋 Server: ui-mcp-server v1.0.0' )
254- console . log ( `🌐 UI Server: http://localhost:${ PORT } ` )
255201console . log ( '📦 Resources: ui://status, ui://widget/kanban-board, ui://widget/todo-list, ui://widget/data-visualization' )
256202console . log ( '🛠️ Tools: show-kanban, show-todo-list, show-data-viz' )
257203console . log ( '💬 Prompts: ui-development' )
258204
259- // Start the MCP server with HTTP by default (use MCP_TRANSPORT=stdio env var for stdio)
260- console . log ( '📡 Setting up MCP server...' )
261- mcp . serve ( {
262- transport : ( process . env . MCP_TRANSPORT as 'http' | 'stdio' ) || 'http' ,
263- endpoint : '/mcp'
264- } ) . then ( ( ) => {
265- const transport = process . env . MCP_TRANSPORT || 'http'
266- if ( transport === 'http' ) {
267- console . log ( `📡 MCP server accessible at: http://localhost:${ PORT } /mcp` )
268- console . log ( '✅ Server ready! Connect with MCP clients via HTTP (StreamableHTTP transport)' )
269- } else {
270- console . log ( '✅ Server ready! Connect with MCP clients via stdio' )
271- }
272- } ) . catch ( ( error ) => {
273- console . error ( '❌ Failed to start MCP server:' , error )
274- } )
205+ // Start the server (MCP endpoints auto-mounted at /mcp)
206+ server . listen ( PORT )
0 commit comments