mcp-use 1.1.6 → 1.1.7-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.
@@ -47,6 +47,7 @@ var import_express = __toESM(require("express"), 1);
47
47
  var import_cors = __toESM(require("cors"), 1);
48
48
  var import_node_fs = require("fs");
49
49
  var import_node_path = require("path");
50
+ var import_node_fs2 = require("fs");
50
51
 
51
52
  // src/server/logging.ts
52
53
  function requestLogger(req, res, next) {
@@ -85,13 +86,8 @@ function buildWidgetUrl(widget, props, config) {
85
86
  `/mcp-use/widgets/${widget}`,
86
87
  `${config.baseUrl}:${config.port}`
87
88
  );
88
- if (props) {
89
- Object.entries(props).forEach(([key, value]) => {
90
- if (value !== void 0 && value !== null) {
91
- const stringValue = typeof value === "object" ? JSON.stringify(value) : String(value);
92
- url.searchParams.set(key, stringValue);
93
- }
94
- });
89
+ if (props && Object.keys(props).length > 0) {
90
+ url.searchParams.set("props", JSON.stringify(props));
95
91
  }
96
92
  return url.toString();
97
93
  }
@@ -191,6 +187,8 @@ function createUIResourceFromDefinition(definition, params, config) {
191
187
  __name(createUIResourceFromDefinition, "createUIResourceFromDefinition");
192
188
 
193
189
  // src/server/mcp-server.ts
190
+ var import_vite = require("vite");
191
+ var TMP_MCP_USE_DIR = ".mcp-use";
194
192
  var McpServer = class {
195
193
  static {
196
194
  __name(this, "McpServer");
@@ -201,6 +199,8 @@ var McpServer = class {
201
199
  mcpMounted = false;
202
200
  inspectorMounted = false;
203
201
  serverPort;
202
+ serverHost;
203
+ serverBaseUrl;
204
204
  /**
205
205
  * Creates a new MCP server instance with Express integration
206
206
  *
@@ -213,6 +213,8 @@ var McpServer = class {
213
213
  */
214
214
  constructor(config) {
215
215
  this.config = config;
216
+ this.serverHost = config.host || "localhost";
217
+ this.serverBaseUrl = config.baseUrl;
216
218
  this.server = new import_mcp.McpServer({
217
219
  name: config.name,
218
220
  version: config.version
@@ -225,7 +227,6 @@ var McpServer = class {
225
227
  allowedHeaders: ["Content-Type", "Accept", "Authorization", "mcp-protocol-version", "mcp-session-id", "X-Proxy-Token", "X-Target-URL"]
226
228
  }));
227
229
  this.app.use(requestLogger);
228
- this.setupWidgetRoutes();
229
230
  return new Proxy(this, {
230
231
  get(target, prop) {
231
232
  if (prop in target) {
@@ -284,7 +285,8 @@ var McpServer = class {
284
285
  title: resourceDefinition.title,
285
286
  description: resourceDefinition.description,
286
287
  mimeType: resourceDefinition.mimeType,
287
- annotations: resourceDefinition.annotations
288
+ annotations: resourceDefinition.annotations,
289
+ _meta: resourceDefinition._meta
288
290
  },
289
291
  async () => {
290
292
  return await resourceDefinition.readCallback();
@@ -403,7 +405,7 @@ var McpServer = class {
403
405
  * ```
404
406
  */
405
407
  tool(toolDefinition) {
406
- const inputSchema = this.createToolInputSchema(toolDefinition.inputs || []);
408
+ const inputSchema = this.createParamsSchema(toolDefinition.inputs || []);
407
409
  this.server.registerTool(
408
410
  toolDefinition.name,
409
411
  {
@@ -454,7 +456,7 @@ var McpServer = class {
454
456
  * ```
455
457
  */
456
458
  prompt(promptDefinition) {
457
- const argsSchema = this.createPromptArgsSchema(promptDefinition.args || []);
459
+ const argsSchema = this.createParamsSchema(promptDefinition.args || []);
458
460
  this.server.registerPrompt(
459
461
  promptDefinition.name,
460
462
  {
@@ -481,19 +483,22 @@ var McpServer = class {
481
483
  * - remoteDom: Legacy MCP-UI Remote DOM scripting
482
484
  * - appsSdk: OpenAI Apps SDK compatible widgets (text/html+skybridge)
483
485
  *
484
- * @param definition - Configuration for the UI widget
486
+ * @param widgetNameOrDefinition - Widget name (string) for auto-loading schema, or full configuration object
485
487
  * @param definition.name - Unique identifier for the resource
486
488
  * @param definition.type - Type of UI resource (externalUrl, rawHtml, remoteDom, appsSdk)
487
489
  * @param definition.title - Human-readable title for the widget
488
490
  * @param definition.description - Description of the widget's functionality
489
491
  * @param definition.props - Widget properties configuration with types and defaults
490
- * @param definition.size - Preferred iframe size [width, height] (e.g., ['800px', '600px'])
492
+ * @param definition.size - Preferred iframe size [width, height] (e.g., ['900px', '600px'])
491
493
  * @param definition.annotations - Resource annotations for discovery
492
494
  * @param definition.appsSdkMetadata - Apps SDK specific metadata (CSP, widget description, etc.)
493
495
  * @returns The server instance for method chaining
494
496
  *
495
497
  * @example
496
498
  * ```typescript
499
+ * // Simple usage - auto-loads from generated schema
500
+ * server.uiResource('display-weather')
501
+ *
497
502
  * // Legacy MCP-UI widget
498
503
  * server.uiResource({
499
504
  * type: 'externalUrl',
@@ -533,14 +538,6 @@ var McpServer = class {
533
538
  * ```
534
539
  */
535
540
  uiResource(definition) {
536
- let toolName;
537
- if (definition.type === "appsSdk") {
538
- toolName = definition.name;
539
- } else if (definition.type === "externalUrl") {
540
- toolName = `ui_${definition.widget}`;
541
- } else {
542
- toolName = `ui_${definition.name}`;
543
- }
544
541
  const displayName = definition.title || definition.name;
545
542
  let resourceUri;
546
543
  let mimeType;
@@ -570,6 +567,7 @@ var McpServer = class {
570
567
  title: definition.title,
571
568
  description: definition.description,
572
569
  mimeType,
570
+ _meta: definition._meta,
573
571
  annotations: definition.annotations,
574
572
  readCallback: /* @__PURE__ */ __name(async () => {
575
573
  const params = definition.type === "externalUrl" ? this.applyDefaultProps(definition.props) : {};
@@ -579,7 +577,28 @@ var McpServer = class {
579
577
  };
580
578
  }, "readCallback")
581
579
  });
582
- const toolMetadata = {};
580
+ if (definition.type === "appsSdk") {
581
+ this.resourceTemplate({
582
+ name: `${definition.name}-dynamic`,
583
+ resourceTemplate: {
584
+ uriTemplate: `ui://widget/${definition.name}-{id}.html`,
585
+ name: definition.title || definition.name,
586
+ description: definition.description,
587
+ mimeType
588
+ },
589
+ _meta: definition._meta,
590
+ title: definition.title,
591
+ description: definition.description,
592
+ annotations: definition.annotations,
593
+ readCallback: /* @__PURE__ */ __name(async (uri, params) => {
594
+ const uiResource = this.createWidgetUIResource(definition, {});
595
+ return {
596
+ contents: [uiResource.resource]
597
+ };
598
+ }, "readCallback")
599
+ });
600
+ }
601
+ const toolMetadata = definition._meta || {};
583
602
  if (definition.type === "appsSdk" && definition.appsSdkMetadata) {
584
603
  toolMetadata["openai/outputTemplate"] = resourceUri;
585
604
  const toolMetadataFields = [
@@ -595,17 +614,19 @@ var McpServer = class {
595
614
  }
596
615
  }
597
616
  this.tool({
598
- name: toolName,
617
+ name: definition.name,
599
618
  title: definition.title,
600
- // For Apps SDK, use title as description to match OpenAI's pizzaz reference implementation
601
- description: definition.type === "appsSdk" && definition.title ? definition.title : definition.description || `Display ${displayName}`,
619
+ description: definition.description,
602
620
  inputs: this.convertPropsToInputs(definition.props),
603
621
  _meta: Object.keys(toolMetadata).length > 0 ? toolMetadata : void 0,
604
622
  cb: /* @__PURE__ */ __name(async (params) => {
605
623
  const uiResource = this.createWidgetUIResource(definition, params);
606
624
  if (definition.type === "appsSdk") {
625
+ const randomId = Math.random().toString(36).substring(2, 15);
626
+ const uniqueUri = `ui://widget/${definition.name}-${randomId}.html`;
627
+ const uniqueToolMetadata = { ...toolMetadata, "openai/outputTemplate": uniqueUri };
607
628
  return {
608
- _meta: toolMetadata,
629
+ _meta: uniqueToolMetadata,
609
630
  content: [
610
631
  {
611
632
  type: "text",
@@ -643,9 +664,20 @@ var McpServer = class {
643
664
  * @returns UIResource object compatible with MCP-UI
644
665
  */
645
666
  createWidgetUIResource(definition, params) {
667
+ let configBaseUrl = `http://${this.serverHost}`;
668
+ let configPort = this.serverPort || 3001;
669
+ if (this.serverBaseUrl) {
670
+ try {
671
+ const url = new URL(this.serverBaseUrl);
672
+ configBaseUrl = `${url.protocol}//${url.hostname}`;
673
+ configPort = url.port || (url.protocol === "https:" ? 443 : 80);
674
+ } catch (e) {
675
+ console.warn("Failed to parse baseUrl, falling back to host:port", e);
676
+ }
677
+ }
646
678
  const urlConfig = {
647
- baseUrl: "http://localhost",
648
- port: this.serverPort || 3001
679
+ baseUrl: configBaseUrl,
680
+ port: configPort
649
681
  };
650
682
  return createUIResourceFromDefinition(definition, params, urlConfig);
651
683
  }
@@ -662,7 +694,7 @@ var McpServer = class {
662
694
  * @returns Complete URL with encoded parameters
663
695
  */
664
696
  buildWidgetUrl(widget, params) {
665
- const baseUrl = `http://localhost:${this.serverPort}/mcp-use/widgets/${widget}`;
697
+ const baseUrl = `http://${this.serverHost}:${this.serverPort}/mcp-use/widgets/${widget}`;
666
698
  if (Object.keys(params).length === 0) {
667
699
  return baseUrl;
668
700
  }
@@ -718,6 +750,324 @@ var McpServer = class {
718
750
  }
719
751
  return defaults;
720
752
  }
753
+ /**
754
+ * Check if server is running in production mode
755
+ *
756
+ * @private
757
+ * @returns true if in production mode, false otherwise
758
+ */
759
+ isProductionMode() {
760
+ return process.env.NODE_ENV === "production";
761
+ }
762
+ /**
763
+ * Read build manifest file
764
+ *
765
+ * @private
766
+ * @returns Build manifest or null if not found
767
+ */
768
+ readBuildManifest() {
769
+ try {
770
+ const manifestPath = (0, import_node_path.join)(process.cwd(), "dist", ".mcp-use-manifest.json");
771
+ const content = (0, import_node_fs2.readFileSync)(manifestPath, "utf8");
772
+ return JSON.parse(content);
773
+ } catch {
774
+ return null;
775
+ }
776
+ }
777
+ /**
778
+ * Mount widget files - automatically chooses between dev and production mode
779
+ *
780
+ * In development mode: creates Vite dev servers with HMR support
781
+ * In production mode: serves pre-built static widgets
782
+ *
783
+ * @param options - Configuration options
784
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
785
+ * @param options.resourcesDir - Directory containing widget files (defaults to 'resources')
786
+ * @returns Promise that resolves when all widgets are mounted
787
+ */
788
+ async mountWidgets(options) {
789
+ if (this.isProductionMode()) {
790
+ await this.mountWidgetsProduction(options);
791
+ } else {
792
+ await this.mountWidgetsDev(options);
793
+ }
794
+ }
795
+ /**
796
+ * Mount individual widget files from resources/ directory in development mode
797
+ *
798
+ * Scans the resources/ directory for .tsx/.ts widget files and creates individual
799
+ * Vite dev servers for each widget with HMR support. Each widget is served at its
800
+ * own route: /mcp-use/widgets/{widget-name}
801
+ *
802
+ * @private
803
+ * @param options - Configuration options
804
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
805
+ * @param options.resourcesDir - Directory containing widget files (defaults to 'resources')
806
+ * @returns Promise that resolves when all widgets are mounted
807
+ */
808
+ async mountWidgetsDev(options) {
809
+ const { promises: fs } = await import("fs");
810
+ const baseRoute = options?.baseRoute || "/mcp-use/widgets";
811
+ const resourcesDir = options?.resourcesDir || "resources";
812
+ const srcDir = (0, import_node_path.join)(process.cwd(), resourcesDir);
813
+ try {
814
+ await fs.access(srcDir);
815
+ } catch (error) {
816
+ console.log(`[WIDGETS] No ${resourcesDir}/ directory found - skipping widget serving`);
817
+ return;
818
+ }
819
+ let entries = [];
820
+ try {
821
+ const files = await fs.readdir(srcDir);
822
+ entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => (0, import_node_path.join)(srcDir, f));
823
+ } catch (error) {
824
+ console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
825
+ return;
826
+ }
827
+ if (entries.length === 0) {
828
+ console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
829
+ return;
830
+ }
831
+ const tempDir = (0, import_node_path.join)(process.cwd(), TMP_MCP_USE_DIR);
832
+ await fs.mkdir(tempDir, { recursive: true }).catch(() => {
833
+ });
834
+ const react = (await import("@vitejs/plugin-react")).default;
835
+ const tailwindcss = (await import("@tailwindcss/vite")).default;
836
+ console.log(react, tailwindcss);
837
+ const widgets = entries.map((entry) => {
838
+ const baseName = entry.split("/").pop()?.replace(/\.tsx?$/, "") || "widget";
839
+ const widgetName = baseName;
840
+ return {
841
+ name: widgetName,
842
+ description: `Widget: ${widgetName}`,
843
+ entry
844
+ };
845
+ });
846
+ for (const widget of widgets) {
847
+ const widgetTempDir = (0, import_node_path.join)(tempDir, widget.name);
848
+ await fs.mkdir(widgetTempDir, { recursive: true });
849
+ const resourcesPath = (0, import_node_path.join)(process.cwd(), resourcesDir);
850
+ const { relative } = await import("path");
851
+ const relativeResourcesPath = relative(widgetTempDir, resourcesPath).replace(/\\/g, "/");
852
+ const cssContent = `@import "tailwindcss";
853
+
854
+ /* Configure Tailwind to scan the resources directory */
855
+ @source "${relativeResourcesPath}";
856
+ `;
857
+ await fs.writeFile((0, import_node_path.join)(widgetTempDir, "styles.css"), cssContent, "utf8");
858
+ const entryContent = `import React from 'react'
859
+ import { createRoot } from 'react-dom/client'
860
+ import './styles.css'
861
+ import Component from '${widget.entry}'
862
+
863
+ const container = document.getElementById('widget-root')
864
+ if (container && Component) {
865
+ const root = createRoot(container)
866
+ root.render(<Component />)
867
+ }
868
+ `;
869
+ const htmlContent = `<!doctype html>
870
+ <html lang="en">
871
+ <head>
872
+ <meta charset="UTF-8" />
873
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
874
+ <title>${widget.name} Widget</title>
875
+ </head>
876
+ <body>
877
+ <div id="widget-root"></div>
878
+ <script type="module" src="${baseRoute}/${widget.name}/entry.tsx"></script>
879
+ </body>
880
+ </html>`;
881
+ await fs.writeFile((0, import_node_path.join)(widgetTempDir, "entry.tsx"), entryContent, "utf8");
882
+ await fs.writeFile((0, import_node_path.join)(widgetTempDir, "index.html"), htmlContent, "utf8");
883
+ }
884
+ const serverOrigin = this.serverBaseUrl || `http://${this.serverHost}:${this.serverPort}`;
885
+ console.log(`[WIDGETS] Serving ${entries.length} widget(s) with shared Vite dev server and HMR`);
886
+ const viteServer = await (0, import_vite.createServer)({
887
+ root: tempDir,
888
+ base: baseRoute + "/",
889
+ plugins: [tailwindcss(), react()],
890
+ resolve: {
891
+ alias: {
892
+ "@": (0, import_node_path.join)(process.cwd(), resourcesDir)
893
+ }
894
+ },
895
+ server: {
896
+ middlewareMode: true,
897
+ origin: serverOrigin
898
+ }
899
+ });
900
+ this.app.use(baseRoute, (req, res, next) => {
901
+ const urlPath = req.url || "";
902
+ const [pathname, queryString] = urlPath.split("?");
903
+ const widgetMatch = pathname.match(/^\/([^/]+)/);
904
+ if (widgetMatch) {
905
+ const widgetName = widgetMatch[1];
906
+ const widget = widgets.find((w) => w.name === widgetName);
907
+ if (widget) {
908
+ if (pathname === `/${widgetName}` || pathname === `/${widgetName}/`) {
909
+ req.url = `/${widgetName}/index.html${queryString ? "?" + queryString : ""}`;
910
+ }
911
+ }
912
+ }
913
+ next();
914
+ });
915
+ this.app.use(baseRoute, viteServer.middlewares);
916
+ widgets.forEach((widget) => {
917
+ console.log(`[WIDGET] ${widget.name} mounted at ${baseRoute}/${widget.name}`);
918
+ });
919
+ for (const widget of widgets) {
920
+ const type = "appsSdk";
921
+ let widgetMetadata = {};
922
+ let props = {};
923
+ let description = widget.description;
924
+ try {
925
+ const mod = await viteServer.ssrLoadModule(widget.entry);
926
+ if (mod.widgetMetadata) {
927
+ widgetMetadata = mod.widgetMetadata;
928
+ description = widgetMetadata.description || widget.description;
929
+ if (widgetMetadata.inputs) {
930
+ try {
931
+ props = widgetMetadata.inputs.shape || {};
932
+ } catch (error) {
933
+ console.warn(`[WIDGET] Failed to extract props schema for ${widget.name}:`, error);
934
+ }
935
+ }
936
+ }
937
+ } catch (error) {
938
+ console.warn(`[WIDGET] Failed to load metadata for ${widget.name}:`, error);
939
+ }
940
+ let html = "";
941
+ try {
942
+ html = await (0, import_node_fs2.readFileSync)((0, import_node_path.join)(tempDir, widget.name, "index.html"), "utf8");
943
+ } catch (error) {
944
+ console.error(`Failed to read html template for widget ${widget.name}`, error);
945
+ }
946
+ this.uiResource({
947
+ name: widget.name,
948
+ title: widget.name,
949
+ description,
950
+ type,
951
+ props,
952
+ _meta: {
953
+ "mcp-use/widget": {
954
+ name: widget.name,
955
+ description,
956
+ type,
957
+ props,
958
+ html,
959
+ dev: true
960
+ }
961
+ },
962
+ htmlTemplate: html,
963
+ appsSdkMetadata: {
964
+ "openai/widgetDescription": description,
965
+ "openai/toolInvocation/invoking": "Hand-tossing a map",
966
+ "openai/toolInvocation/invoked": "Served a fresh map",
967
+ "openai/widgetAccessible": true,
968
+ "openai/resultCanProduceWidget": true,
969
+ "openai/widgetCSP": {
970
+ connect_domains: [],
971
+ resource_domains: ["https://persistent.oaistatic.com"]
972
+ }
973
+ }
974
+ });
975
+ }
976
+ }
977
+ /**
978
+ * Mount pre-built widgets from dist/resources/widgets/ directory in production mode
979
+ *
980
+ * Serves static widget bundles that were built using the build command.
981
+ * Sets up Express routes to serve the HTML and asset files, then registers
982
+ * tools and resources for each widget.
983
+ *
984
+ * @private
985
+ * @param options - Configuration options
986
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
987
+ * @returns Promise that resolves when all widgets are mounted
988
+ */
989
+ async mountWidgetsProduction(options) {
990
+ const baseRoute = options?.baseRoute || "/mcp-use/widgets";
991
+ const widgetsDir = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets");
992
+ if (!(0, import_node_fs.existsSync)(widgetsDir)) {
993
+ console.log("[WIDGETS] No dist/resources/widgets/ directory found - skipping widget serving");
994
+ return;
995
+ }
996
+ this.setupWidgetRoutes();
997
+ const widgets = (0, import_node_fs.readdirSync)(widgetsDir).filter((name) => {
998
+ const widgetPath = (0, import_node_path.join)(widgetsDir, name);
999
+ const indexPath = (0, import_node_path.join)(widgetPath, "index.html");
1000
+ return (0, import_node_fs.existsSync)(indexPath);
1001
+ });
1002
+ if (widgets.length === 0) {
1003
+ console.log("[WIDGETS] No built widgets found in dist/resources/widgets/");
1004
+ return;
1005
+ }
1006
+ console.log(`[WIDGETS] Serving ${widgets.length} pre-built widget(s) from dist/resources/widgets/`);
1007
+ for (const widgetName of widgets) {
1008
+ const widgetPath = (0, import_node_path.join)(widgetsDir, widgetName);
1009
+ const indexPath = (0, import_node_path.join)(widgetPath, "index.html");
1010
+ const metadataPath = (0, import_node_path.join)(widgetPath, "metadata.json");
1011
+ let html = "";
1012
+ try {
1013
+ html = (0, import_node_fs2.readFileSync)(indexPath, "utf8");
1014
+ } catch (error) {
1015
+ console.error(`[WIDGET] Failed to read ${widgetName}/index.html:`, error);
1016
+ continue;
1017
+ }
1018
+ let metadata = {};
1019
+ let props = {};
1020
+ let description = `Widget: ${widgetName}`;
1021
+ try {
1022
+ const metadataContent = (0, import_node_fs2.readFileSync)(metadataPath, "utf8");
1023
+ metadata = JSON.parse(metadataContent);
1024
+ if (metadata.description) {
1025
+ description = metadata.description;
1026
+ }
1027
+ if (metadata.inputs) {
1028
+ props = metadata.inputs;
1029
+ }
1030
+ } catch (error) {
1031
+ console.log(`[WIDGET] No metadata found for ${widgetName}, using defaults`);
1032
+ }
1033
+ this.uiResource({
1034
+ name: widgetName,
1035
+ title: widgetName,
1036
+ description,
1037
+ type: "appsSdk",
1038
+ props,
1039
+ _meta: {
1040
+ "mcp-use/widget": {
1041
+ name: widgetName,
1042
+ description,
1043
+ type: "appsSdk",
1044
+ props,
1045
+ html,
1046
+ dev: false
1047
+ }
1048
+ },
1049
+ htmlTemplate: html,
1050
+ appsSdkMetadata: {
1051
+ "openai/widgetDescription": description,
1052
+ "openai/toolInvocation/invoking": `Loading ${widgetName}...`,
1053
+ "openai/toolInvocation/invoked": `${widgetName} ready`,
1054
+ "openai/widgetAccessible": true,
1055
+ "openai/resultCanProduceWidget": true,
1056
+ "openai/widgetCSP": {
1057
+ connect_domains: [],
1058
+ resource_domains: [
1059
+ "https://*.oaistatic.com",
1060
+ "https://*.unsplash.com",
1061
+ "https://*.oaiusercontent.com",
1062
+ // always also add the base url of the server
1063
+ ...this.serverBaseUrl ? [this.serverBaseUrl] : []
1064
+ ]
1065
+ }
1066
+ }
1067
+ });
1068
+ console.log(`[WIDGET] ${widgetName} mounted at ${baseRoute}/${widgetName}`);
1069
+ }
1070
+ }
721
1071
  /**
722
1072
  * Mount MCP server endpoints at /mcp
723
1073
  *
@@ -794,18 +1144,25 @@ var McpServer = class {
794
1144
  * @example
795
1145
  * ```typescript
796
1146
  * await server.listen(8080)
797
- * // Server now running at http://localhost:8080
1147
+ * // Server now running at http://localhost:8080 (or configured host)
798
1148
  * // MCP endpoints: http://localhost:8080/mcp
799
1149
  * // Inspector UI: http://localhost:8080/inspector
800
1150
  * ```
801
1151
  */
802
1152
  async listen(port) {
1153
+ this.serverPort = port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 3001);
1154
+ if (process.env.HOST) {
1155
+ this.serverHost = process.env.HOST;
1156
+ }
1157
+ await this.mountWidgets({
1158
+ baseRoute: "/mcp-use/widgets",
1159
+ resourcesDir: "resources"
1160
+ });
803
1161
  await this.mountMcp();
804
- this.serverPort = port || 3001;
805
1162
  this.mountInspector();
806
1163
  this.app.listen(this.serverPort, () => {
807
- console.log(`[SERVER] Listening on http://localhost:${this.serverPort}`);
808
- console.log(`[MCP] Endpoints: http://localhost:${this.serverPort}/mcp`);
1164
+ console.log(`[SERVER] Listening on http://${this.serverHost}:${this.serverPort}`);
1165
+ console.log(`[MCP] Endpoints: http://${this.serverHost}:${this.serverPort}/mcp`);
809
1166
  });
810
1167
  }
811
1168
  /**
@@ -832,10 +1189,17 @@ var McpServer = class {
832
1189
  */
833
1190
  mountInspector() {
834
1191
  if (this.inspectorMounted) return;
1192
+ if (this.isProductionMode()) {
1193
+ const manifest = this.readBuildManifest();
1194
+ if (!manifest?.includeInspector) {
1195
+ console.log("[INSPECTOR] Skipped in production (use --with-inspector flag during build)");
1196
+ return;
1197
+ }
1198
+ }
835
1199
  import("@mcp-use/inspector").then(({ mountInspector }) => {
836
1200
  mountInspector(this.app);
837
1201
  this.inspectorMounted = true;
838
- console.log(`[INSPECTOR] UI available at http://localhost:${this.serverPort}/inspector`);
1202
+ console.log(`[INSPECTOR] UI available at http://${this.serverHost}:${this.serverPort}/inspector`);
839
1203
  }).catch(() => {
840
1204
  });
841
1205
  }
@@ -843,7 +1207,7 @@ var McpServer = class {
843
1207
  * Setup default widget serving routes
844
1208
  *
845
1209
  * Configures Express routes to serve MCP UI widgets and their static assets.
846
- * Widgets are served from the dist/resources/mcp-use/widgets directory and can
1210
+ * Widgets are served from the dist/resources/widgets directory and can
847
1211
  * be accessed via HTTP endpoints for embedding in web applications.
848
1212
  *
849
1213
  * Routes created:
@@ -864,12 +1228,12 @@ var McpServer = class {
864
1228
  this.app.get("/mcp-use/widgets/:widget/assets/*", (req, res, next) => {
865
1229
  const widget = req.params.widget;
866
1230
  const assetFile = req.params[0];
867
- const assetPath = (0, import_node_path.join)(process.cwd(), "dist", "resources", "mcp-use", "widgets", widget, "assets", assetFile);
1231
+ const assetPath = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets", widget, "assets", assetFile);
868
1232
  res.sendFile(assetPath, (err) => err ? next() : void 0);
869
1233
  });
870
1234
  this.app.get("/mcp-use/widgets/assets/*", (req, res, next) => {
871
1235
  const assetFile = req.params[0];
872
- const widgetsDir = (0, import_node_path.join)(process.cwd(), "dist", "resources", "mcp-use", "widgets");
1236
+ const widgetsDir = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets");
873
1237
  try {
874
1238
  const widgets = (0, import_node_fs.readdirSync)(widgetsDir);
875
1239
  for (const widget of widgets) {
@@ -884,7 +1248,7 @@ var McpServer = class {
884
1248
  }
885
1249
  });
886
1250
  this.app.get("/mcp-use/widgets/:widget", (req, res, next) => {
887
- const filePath = (0, import_node_path.join)(process.cwd(), "dist", "resources", "mcp-use", "widgets", req.params.widget, "index.html");
1251
+ const filePath = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets", req.params.widget, "index.html");
888
1252
  res.sendFile(filePath, (err) => err ? next() : void 0);
889
1253
  });
890
1254
  }
@@ -924,14 +1288,14 @@ var McpServer = class {
924
1288
  *
925
1289
  * @example
926
1290
  * ```typescript
927
- * const schema = this.createToolInputSchema([
928
- * { name: 'query', type: 'string', required: true },
1291
+ * const schema = this.createParamsSchema([
1292
+ * { name: 'query', type: 'string', required: true, description: 'Search query' },
929
1293
  * { name: 'limit', type: 'number', required: false }
930
1294
  * ])
931
- * // Returns: { query: z.string(), limit: z.number().optional() }
1295
+ * // Returns: { query: z.string().describe('Search query'), limit: z.number().optional() }
932
1296
  * ```
933
1297
  */
934
- createToolInputSchema(inputs) {
1298
+ createParamsSchema(inputs) {
935
1299
  const schema = {};
936
1300
  inputs.forEach((input) => {
937
1301
  let zodType;
@@ -1071,7 +1435,9 @@ function createMCPServer(name, config = {}) {
1071
1435
  const instance = new McpServer({
1072
1436
  name,
1073
1437
  version: config.version || "1.0.0",
1074
- description: config.description
1438
+ description: config.description,
1439
+ host: config.host,
1440
+ baseUrl: config.baseUrl
1075
1441
  });
1076
1442
  return instance;
1077
1443
  }