mcp-use 1.0.4 → 1.0.6

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.
Files changed (34) hide show
  1. package/README.md +98 -1
  2. package/dist/index.cjs +118 -689
  3. package/dist/index.d.ts +10 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +118 -54
  6. package/dist/src/agents/mcp_agent.d.ts +1 -1
  7. package/dist/src/agents/mcp_agent.d.ts.map +1 -1
  8. package/dist/src/server/adapters/mcp-ui-adapter.d.ts +66 -0
  9. package/dist/src/server/adapters/mcp-ui-adapter.d.ts.map +1 -0
  10. package/dist/src/server/index.cjs +292 -14
  11. package/dist/src/server/index.d.ts +4 -2
  12. package/dist/src/server/index.d.ts.map +1 -1
  13. package/dist/src/server/index.js +913 -4
  14. package/dist/src/server/mcp-server.d.ts +91 -2
  15. package/dist/src/server/mcp-server.d.ts.map +1 -1
  16. package/dist/src/server/types/common.d.ts +27 -0
  17. package/dist/src/server/types/common.d.ts.map +1 -0
  18. package/dist/src/server/types/index.d.ts +8 -0
  19. package/dist/src/server/types/index.d.ts.map +1 -0
  20. package/dist/src/server/types/prompt.d.ts +14 -0
  21. package/dist/src/server/types/prompt.d.ts.map +1 -0
  22. package/dist/src/server/types/resource.d.ts +155 -0
  23. package/dist/src/server/types/resource.d.ts.map +1 -0
  24. package/dist/src/server/types/tool.d.ts +14 -0
  25. package/dist/src/server/types/tool.d.ts.map +1 -0
  26. package/dist/src/server/types.d.ts +3 -76
  27. package/dist/src/server/types.d.ts.map +1 -1
  28. package/dist/tests/helpers/widget-generators.d.ts +24 -0
  29. package/dist/tests/helpers/widget-generators.d.ts.map +1 -0
  30. package/dist/tests/mcp-ui-adapter.test.d.ts +8 -0
  31. package/dist/tests/mcp-ui-adapter.test.d.ts.map +1 -0
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +33 -36
  34. package/dist/chunk-MZPKOZE4.js +0 -644
@@ -1,7 +1,916 @@
1
1
  import {
2
- createMCPServer
3
- } from "../../chunk-MZPKOZE4.js";
4
- import "../../chunk-SHUYVCID.js";
2
+ __name
3
+ } from "../../chunk-SHUYVCID.js";
4
+
5
+ // src/server/mcp-server.ts
6
+ import { McpServer as OfficialMcpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { z } from "zod";
8
+ import express from "express";
9
+ import { existsSync, readdirSync } from "fs";
10
+ import { join } from "path";
11
+
12
+ // src/server/logging.ts
13
+ function requestLogger(req, res, next) {
14
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().substring(11, 23);
15
+ const method = req.method;
16
+ const url = req.url;
17
+ const originalEnd = res.end.bind(res);
18
+ res.end = function(chunk, encoding, cb) {
19
+ const statusCode = res.statusCode;
20
+ let statusColor = "";
21
+ if (statusCode >= 200 && statusCode < 300) {
22
+ statusColor = "\x1B[32m";
23
+ } else if (statusCode >= 300 && statusCode < 400) {
24
+ statusColor = "\x1B[33m";
25
+ } else if (statusCode >= 400 && statusCode < 500) {
26
+ statusColor = "\x1B[31m";
27
+ } else if (statusCode >= 500) {
28
+ statusColor = "\x1B[35m";
29
+ }
30
+ let logMessage = `[${timestamp}] ${method} \x1B[1m${url}\x1B[0m`;
31
+ if (method === "POST" && url === "/mcp" && req.body?.method) {
32
+ logMessage += ` \x1B[1m[${req.body.method}]\x1B[0m`;
33
+ }
34
+ logMessage += ` ${statusColor}${statusCode}\x1B[0m`;
35
+ console.log(logMessage);
36
+ return originalEnd(chunk, encoding, cb);
37
+ };
38
+ next();
39
+ }
40
+ __name(requestLogger, "requestLogger");
41
+
42
+ // src/server/adapters/mcp-ui-adapter.ts
43
+ import { createUIResource } from "@mcp-ui/server";
44
+ function buildWidgetUrl(widget, props, config) {
45
+ const url = new URL(
46
+ `/mcp-use/widgets/${widget}`,
47
+ `${config.baseUrl}:${config.port}`
48
+ );
49
+ if (props) {
50
+ Object.entries(props).forEach(([key, value]) => {
51
+ if (value !== void 0 && value !== null) {
52
+ const stringValue = typeof value === "object" ? JSON.stringify(value) : String(value);
53
+ url.searchParams.set(key, stringValue);
54
+ }
55
+ });
56
+ }
57
+ return url.toString();
58
+ }
59
+ __name(buildWidgetUrl, "buildWidgetUrl");
60
+ function createExternalUrlResource(uri, iframeUrl, encoding = "text") {
61
+ return createUIResource({
62
+ uri,
63
+ content: { type: "externalUrl", iframeUrl },
64
+ encoding
65
+ });
66
+ }
67
+ __name(createExternalUrlResource, "createExternalUrlResource");
68
+ function createRawHtmlResource(uri, htmlString, encoding = "text") {
69
+ return createUIResource({
70
+ uri,
71
+ content: { type: "rawHtml", htmlString },
72
+ encoding
73
+ });
74
+ }
75
+ __name(createRawHtmlResource, "createRawHtmlResource");
76
+ function createRemoteDomResource(uri, script, framework = "react", encoding = "text") {
77
+ return createUIResource({
78
+ uri,
79
+ content: { type: "remoteDom", script, framework },
80
+ encoding
81
+ });
82
+ }
83
+ __name(createRemoteDomResource, "createRemoteDomResource");
84
+ function createUIResourceFromDefinition(definition, params, config) {
85
+ const uri = `ui://widget/${definition.name}`;
86
+ const encoding = definition.encoding || "text";
87
+ switch (definition.type) {
88
+ case "externalUrl": {
89
+ const widgetUrl = buildWidgetUrl(definition.widget, params, config);
90
+ return createExternalUrlResource(uri, widgetUrl, encoding);
91
+ }
92
+ case "rawHtml": {
93
+ return createRawHtmlResource(uri, definition.htmlContent, encoding);
94
+ }
95
+ case "remoteDom": {
96
+ const framework = definition.framework || "react";
97
+ return createRemoteDomResource(uri, definition.script, framework, encoding);
98
+ }
99
+ default: {
100
+ const _exhaustive = definition;
101
+ throw new Error(`Unknown UI resource type: ${_exhaustive.type}`);
102
+ }
103
+ }
104
+ }
105
+ __name(createUIResourceFromDefinition, "createUIResourceFromDefinition");
106
+
107
+ // src/server/mcp-server.ts
108
+ var McpServer = class {
109
+ static {
110
+ __name(this, "McpServer");
111
+ }
112
+ server;
113
+ config;
114
+ app;
115
+ mcpMounted = false;
116
+ inspectorMounted = false;
117
+ serverPort;
118
+ /**
119
+ * Creates a new MCP server instance with Express integration
120
+ *
121
+ * Initializes the server with the provided configuration, sets up CORS headers,
122
+ * configures widget serving routes, and creates a proxy that allows direct
123
+ * access to Express methods while preserving MCP server functionality.
124
+ *
125
+ * @param config - Server configuration including name, version, and description
126
+ * @returns A proxied McpServer instance that supports both MCP and Express methods
127
+ */
128
+ constructor(config) {
129
+ this.config = config;
130
+ this.server = new OfficialMcpServer({
131
+ name: config.name,
132
+ version: config.version
133
+ });
134
+ this.app = express();
135
+ this.app.use(express.json());
136
+ this.app.use((req, res, next) => {
137
+ res.header("Access-Control-Allow-Origin", "*");
138
+ res.header("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
139
+ res.header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, mcp-protocol-version, mcp-session-id, X-Proxy-Token, X-Target-URL");
140
+ next();
141
+ });
142
+ this.app.use(requestLogger);
143
+ this.setupWidgetRoutes();
144
+ return new Proxy(this, {
145
+ get(target, prop) {
146
+ if (prop in target) {
147
+ return target[prop];
148
+ }
149
+ const value = target.app[prop];
150
+ return typeof value === "function" ? value.bind(target.app) : value;
151
+ }
152
+ });
153
+ }
154
+ /**
155
+ * Define a static resource that can be accessed by clients
156
+ *
157
+ * Registers a resource with the MCP server that clients can access via HTTP.
158
+ * Resources are static content like files, data, or pre-computed results that
159
+ * can be retrieved by clients without requiring parameters.
160
+ *
161
+ * @param resourceDefinition - Configuration object containing resource metadata and handler function
162
+ * @param resourceDefinition.name - Unique identifier for the resource
163
+ * @param resourceDefinition.uri - URI pattern for accessing the resource
164
+ * @param resourceDefinition.title - Optional human-readable title for the resource
165
+ * @param resourceDefinition.description - Optional description of the resource
166
+ * @param resourceDefinition.mimeType - MIME type of the resource content
167
+ * @param resourceDefinition.annotations - Optional annotations (audience, priority, lastModified)
168
+ * @param resourceDefinition.fn - Async function that returns the resource content
169
+ * @returns The server instance for method chaining
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * server.resource({
174
+ * name: 'config',
175
+ * uri: 'config://app-settings',
176
+ * title: 'Application Settings',
177
+ * mimeType: 'application/json',
178
+ * description: 'Current application configuration',
179
+ * annotations: {
180
+ * audience: ['user'],
181
+ * priority: 0.8
182
+ * },
183
+ * fn: async () => ({
184
+ * contents: [{
185
+ * uri: 'config://app-settings',
186
+ * mimeType: 'application/json',
187
+ * text: JSON.stringify({ theme: 'dark', language: 'en' })
188
+ * }]
189
+ * })
190
+ * })
191
+ * ```
192
+ */
193
+ resource(resourceDefinition) {
194
+ this.server.resource(
195
+ resourceDefinition.name,
196
+ resourceDefinition.uri,
197
+ {
198
+ name: resourceDefinition.name,
199
+ title: resourceDefinition.title,
200
+ description: resourceDefinition.description,
201
+ mimeType: resourceDefinition.mimeType,
202
+ annotations: resourceDefinition.annotations
203
+ },
204
+ async () => {
205
+ return await resourceDefinition.fn();
206
+ }
207
+ );
208
+ return this;
209
+ }
210
+ /**
211
+ * Define a dynamic resource template with parameters
212
+ *
213
+ * Registers a parameterized resource template with the MCP server. Templates use URI
214
+ * patterns with placeholders that can be filled in at request time, allowing dynamic
215
+ * resource generation based on parameters.
216
+ *
217
+ * @param resourceTemplateDefinition - Configuration object for the resource template
218
+ * @param resourceTemplateDefinition.name - Unique identifier for the template
219
+ * @param resourceTemplateDefinition.resourceTemplate - ResourceTemplate object with uriTemplate and metadata
220
+ * @param resourceTemplateDefinition.fn - Async function that generates resource content from URI and params
221
+ * @returns The server instance for method chaining
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * server.resourceTemplate({
226
+ * name: 'user-profile',
227
+ * resourceTemplate: {
228
+ * uriTemplate: 'user://{userId}/profile',
229
+ * name: 'User Profile',
230
+ * mimeType: 'application/json'
231
+ * },
232
+ * fn: async (uri, params) => ({
233
+ * contents: [{
234
+ * uri: uri.toString(),
235
+ * mimeType: 'application/json',
236
+ * text: JSON.stringify({ userId: params.userId, name: 'John Doe' })
237
+ * }]
238
+ * })
239
+ * })
240
+ * ```
241
+ */
242
+ resourceTemplate(resourceTemplateDefinition) {
243
+ const template = new ResourceTemplate(
244
+ resourceTemplateDefinition.resourceTemplate.uriTemplate,
245
+ {
246
+ list: void 0,
247
+ // Optional: callback to list all matching resources
248
+ complete: void 0
249
+ // Optional: callback for auto-completion
250
+ }
251
+ );
252
+ const metadata = {};
253
+ if (resourceTemplateDefinition.resourceTemplate.name) {
254
+ metadata.name = resourceTemplateDefinition.resourceTemplate.name;
255
+ }
256
+ if (resourceTemplateDefinition.title) {
257
+ metadata.title = resourceTemplateDefinition.title;
258
+ }
259
+ if (resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description) {
260
+ metadata.description = resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description;
261
+ }
262
+ if (resourceTemplateDefinition.resourceTemplate.mimeType) {
263
+ metadata.mimeType = resourceTemplateDefinition.resourceTemplate.mimeType;
264
+ }
265
+ if (resourceTemplateDefinition.annotations) {
266
+ metadata.annotations = resourceTemplateDefinition.annotations;
267
+ }
268
+ this.server.resource(
269
+ resourceTemplateDefinition.name,
270
+ template,
271
+ metadata,
272
+ async (uri) => {
273
+ const params = this.parseTemplateUri(
274
+ resourceTemplateDefinition.resourceTemplate.uriTemplate,
275
+ uri.toString()
276
+ );
277
+ return await resourceTemplateDefinition.fn(uri, params);
278
+ }
279
+ );
280
+ return this;
281
+ }
282
+ /**
283
+ * Define a tool that can be called by clients
284
+ *
285
+ * Registers a tool with the MCP server that clients can invoke with parameters.
286
+ * Tools are functions that perform actions, computations, or operations and
287
+ * return results. They accept structured input parameters and return structured output.
288
+ *
289
+ * @param toolDefinition - Configuration object containing tool metadata and handler function
290
+ * @param toolDefinition.name - Unique identifier for the tool
291
+ * @param toolDefinition.description - Human-readable description of what the tool does
292
+ * @param toolDefinition.inputs - Array of input parameter definitions with types and validation
293
+ * @param toolDefinition.fn - Async function that executes the tool logic with provided parameters
294
+ * @returns The server instance for method chaining
295
+ *
296
+ * @example
297
+ * ```typescript
298
+ * server.tool({
299
+ * name: 'calculate',
300
+ * description: 'Performs mathematical calculations',
301
+ * inputs: [
302
+ * { name: 'expression', type: 'string', required: true },
303
+ * { name: 'precision', type: 'number', required: false }
304
+ * ],
305
+ * fn: async ({ expression, precision = 2 }) => {
306
+ * const result = eval(expression)
307
+ * return { result: Number(result.toFixed(precision)) }
308
+ * }
309
+ * })
310
+ * ```
311
+ */
312
+ tool(toolDefinition) {
313
+ const inputSchema = this.createToolInputSchema(toolDefinition.inputs || []);
314
+ this.server.tool(
315
+ toolDefinition.name,
316
+ toolDefinition.description ?? "",
317
+ inputSchema,
318
+ async (params) => {
319
+ return await toolDefinition.fn(params);
320
+ }
321
+ );
322
+ return this;
323
+ }
324
+ /**
325
+ * Define a prompt template
326
+ *
327
+ * Registers a prompt template with the MCP server that clients can use to generate
328
+ * structured prompts for AI models. Prompt templates accept parameters and return
329
+ * formatted text that can be used as input to language models or other AI systems.
330
+ *
331
+ * @param promptDefinition - Configuration object containing prompt metadata and handler function
332
+ * @param promptDefinition.name - Unique identifier for the prompt template
333
+ * @param promptDefinition.description - Human-readable description of the prompt's purpose
334
+ * @param promptDefinition.args - Array of argument definitions with types and validation
335
+ * @param promptDefinition.fn - Async function that generates the prompt from provided arguments
336
+ * @returns The server instance for method chaining
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * server.prompt({
341
+ * name: 'code-review',
342
+ * description: 'Generates a code review prompt',
343
+ * args: [
344
+ * { name: 'language', type: 'string', required: true },
345
+ * { name: 'focus', type: 'string', required: false }
346
+ * ],
347
+ * fn: async ({ language, focus = 'general' }) => {
348
+ * return {
349
+ * messages: [{
350
+ * role: 'user',
351
+ * content: `Please review this ${language} code with focus on ${focus}...`
352
+ * }]
353
+ * }
354
+ * }
355
+ * })
356
+ * ```
357
+ */
358
+ prompt(promptDefinition) {
359
+ const argsSchema = this.createPromptArgsSchema(promptDefinition.args || []);
360
+ this.server.prompt(
361
+ promptDefinition.name,
362
+ promptDefinition.description ?? "",
363
+ argsSchema,
364
+ async (params) => {
365
+ return await promptDefinition.fn(params);
366
+ }
367
+ );
368
+ return this;
369
+ }
370
+ /**
371
+ * Register a UI widget as both a tool and a resource
372
+ *
373
+ * Creates a unified interface for MCP-UI compatible widgets that can be accessed
374
+ * either as tools (with parameters) or as resources (static access). The tool
375
+ * allows dynamic parameter passing while the resource provides discoverable access.
376
+ *
377
+ * @param definition - Configuration for the UI widget
378
+ * @param definition.name - Unique identifier for the resource
379
+ * @param definition.widget - Widget name (matches directory in dist/resources/mcp-use/widgets)
380
+ * @param definition.title - Human-readable title for the widget
381
+ * @param definition.description - Description of the widget's functionality
382
+ * @param definition.props - Widget properties configuration with types and defaults
383
+ * @param definition.size - Preferred iframe size [width, height] (e.g., ['800px', '600px'])
384
+ * @param definition.annotations - Resource annotations for discovery
385
+ * @returns The server instance for method chaining
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * server.uiResource({
390
+ * name: 'kanban-board',
391
+ * widget: 'kanban-board',
392
+ * title: 'Kanban Board',
393
+ * description: 'Interactive task management board',
394
+ * props: {
395
+ * initialTasks: {
396
+ * type: 'array',
397
+ * description: 'Initial tasks to display',
398
+ * required: false
399
+ * },
400
+ * theme: {
401
+ * type: 'string',
402
+ * default: 'light'
403
+ * }
404
+ * },
405
+ * size: ['900px', '600px']
406
+ * })
407
+ * ```
408
+ */
409
+ uiResource(definition) {
410
+ const toolName = definition.type === "externalUrl" ? `ui_${definition.widget}` : `ui_${definition.name}`;
411
+ const displayName = definition.title || definition.name;
412
+ let resourceUri;
413
+ let mimeType;
414
+ switch (definition.type) {
415
+ case "externalUrl":
416
+ resourceUri = `ui://widget/${definition.widget}`;
417
+ mimeType = "text/uri-list";
418
+ break;
419
+ case "rawHtml":
420
+ resourceUri = `ui://widget/${definition.name}`;
421
+ mimeType = "text/html";
422
+ break;
423
+ case "remoteDom":
424
+ resourceUri = `ui://widget/${definition.name}`;
425
+ mimeType = "application/vnd.mcp-ui.remote-dom+javascript";
426
+ break;
427
+ default:
428
+ throw new Error(`Unsupported UI resource type. Must be one of: externalUrl, rawHtml, remoteDom`);
429
+ }
430
+ this.resource({
431
+ name: definition.name,
432
+ uri: resourceUri,
433
+ title: definition.title,
434
+ description: definition.description,
435
+ mimeType,
436
+ annotations: definition.annotations,
437
+ fn: /* @__PURE__ */ __name(async () => {
438
+ const params = definition.type === "externalUrl" ? this.applyDefaultProps(definition.props) : {};
439
+ const uiResource = this.createWidgetUIResource(definition, params);
440
+ return {
441
+ contents: [uiResource.resource]
442
+ };
443
+ }, "fn")
444
+ });
445
+ this.tool({
446
+ name: toolName,
447
+ description: definition.description || `Display ${displayName}`,
448
+ inputs: this.convertPropsToInputs(definition.props),
449
+ fn: /* @__PURE__ */ __name(async (params) => {
450
+ const uiResource = this.createWidgetUIResource(definition, params);
451
+ return {
452
+ content: [
453
+ {
454
+ type: "text",
455
+ text: `Displaying ${displayName}`,
456
+ description: `Show MCP-UI widget for ${displayName}`
457
+ },
458
+ uiResource
459
+ ]
460
+ };
461
+ }, "fn")
462
+ });
463
+ return this;
464
+ }
465
+ /**
466
+ * Create a UIResource object for a widget with the given parameters
467
+ *
468
+ * This method is shared between tool and resource handlers to avoid duplication.
469
+ * It creates a consistent UIResource structure that can be rendered by MCP-UI
470
+ * compatible clients.
471
+ *
472
+ * @private
473
+ * @param definition - UIResource definition
474
+ * @param params - Parameters to pass to the widget via URL
475
+ * @returns UIResource object compatible with MCP-UI
476
+ */
477
+ createWidgetUIResource(definition, params) {
478
+ const urlConfig = {
479
+ baseUrl: "http://localhost",
480
+ port: this.serverPort || 3001
481
+ };
482
+ return createUIResourceFromDefinition(definition, params, urlConfig);
483
+ }
484
+ /**
485
+ * Build a complete URL for a widget including query parameters
486
+ *
487
+ * Constructs the full URL to access a widget's iframe, encoding any provided
488
+ * parameters as query string parameters. Complex objects are JSON-stringified
489
+ * for transmission.
490
+ *
491
+ * @private
492
+ * @param widget - Widget name/identifier
493
+ * @param params - Parameters to encode in the URL
494
+ * @returns Complete URL with encoded parameters
495
+ */
496
+ buildWidgetUrl(widget, params) {
497
+ const baseUrl = `http://localhost:${this.serverPort}/mcp-use/widgets/${widget}`;
498
+ if (Object.keys(params).length === 0) {
499
+ return baseUrl;
500
+ }
501
+ const queryParams = new URLSearchParams();
502
+ for (const [key, value] of Object.entries(params)) {
503
+ if (value !== void 0 && value !== null) {
504
+ if (typeof value === "object") {
505
+ queryParams.append(key, JSON.stringify(value));
506
+ } else {
507
+ queryParams.append(key, String(value));
508
+ }
509
+ }
510
+ }
511
+ return `${baseUrl}?${queryParams.toString()}`;
512
+ }
513
+ /**
514
+ * Convert widget props definition to tool input schema
515
+ *
516
+ * Transforms the widget props configuration into the format expected by
517
+ * the tool registration system, mapping types and handling defaults.
518
+ *
519
+ * @private
520
+ * @param props - Widget props configuration
521
+ * @returns Array of InputDefinition objects for tool registration
522
+ */
523
+ convertPropsToInputs(props) {
524
+ if (!props) return [];
525
+ return Object.entries(props).map(([name, prop]) => ({
526
+ name,
527
+ type: prop.type,
528
+ description: prop.description,
529
+ required: prop.required,
530
+ default: prop.default
531
+ }));
532
+ }
533
+ /**
534
+ * Apply default values to widget props
535
+ *
536
+ * Extracts default values from the props configuration to use when
537
+ * the resource is accessed without parameters.
538
+ *
539
+ * @private
540
+ * @param props - Widget props configuration
541
+ * @returns Object with default values for each prop
542
+ */
543
+ applyDefaultProps(props) {
544
+ if (!props) return {};
545
+ const defaults = {};
546
+ for (const [key, prop] of Object.entries(props)) {
547
+ if (prop.default !== void 0) {
548
+ defaults[key] = prop.default;
549
+ }
550
+ }
551
+ return defaults;
552
+ }
553
+ /**
554
+ * Mount MCP server endpoints at /mcp
555
+ *
556
+ * Sets up the HTTP transport layer for the MCP server, creating endpoints for
557
+ * Server-Sent Events (SSE) streaming, POST message handling, and DELETE session cleanup.
558
+ * Each request gets its own transport instance to prevent state conflicts between
559
+ * concurrent client connections.
560
+ *
561
+ * This method is called automatically when the server starts listening and ensures
562
+ * that MCP clients can communicate with the server over HTTP.
563
+ *
564
+ * @private
565
+ * @returns Promise that resolves when MCP endpoints are successfully mounted
566
+ *
567
+ * @example
568
+ * Endpoints created:
569
+ * - GET /mcp - SSE streaming endpoint for real-time communication
570
+ * - POST /mcp - Message handling endpoint for MCP protocol messages
571
+ * - DELETE /mcp - Session cleanup endpoint
572
+ */
573
+ async mountMcp() {
574
+ if (this.mcpMounted) return;
575
+ const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js");
576
+ const endpoint = "/mcp";
577
+ this.app.post(endpoint, express.json(), async (req, res) => {
578
+ const transport = new StreamableHTTPServerTransport({
579
+ sessionIdGenerator: void 0,
580
+ enableJsonResponse: true
581
+ });
582
+ res.on("close", () => {
583
+ transport.close();
584
+ });
585
+ await this.server.connect(transport);
586
+ await transport.handleRequest(req, res, req.body);
587
+ });
588
+ this.app.get(endpoint, async (req, res) => {
589
+ const transport = new StreamableHTTPServerTransport({
590
+ sessionIdGenerator: void 0,
591
+ enableJsonResponse: true
592
+ });
593
+ res.on("close", () => {
594
+ transport.close();
595
+ });
596
+ await this.server.connect(transport);
597
+ await transport.handleRequest(req, res);
598
+ });
599
+ this.app.delete(endpoint, async (req, res) => {
600
+ const transport = new StreamableHTTPServerTransport({
601
+ sessionIdGenerator: void 0,
602
+ enableJsonResponse: true
603
+ });
604
+ res.on("close", () => {
605
+ transport.close();
606
+ });
607
+ await this.server.connect(transport);
608
+ await transport.handleRequest(req, res);
609
+ });
610
+ this.mcpMounted = true;
611
+ console.log(`[MCP] Server mounted at ${endpoint}`);
612
+ }
613
+ /**
614
+ * Start the Express server with MCP endpoints
615
+ *
616
+ * Initiates the server startup process by mounting MCP endpoints, configuring
617
+ * the inspector UI (if available), and starting the Express server to listen
618
+ * for incoming connections. This is the main entry point for running the server.
619
+ *
620
+ * The server will be accessible at the specified port with MCP endpoints at /mcp
621
+ * and inspector UI at /inspector (if the inspector package is installed).
622
+ *
623
+ * @param port - Port number to listen on (defaults to 3001 if not specified)
624
+ * @returns Promise that resolves when the server is successfully listening
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * await server.listen(8080)
629
+ * // Server now running at http://localhost:8080
630
+ * // MCP endpoints: http://localhost:8080/mcp
631
+ * // Inspector UI: http://localhost:8080/inspector
632
+ * ```
633
+ */
634
+ async listen(port) {
635
+ await this.mountMcp();
636
+ this.serverPort = port || 3001;
637
+ this.mountInspector();
638
+ this.app.listen(this.serverPort, () => {
639
+ console.log(`[SERVER] Listening on http://localhost:${this.serverPort}`);
640
+ console.log(`[MCP] Endpoints: http://localhost:${this.serverPort}/mcp`);
641
+ });
642
+ }
643
+ /**
644
+ * Mount MCP Inspector UI at /inspector
645
+ *
646
+ * Dynamically loads and mounts the MCP Inspector UI package if available, providing
647
+ * a web-based interface for testing and debugging MCP servers. The inspector
648
+ * automatically connects to the local MCP server endpoints.
649
+ *
650
+ * This method gracefully handles cases where the inspector package is not installed,
651
+ * allowing the server to function without the inspector in production environments.
652
+ *
653
+ * @private
654
+ * @returns void
655
+ *
656
+ * @example
657
+ * If @mcp-use/inspector is installed:
658
+ * - Inspector UI available at http://localhost:PORT/inspector
659
+ * - Automatically connects to http://localhost:PORT/mcp
660
+ *
661
+ * If not installed:
662
+ * - Server continues to function normally
663
+ * - No inspector UI available
664
+ */
665
+ mountInspector() {
666
+ if (this.inspectorMounted) return;
667
+ import("@mcp-use/inspector").then(({ mountInspector }) => {
668
+ const mcpServerUrl = `http://localhost:${this.serverPort}/mcp`;
669
+ mountInspector(this.app, "/inspector", mcpServerUrl);
670
+ this.inspectorMounted = true;
671
+ console.log(`[INSPECTOR] UI available at http://localhost:${this.serverPort}/inspector`);
672
+ }).catch(() => {
673
+ });
674
+ }
675
+ /**
676
+ * Setup default widget serving routes
677
+ *
678
+ * Configures Express routes to serve MCP UI widgets and their static assets.
679
+ * Widgets are served from the dist/resources/mcp-use/widgets directory and can
680
+ * be accessed via HTTP endpoints for embedding in web applications.
681
+ *
682
+ * Routes created:
683
+ * - GET /mcp-use/widgets/:widget - Serves widget's index.html
684
+ * - GET /mcp-use/widgets/:widget/assets/* - Serves widget-specific assets
685
+ * - GET /mcp-use/widgets/assets/* - Fallback asset serving with auto-discovery
686
+ *
687
+ * @private
688
+ * @returns void
689
+ *
690
+ * @example
691
+ * Widget routes:
692
+ * - http://localhost:3001/mcp-use/widgets/kanban-board
693
+ * - http://localhost:3001/mcp-use/widgets/todo-list/assets/style.css
694
+ * - http://localhost:3001/mcp-use/widgets/assets/script.js (auto-discovered)
695
+ */
696
+ setupWidgetRoutes() {
697
+ this.app.get("/mcp-use/widgets/:widget/assets/*", (req, res, next) => {
698
+ const widget = req.params.widget;
699
+ const assetFile = req.params[0];
700
+ const assetPath = join(process.cwd(), "dist", "resources", "mcp-use", "widgets", widget, "assets", assetFile);
701
+ res.sendFile(assetPath, (err) => err ? next() : void 0);
702
+ });
703
+ this.app.get("/mcp-use/widgets/assets/*", (req, res, next) => {
704
+ const assetFile = req.params[0];
705
+ const widgetsDir = join(process.cwd(), "dist", "resources", "mcp-use", "widgets");
706
+ try {
707
+ const widgets = readdirSync(widgetsDir);
708
+ for (const widget of widgets) {
709
+ const assetPath = join(widgetsDir, widget, "assets", assetFile);
710
+ if (existsSync(assetPath)) {
711
+ return res.sendFile(assetPath);
712
+ }
713
+ }
714
+ next();
715
+ } catch {
716
+ next();
717
+ }
718
+ });
719
+ this.app.get("/mcp-use/widgets/:widget", (req, res, next) => {
720
+ const filePath = join(process.cwd(), "dist", "resources", "mcp-use", "widgets", req.params.widget, "index.html");
721
+ res.sendFile(filePath, (err) => err ? next() : void 0);
722
+ });
723
+ }
724
+ /**
725
+ * Create input schema for resource templates
726
+ *
727
+ * Parses a URI template string to extract parameter names and generates a Zod
728
+ * validation schema for those parameters. Used internally for validating resource
729
+ * template parameters before processing requests.
730
+ *
731
+ * @param uriTemplate - URI template string with parameter placeholders (e.g., "/users/{id}/posts/{postId}")
732
+ * @returns Object mapping parameter names to Zod string schemas
733
+ *
734
+ * @example
735
+ * ```typescript
736
+ * const schema = this.createInputSchema("/users/{id}/posts/{postId}")
737
+ * // Returns: { id: z.string(), postId: z.string() }
738
+ * ```
739
+ */
740
+ createInputSchema(uriTemplate) {
741
+ const params = this.extractTemplateParams(uriTemplate);
742
+ const schema = {};
743
+ params.forEach((param) => {
744
+ schema[param] = z.string();
745
+ });
746
+ return schema;
747
+ }
748
+ /**
749
+ * Create input schema for tools
750
+ *
751
+ * Converts tool input definitions into Zod validation schemas for runtime validation.
752
+ * Supports common data types (string, number, boolean, object, array) and optional
753
+ * parameters. Used internally when registering tools with the MCP server.
754
+ *
755
+ * @param inputs - Array of input parameter definitions with name, type, and optional flag
756
+ * @returns Object mapping parameter names to Zod validation schemas
757
+ *
758
+ * @example
759
+ * ```typescript
760
+ * const schema = this.createToolInputSchema([
761
+ * { name: 'query', type: 'string', required: true },
762
+ * { name: 'limit', type: 'number', required: false }
763
+ * ])
764
+ * // Returns: { query: z.string(), limit: z.number().optional() }
765
+ * ```
766
+ */
767
+ createToolInputSchema(inputs) {
768
+ const schema = {};
769
+ inputs.forEach((input) => {
770
+ let zodType;
771
+ switch (input.type) {
772
+ case "string":
773
+ zodType = z.string();
774
+ break;
775
+ case "number":
776
+ zodType = z.number();
777
+ break;
778
+ case "boolean":
779
+ zodType = z.boolean();
780
+ break;
781
+ case "object":
782
+ zodType = z.object({});
783
+ break;
784
+ case "array":
785
+ zodType = z.array(z.any());
786
+ break;
787
+ default:
788
+ zodType = z.any();
789
+ }
790
+ if (!input.required) {
791
+ zodType = zodType.optional();
792
+ }
793
+ schema[input.name] = zodType;
794
+ });
795
+ return schema;
796
+ }
797
+ /**
798
+ * Create arguments schema for prompts
799
+ *
800
+ * Converts prompt argument definitions into Zod validation schemas for runtime validation.
801
+ * Supports common data types (string, number, boolean, object, array) and optional
802
+ * parameters. Used internally when registering prompt templates with the MCP server.
803
+ *
804
+ * @param inputs - Array of argument definitions with name, type, and optional flag
805
+ * @returns Object mapping argument names to Zod validation schemas
806
+ *
807
+ * @example
808
+ * ```typescript
809
+ * const schema = this.createPromptArgsSchema([
810
+ * { name: 'topic', type: 'string', required: true },
811
+ * { name: 'style', type: 'string', required: false }
812
+ * ])
813
+ * // Returns: { topic: z.string(), style: z.string().optional() }
814
+ * ```
815
+ */
816
+ createPromptArgsSchema(inputs) {
817
+ const schema = {};
818
+ inputs.forEach((input) => {
819
+ let zodType;
820
+ switch (input.type) {
821
+ case "string":
822
+ zodType = z.string();
823
+ break;
824
+ case "number":
825
+ zodType = z.number();
826
+ break;
827
+ case "boolean":
828
+ zodType = z.boolean();
829
+ break;
830
+ case "object":
831
+ zodType = z.object({});
832
+ break;
833
+ case "array":
834
+ zodType = z.array(z.any());
835
+ break;
836
+ default:
837
+ zodType = z.any();
838
+ }
839
+ if (!input.required) {
840
+ zodType = zodType.optional();
841
+ }
842
+ schema[input.name] = zodType;
843
+ });
844
+ return schema;
845
+ }
846
+ /**
847
+ * Extract parameter names from URI template
848
+ *
849
+ * Parses a URI template string to extract parameter names enclosed in curly braces.
850
+ * Used internally to identify dynamic parameters in resource templates and generate
851
+ * appropriate validation schemas.
852
+ *
853
+ * @param uriTemplate - URI template string with parameter placeholders (e.g., "/users/{id}/posts/{postId}")
854
+ * @returns Array of parameter names found in the template
855
+ *
856
+ * @example
857
+ * ```typescript
858
+ * const params = this.extractTemplateParams("/users/{id}/posts/{postId}")
859
+ * // Returns: ["id", "postId"]
860
+ * ```
861
+ */
862
+ extractTemplateParams(uriTemplate) {
863
+ const matches = uriTemplate.match(/\{([^}]+)\}/g);
864
+ return matches ? matches.map((match) => match.slice(1, -1)) : [];
865
+ }
866
+ /**
867
+ * Parse parameter values from a URI based on a template
868
+ *
869
+ * Extracts parameter values from an actual URI by matching it against a URI template.
870
+ * The template contains placeholders like {param} which are extracted as key-value pairs.
871
+ *
872
+ * @param template - URI template with placeholders (e.g., "user://{userId}/posts/{postId}")
873
+ * @param uri - Actual URI to parse (e.g., "user://123/posts/456")
874
+ * @returns Object mapping parameter names to their values
875
+ *
876
+ * @example
877
+ * ```typescript
878
+ * const params = this.parseTemplateUri("user://{userId}/posts/{postId}", "user://123/posts/456")
879
+ * // Returns: { userId: "123", postId: "456" }
880
+ * ```
881
+ */
882
+ parseTemplateUri(template, uri) {
883
+ const params = {};
884
+ let regexPattern = template.replace(/[.*+?^$()[\]\\|]/g, "\\$&");
885
+ const paramNames = [];
886
+ regexPattern = regexPattern.replace(/\\\{([^}]+)\\\}/g, (_, paramName) => {
887
+ paramNames.push(paramName);
888
+ return "([^/]+)";
889
+ });
890
+ const regex = new RegExp(`^${regexPattern}$`);
891
+ const match = uri.match(regex);
892
+ if (match) {
893
+ paramNames.forEach((paramName, index) => {
894
+ params[paramName] = match[index + 1];
895
+ });
896
+ }
897
+ return params;
898
+ }
899
+ };
900
+ function createMCPServer(name, config = {}) {
901
+ const instance = new McpServer({
902
+ name,
903
+ version: config.version || "1.0.0",
904
+ description: config.description
905
+ });
906
+ return instance;
907
+ }
908
+ __name(createMCPServer, "createMCPServer");
5
909
  export {
6
- createMCPServer
910
+ buildWidgetUrl,
911
+ createExternalUrlResource,
912
+ createMCPServer,
913
+ createRawHtmlResource,
914
+ createRemoteDomResource,
915
+ createUIResourceFromDefinition
7
916
  };