mcp-use 1.1.6 → 1.1.7

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.
@@ -9,6 +9,7 @@ import express from "express";
9
9
  import cors from "cors";
10
10
  import { existsSync, readdirSync } from "fs";
11
11
  import { join } from "path";
12
+ import { readFileSync } from "fs";
12
13
 
13
14
  // src/server/logging.ts
14
15
  function requestLogger(req, res, next) {
@@ -47,13 +48,8 @@ function buildWidgetUrl(widget, props, config) {
47
48
  `/mcp-use/widgets/${widget}`,
48
49
  `${config.baseUrl}:${config.port}`
49
50
  );
50
- if (props) {
51
- Object.entries(props).forEach(([key, value]) => {
52
- if (value !== void 0 && value !== null) {
53
- const stringValue = typeof value === "object" ? JSON.stringify(value) : String(value);
54
- url.searchParams.set(key, stringValue);
55
- }
56
- });
51
+ if (props && Object.keys(props).length > 0) {
52
+ url.searchParams.set("props", JSON.stringify(props));
57
53
  }
58
54
  return url.toString();
59
55
  }
@@ -153,6 +149,8 @@ function createUIResourceFromDefinition(definition, params, config) {
153
149
  __name(createUIResourceFromDefinition, "createUIResourceFromDefinition");
154
150
 
155
151
  // src/server/mcp-server.ts
152
+ import { createServer } from "vite";
153
+ var TMP_MCP_USE_DIR = ".mcp-use";
156
154
  var McpServer = class {
157
155
  static {
158
156
  __name(this, "McpServer");
@@ -163,6 +161,8 @@ var McpServer = class {
163
161
  mcpMounted = false;
164
162
  inspectorMounted = false;
165
163
  serverPort;
164
+ serverHost;
165
+ serverBaseUrl;
166
166
  /**
167
167
  * Creates a new MCP server instance with Express integration
168
168
  *
@@ -175,6 +175,8 @@ var McpServer = class {
175
175
  */
176
176
  constructor(config) {
177
177
  this.config = config;
178
+ this.serverHost = config.host || "localhost";
179
+ this.serverBaseUrl = config.baseUrl;
178
180
  this.server = new OfficialMcpServer({
179
181
  name: config.name,
180
182
  version: config.version
@@ -187,7 +189,6 @@ var McpServer = class {
187
189
  allowedHeaders: ["Content-Type", "Accept", "Authorization", "mcp-protocol-version", "mcp-session-id", "X-Proxy-Token", "X-Target-URL"]
188
190
  }));
189
191
  this.app.use(requestLogger);
190
- this.setupWidgetRoutes();
191
192
  return new Proxy(this, {
192
193
  get(target, prop) {
193
194
  if (prop in target) {
@@ -246,7 +247,8 @@ var McpServer = class {
246
247
  title: resourceDefinition.title,
247
248
  description: resourceDefinition.description,
248
249
  mimeType: resourceDefinition.mimeType,
249
- annotations: resourceDefinition.annotations
250
+ annotations: resourceDefinition.annotations,
251
+ _meta: resourceDefinition._meta
250
252
  },
251
253
  async () => {
252
254
  return await resourceDefinition.readCallback();
@@ -365,7 +367,7 @@ var McpServer = class {
365
367
  * ```
366
368
  */
367
369
  tool(toolDefinition) {
368
- const inputSchema = this.createToolInputSchema(toolDefinition.inputs || []);
370
+ const inputSchema = this.createParamsSchema(toolDefinition.inputs || []);
369
371
  this.server.registerTool(
370
372
  toolDefinition.name,
371
373
  {
@@ -416,7 +418,7 @@ var McpServer = class {
416
418
  * ```
417
419
  */
418
420
  prompt(promptDefinition) {
419
- const argsSchema = this.createPromptArgsSchema(promptDefinition.args || []);
421
+ const argsSchema = this.createParamsSchema(promptDefinition.args || []);
420
422
  this.server.registerPrompt(
421
423
  promptDefinition.name,
422
424
  {
@@ -443,19 +445,22 @@ var McpServer = class {
443
445
  * - remoteDom: Legacy MCP-UI Remote DOM scripting
444
446
  * - appsSdk: OpenAI Apps SDK compatible widgets (text/html+skybridge)
445
447
  *
446
- * @param definition - Configuration for the UI widget
448
+ * @param widgetNameOrDefinition - Widget name (string) for auto-loading schema, or full configuration object
447
449
  * @param definition.name - Unique identifier for the resource
448
450
  * @param definition.type - Type of UI resource (externalUrl, rawHtml, remoteDom, appsSdk)
449
451
  * @param definition.title - Human-readable title for the widget
450
452
  * @param definition.description - Description of the widget's functionality
451
453
  * @param definition.props - Widget properties configuration with types and defaults
452
- * @param definition.size - Preferred iframe size [width, height] (e.g., ['800px', '600px'])
454
+ * @param definition.size - Preferred iframe size [width, height] (e.g., ['900px', '600px'])
453
455
  * @param definition.annotations - Resource annotations for discovery
454
456
  * @param definition.appsSdkMetadata - Apps SDK specific metadata (CSP, widget description, etc.)
455
457
  * @returns The server instance for method chaining
456
458
  *
457
459
  * @example
458
460
  * ```typescript
461
+ * // Simple usage - auto-loads from generated schema
462
+ * server.uiResource('display-weather')
463
+ *
459
464
  * // Legacy MCP-UI widget
460
465
  * server.uiResource({
461
466
  * type: 'externalUrl',
@@ -495,14 +500,6 @@ var McpServer = class {
495
500
  * ```
496
501
  */
497
502
  uiResource(definition) {
498
- let toolName;
499
- if (definition.type === "appsSdk") {
500
- toolName = definition.name;
501
- } else if (definition.type === "externalUrl") {
502
- toolName = `ui_${definition.widget}`;
503
- } else {
504
- toolName = `ui_${definition.name}`;
505
- }
506
503
  const displayName = definition.title || definition.name;
507
504
  let resourceUri;
508
505
  let mimeType;
@@ -532,6 +529,7 @@ var McpServer = class {
532
529
  title: definition.title,
533
530
  description: definition.description,
534
531
  mimeType,
532
+ _meta: definition._meta,
535
533
  annotations: definition.annotations,
536
534
  readCallback: /* @__PURE__ */ __name(async () => {
537
535
  const params = definition.type === "externalUrl" ? this.applyDefaultProps(definition.props) : {};
@@ -541,7 +539,28 @@ var McpServer = class {
541
539
  };
542
540
  }, "readCallback")
543
541
  });
544
- const toolMetadata = {};
542
+ if (definition.type === "appsSdk") {
543
+ this.resourceTemplate({
544
+ name: `${definition.name}-dynamic`,
545
+ resourceTemplate: {
546
+ uriTemplate: `ui://widget/${definition.name}-{id}.html`,
547
+ name: definition.title || definition.name,
548
+ description: definition.description,
549
+ mimeType
550
+ },
551
+ _meta: definition._meta,
552
+ title: definition.title,
553
+ description: definition.description,
554
+ annotations: definition.annotations,
555
+ readCallback: /* @__PURE__ */ __name(async (uri, params) => {
556
+ const uiResource = this.createWidgetUIResource(definition, {});
557
+ return {
558
+ contents: [uiResource.resource]
559
+ };
560
+ }, "readCallback")
561
+ });
562
+ }
563
+ const toolMetadata = definition._meta || {};
545
564
  if (definition.type === "appsSdk" && definition.appsSdkMetadata) {
546
565
  toolMetadata["openai/outputTemplate"] = resourceUri;
547
566
  const toolMetadataFields = [
@@ -557,17 +576,19 @@ var McpServer = class {
557
576
  }
558
577
  }
559
578
  this.tool({
560
- name: toolName,
579
+ name: definition.name,
561
580
  title: definition.title,
562
- // For Apps SDK, use title as description to match OpenAI's pizzaz reference implementation
563
- description: definition.type === "appsSdk" && definition.title ? definition.title : definition.description || `Display ${displayName}`,
581
+ description: definition.description,
564
582
  inputs: this.convertPropsToInputs(definition.props),
565
583
  _meta: Object.keys(toolMetadata).length > 0 ? toolMetadata : void 0,
566
584
  cb: /* @__PURE__ */ __name(async (params) => {
567
585
  const uiResource = this.createWidgetUIResource(definition, params);
568
586
  if (definition.type === "appsSdk") {
587
+ const randomId = Math.random().toString(36).substring(2, 15);
588
+ const uniqueUri = `ui://widget/${definition.name}-${randomId}.html`;
589
+ const uniqueToolMetadata = { ...toolMetadata, "openai/outputTemplate": uniqueUri };
569
590
  return {
570
- _meta: toolMetadata,
591
+ _meta: uniqueToolMetadata,
571
592
  content: [
572
593
  {
573
594
  type: "text",
@@ -605,9 +626,20 @@ var McpServer = class {
605
626
  * @returns UIResource object compatible with MCP-UI
606
627
  */
607
628
  createWidgetUIResource(definition, params) {
629
+ let configBaseUrl = `http://${this.serverHost}`;
630
+ let configPort = this.serverPort || 3001;
631
+ if (this.serverBaseUrl) {
632
+ try {
633
+ const url = new URL(this.serverBaseUrl);
634
+ configBaseUrl = `${url.protocol}//${url.hostname}`;
635
+ configPort = url.port || (url.protocol === "https:" ? 443 : 80);
636
+ } catch (e) {
637
+ console.warn("Failed to parse baseUrl, falling back to host:port", e);
638
+ }
639
+ }
608
640
  const urlConfig = {
609
- baseUrl: "http://localhost",
610
- port: this.serverPort || 3001
641
+ baseUrl: configBaseUrl,
642
+ port: configPort
611
643
  };
612
644
  return createUIResourceFromDefinition(definition, params, urlConfig);
613
645
  }
@@ -624,7 +656,7 @@ var McpServer = class {
624
656
  * @returns Complete URL with encoded parameters
625
657
  */
626
658
  buildWidgetUrl(widget, params) {
627
- const baseUrl = `http://localhost:${this.serverPort}/mcp-use/widgets/${widget}`;
659
+ const baseUrl = `http://${this.serverHost}:${this.serverPort}/mcp-use/widgets/${widget}`;
628
660
  if (Object.keys(params).length === 0) {
629
661
  return baseUrl;
630
662
  }
@@ -680,6 +712,324 @@ var McpServer = class {
680
712
  }
681
713
  return defaults;
682
714
  }
715
+ /**
716
+ * Check if server is running in production mode
717
+ *
718
+ * @private
719
+ * @returns true if in production mode, false otherwise
720
+ */
721
+ isProductionMode() {
722
+ return process.env.NODE_ENV === "production";
723
+ }
724
+ /**
725
+ * Read build manifest file
726
+ *
727
+ * @private
728
+ * @returns Build manifest or null if not found
729
+ */
730
+ readBuildManifest() {
731
+ try {
732
+ const manifestPath = join(process.cwd(), "dist", ".mcp-use-manifest.json");
733
+ const content = readFileSync(manifestPath, "utf8");
734
+ return JSON.parse(content);
735
+ } catch {
736
+ return null;
737
+ }
738
+ }
739
+ /**
740
+ * Mount widget files - automatically chooses between dev and production mode
741
+ *
742
+ * In development mode: creates Vite dev servers with HMR support
743
+ * In production mode: serves pre-built static widgets
744
+ *
745
+ * @param options - Configuration options
746
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
747
+ * @param options.resourcesDir - Directory containing widget files (defaults to 'resources')
748
+ * @returns Promise that resolves when all widgets are mounted
749
+ */
750
+ async mountWidgets(options) {
751
+ if (this.isProductionMode()) {
752
+ await this.mountWidgetsProduction(options);
753
+ } else {
754
+ await this.mountWidgetsDev(options);
755
+ }
756
+ }
757
+ /**
758
+ * Mount individual widget files from resources/ directory in development mode
759
+ *
760
+ * Scans the resources/ directory for .tsx/.ts widget files and creates individual
761
+ * Vite dev servers for each widget with HMR support. Each widget is served at its
762
+ * own route: /mcp-use/widgets/{widget-name}
763
+ *
764
+ * @private
765
+ * @param options - Configuration options
766
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
767
+ * @param options.resourcesDir - Directory containing widget files (defaults to 'resources')
768
+ * @returns Promise that resolves when all widgets are mounted
769
+ */
770
+ async mountWidgetsDev(options) {
771
+ const { promises: fs } = await import("fs");
772
+ const baseRoute = options?.baseRoute || "/mcp-use/widgets";
773
+ const resourcesDir = options?.resourcesDir || "resources";
774
+ const srcDir = join(process.cwd(), resourcesDir);
775
+ try {
776
+ await fs.access(srcDir);
777
+ } catch (error) {
778
+ console.log(`[WIDGETS] No ${resourcesDir}/ directory found - skipping widget serving`);
779
+ return;
780
+ }
781
+ let entries = [];
782
+ try {
783
+ const files = await fs.readdir(srcDir);
784
+ entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => join(srcDir, f));
785
+ } catch (error) {
786
+ console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
787
+ return;
788
+ }
789
+ if (entries.length === 0) {
790
+ console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
791
+ return;
792
+ }
793
+ const tempDir = join(process.cwd(), TMP_MCP_USE_DIR);
794
+ await fs.mkdir(tempDir, { recursive: true }).catch(() => {
795
+ });
796
+ const react = (await import("@vitejs/plugin-react")).default;
797
+ const tailwindcss = (await import("@tailwindcss/vite")).default;
798
+ console.log(react, tailwindcss);
799
+ const widgets = entries.map((entry) => {
800
+ const baseName = entry.split("/").pop()?.replace(/\.tsx?$/, "") || "widget";
801
+ const widgetName = baseName;
802
+ return {
803
+ name: widgetName,
804
+ description: `Widget: ${widgetName}`,
805
+ entry
806
+ };
807
+ });
808
+ for (const widget of widgets) {
809
+ const widgetTempDir = join(tempDir, widget.name);
810
+ await fs.mkdir(widgetTempDir, { recursive: true });
811
+ const resourcesPath = join(process.cwd(), resourcesDir);
812
+ const { relative } = await import("path");
813
+ const relativeResourcesPath = relative(widgetTempDir, resourcesPath).replace(/\\/g, "/");
814
+ const cssContent = `@import "tailwindcss";
815
+
816
+ /* Configure Tailwind to scan the resources directory */
817
+ @source "${relativeResourcesPath}";
818
+ `;
819
+ await fs.writeFile(join(widgetTempDir, "styles.css"), cssContent, "utf8");
820
+ const entryContent = `import React from 'react'
821
+ import { createRoot } from 'react-dom/client'
822
+ import './styles.css'
823
+ import Component from '${widget.entry}'
824
+
825
+ const container = document.getElementById('widget-root')
826
+ if (container && Component) {
827
+ const root = createRoot(container)
828
+ root.render(<Component />)
829
+ }
830
+ `;
831
+ const htmlContent = `<!doctype html>
832
+ <html lang="en">
833
+ <head>
834
+ <meta charset="UTF-8" />
835
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
836
+ <title>${widget.name} Widget</title>
837
+ </head>
838
+ <body>
839
+ <div id="widget-root"></div>
840
+ <script type="module" src="${baseRoute}/${widget.name}/entry.tsx"></script>
841
+ </body>
842
+ </html>`;
843
+ await fs.writeFile(join(widgetTempDir, "entry.tsx"), entryContent, "utf8");
844
+ await fs.writeFile(join(widgetTempDir, "index.html"), htmlContent, "utf8");
845
+ }
846
+ const serverOrigin = this.serverBaseUrl || `http://${this.serverHost}:${this.serverPort}`;
847
+ console.log(`[WIDGETS] Serving ${entries.length} widget(s) with shared Vite dev server and HMR`);
848
+ const viteServer = await createServer({
849
+ root: tempDir,
850
+ base: baseRoute + "/",
851
+ plugins: [tailwindcss(), react()],
852
+ resolve: {
853
+ alias: {
854
+ "@": join(process.cwd(), resourcesDir)
855
+ }
856
+ },
857
+ server: {
858
+ middlewareMode: true,
859
+ origin: serverOrigin
860
+ }
861
+ });
862
+ this.app.use(baseRoute, (req, res, next) => {
863
+ const urlPath = req.url || "";
864
+ const [pathname, queryString] = urlPath.split("?");
865
+ const widgetMatch = pathname.match(/^\/([^/]+)/);
866
+ if (widgetMatch) {
867
+ const widgetName = widgetMatch[1];
868
+ const widget = widgets.find((w) => w.name === widgetName);
869
+ if (widget) {
870
+ if (pathname === `/${widgetName}` || pathname === `/${widgetName}/`) {
871
+ req.url = `/${widgetName}/index.html${queryString ? "?" + queryString : ""}`;
872
+ }
873
+ }
874
+ }
875
+ next();
876
+ });
877
+ this.app.use(baseRoute, viteServer.middlewares);
878
+ widgets.forEach((widget) => {
879
+ console.log(`[WIDGET] ${widget.name} mounted at ${baseRoute}/${widget.name}`);
880
+ });
881
+ for (const widget of widgets) {
882
+ const type = "appsSdk";
883
+ let widgetMetadata = {};
884
+ let props = {};
885
+ let description = widget.description;
886
+ try {
887
+ const mod = await viteServer.ssrLoadModule(widget.entry);
888
+ if (mod.widgetMetadata) {
889
+ widgetMetadata = mod.widgetMetadata;
890
+ description = widgetMetadata.description || widget.description;
891
+ if (widgetMetadata.inputs) {
892
+ try {
893
+ props = widgetMetadata.inputs.shape || {};
894
+ } catch (error) {
895
+ console.warn(`[WIDGET] Failed to extract props schema for ${widget.name}:`, error);
896
+ }
897
+ }
898
+ }
899
+ } catch (error) {
900
+ console.warn(`[WIDGET] Failed to load metadata for ${widget.name}:`, error);
901
+ }
902
+ let html = "";
903
+ try {
904
+ html = await readFileSync(join(tempDir, widget.name, "index.html"), "utf8");
905
+ } catch (error) {
906
+ console.error(`Failed to read html template for widget ${widget.name}`, error);
907
+ }
908
+ this.uiResource({
909
+ name: widget.name,
910
+ title: widget.name,
911
+ description,
912
+ type,
913
+ props,
914
+ _meta: {
915
+ "mcp-use/widget": {
916
+ name: widget.name,
917
+ description,
918
+ type,
919
+ props,
920
+ html,
921
+ dev: true
922
+ }
923
+ },
924
+ htmlTemplate: html,
925
+ appsSdkMetadata: {
926
+ "openai/widgetDescription": description,
927
+ "openai/toolInvocation/invoking": "Hand-tossing a map",
928
+ "openai/toolInvocation/invoked": "Served a fresh map",
929
+ "openai/widgetAccessible": true,
930
+ "openai/resultCanProduceWidget": true,
931
+ "openai/widgetCSP": {
932
+ connect_domains: [],
933
+ resource_domains: ["https://persistent.oaistatic.com"]
934
+ }
935
+ }
936
+ });
937
+ }
938
+ }
939
+ /**
940
+ * Mount pre-built widgets from dist/resources/widgets/ directory in production mode
941
+ *
942
+ * Serves static widget bundles that were built using the build command.
943
+ * Sets up Express routes to serve the HTML and asset files, then registers
944
+ * tools and resources for each widget.
945
+ *
946
+ * @private
947
+ * @param options - Configuration options
948
+ * @param options.baseRoute - Base route for widgets (defaults to '/mcp-use/widgets')
949
+ * @returns Promise that resolves when all widgets are mounted
950
+ */
951
+ async mountWidgetsProduction(options) {
952
+ const baseRoute = options?.baseRoute || "/mcp-use/widgets";
953
+ const widgetsDir = join(process.cwd(), "dist", "resources", "widgets");
954
+ if (!existsSync(widgetsDir)) {
955
+ console.log("[WIDGETS] No dist/resources/widgets/ directory found - skipping widget serving");
956
+ return;
957
+ }
958
+ this.setupWidgetRoutes();
959
+ const widgets = readdirSync(widgetsDir).filter((name) => {
960
+ const widgetPath = join(widgetsDir, name);
961
+ const indexPath = join(widgetPath, "index.html");
962
+ return existsSync(indexPath);
963
+ });
964
+ if (widgets.length === 0) {
965
+ console.log("[WIDGETS] No built widgets found in dist/resources/widgets/");
966
+ return;
967
+ }
968
+ console.log(`[WIDGETS] Serving ${widgets.length} pre-built widget(s) from dist/resources/widgets/`);
969
+ for (const widgetName of widgets) {
970
+ const widgetPath = join(widgetsDir, widgetName);
971
+ const indexPath = join(widgetPath, "index.html");
972
+ const metadataPath = join(widgetPath, "metadata.json");
973
+ let html = "";
974
+ try {
975
+ html = readFileSync(indexPath, "utf8");
976
+ } catch (error) {
977
+ console.error(`[WIDGET] Failed to read ${widgetName}/index.html:`, error);
978
+ continue;
979
+ }
980
+ let metadata = {};
981
+ let props = {};
982
+ let description = `Widget: ${widgetName}`;
983
+ try {
984
+ const metadataContent = readFileSync(metadataPath, "utf8");
985
+ metadata = JSON.parse(metadataContent);
986
+ if (metadata.description) {
987
+ description = metadata.description;
988
+ }
989
+ if (metadata.inputs) {
990
+ props = metadata.inputs;
991
+ }
992
+ } catch (error) {
993
+ console.log(`[WIDGET] No metadata found for ${widgetName}, using defaults`);
994
+ }
995
+ this.uiResource({
996
+ name: widgetName,
997
+ title: widgetName,
998
+ description,
999
+ type: "appsSdk",
1000
+ props,
1001
+ _meta: {
1002
+ "mcp-use/widget": {
1003
+ name: widgetName,
1004
+ description,
1005
+ type: "appsSdk",
1006
+ props,
1007
+ html,
1008
+ dev: false
1009
+ }
1010
+ },
1011
+ htmlTemplate: html,
1012
+ appsSdkMetadata: {
1013
+ "openai/widgetDescription": description,
1014
+ "openai/toolInvocation/invoking": `Loading ${widgetName}...`,
1015
+ "openai/toolInvocation/invoked": `${widgetName} ready`,
1016
+ "openai/widgetAccessible": true,
1017
+ "openai/resultCanProduceWidget": true,
1018
+ "openai/widgetCSP": {
1019
+ connect_domains: [],
1020
+ resource_domains: [
1021
+ "https://*.oaistatic.com",
1022
+ "https://*.unsplash.com",
1023
+ "https://*.oaiusercontent.com",
1024
+ // always also add the base url of the server
1025
+ ...this.serverBaseUrl ? [this.serverBaseUrl] : []
1026
+ ]
1027
+ }
1028
+ }
1029
+ });
1030
+ console.log(`[WIDGET] ${widgetName} mounted at ${baseRoute}/${widgetName}`);
1031
+ }
1032
+ }
683
1033
  /**
684
1034
  * Mount MCP server endpoints at /mcp
685
1035
  *
@@ -756,18 +1106,25 @@ var McpServer = class {
756
1106
  * @example
757
1107
  * ```typescript
758
1108
  * await server.listen(8080)
759
- * // Server now running at http://localhost:8080
1109
+ * // Server now running at http://localhost:8080 (or configured host)
760
1110
  * // MCP endpoints: http://localhost:8080/mcp
761
1111
  * // Inspector UI: http://localhost:8080/inspector
762
1112
  * ```
763
1113
  */
764
1114
  async listen(port) {
1115
+ this.serverPort = port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 3001);
1116
+ if (process.env.HOST) {
1117
+ this.serverHost = process.env.HOST;
1118
+ }
1119
+ await this.mountWidgets({
1120
+ baseRoute: "/mcp-use/widgets",
1121
+ resourcesDir: "resources"
1122
+ });
765
1123
  await this.mountMcp();
766
- this.serverPort = port || 3001;
767
1124
  this.mountInspector();
768
1125
  this.app.listen(this.serverPort, () => {
769
- console.log(`[SERVER] Listening on http://localhost:${this.serverPort}`);
770
- console.log(`[MCP] Endpoints: http://localhost:${this.serverPort}/mcp`);
1126
+ console.log(`[SERVER] Listening on http://${this.serverHost}:${this.serverPort}`);
1127
+ console.log(`[MCP] Endpoints: http://${this.serverHost}:${this.serverPort}/mcp`);
771
1128
  });
772
1129
  }
773
1130
  /**
@@ -794,10 +1151,17 @@ var McpServer = class {
794
1151
  */
795
1152
  mountInspector() {
796
1153
  if (this.inspectorMounted) return;
1154
+ if (this.isProductionMode()) {
1155
+ const manifest = this.readBuildManifest();
1156
+ if (!manifest?.includeInspector) {
1157
+ console.log("[INSPECTOR] Skipped in production (use --with-inspector flag during build)");
1158
+ return;
1159
+ }
1160
+ }
797
1161
  import("@mcp-use/inspector").then(({ mountInspector }) => {
798
1162
  mountInspector(this.app);
799
1163
  this.inspectorMounted = true;
800
- console.log(`[INSPECTOR] UI available at http://localhost:${this.serverPort}/inspector`);
1164
+ console.log(`[INSPECTOR] UI available at http://${this.serverHost}:${this.serverPort}/inspector`);
801
1165
  }).catch(() => {
802
1166
  });
803
1167
  }
@@ -805,7 +1169,7 @@ var McpServer = class {
805
1169
  * Setup default widget serving routes
806
1170
  *
807
1171
  * Configures Express routes to serve MCP UI widgets and their static assets.
808
- * Widgets are served from the dist/resources/mcp-use/widgets directory and can
1172
+ * Widgets are served from the dist/resources/widgets directory and can
809
1173
  * be accessed via HTTP endpoints for embedding in web applications.
810
1174
  *
811
1175
  * Routes created:
@@ -826,12 +1190,12 @@ var McpServer = class {
826
1190
  this.app.get("/mcp-use/widgets/:widget/assets/*", (req, res, next) => {
827
1191
  const widget = req.params.widget;
828
1192
  const assetFile = req.params[0];
829
- const assetPath = join(process.cwd(), "dist", "resources", "mcp-use", "widgets", widget, "assets", assetFile);
1193
+ const assetPath = join(process.cwd(), "dist", "resources", "widgets", widget, "assets", assetFile);
830
1194
  res.sendFile(assetPath, (err) => err ? next() : void 0);
831
1195
  });
832
1196
  this.app.get("/mcp-use/widgets/assets/*", (req, res, next) => {
833
1197
  const assetFile = req.params[0];
834
- const widgetsDir = join(process.cwd(), "dist", "resources", "mcp-use", "widgets");
1198
+ const widgetsDir = join(process.cwd(), "dist", "resources", "widgets");
835
1199
  try {
836
1200
  const widgets = readdirSync(widgetsDir);
837
1201
  for (const widget of widgets) {
@@ -846,7 +1210,7 @@ var McpServer = class {
846
1210
  }
847
1211
  });
848
1212
  this.app.get("/mcp-use/widgets/:widget", (req, res, next) => {
849
- const filePath = join(process.cwd(), "dist", "resources", "mcp-use", "widgets", req.params.widget, "index.html");
1213
+ const filePath = join(process.cwd(), "dist", "resources", "widgets", req.params.widget, "index.html");
850
1214
  res.sendFile(filePath, (err) => err ? next() : void 0);
851
1215
  });
852
1216
  }
@@ -886,14 +1250,14 @@ var McpServer = class {
886
1250
  *
887
1251
  * @example
888
1252
  * ```typescript
889
- * const schema = this.createToolInputSchema([
890
- * { name: 'query', type: 'string', required: true },
1253
+ * const schema = this.createParamsSchema([
1254
+ * { name: 'query', type: 'string', required: true, description: 'Search query' },
891
1255
  * { name: 'limit', type: 'number', required: false }
892
1256
  * ])
893
- * // Returns: { query: z.string(), limit: z.number().optional() }
1257
+ * // Returns: { query: z.string().describe('Search query'), limit: z.number().optional() }
894
1258
  * ```
895
1259
  */
896
- createToolInputSchema(inputs) {
1260
+ createParamsSchema(inputs) {
897
1261
  const schema = {};
898
1262
  inputs.forEach((input) => {
899
1263
  let zodType;
@@ -1033,7 +1397,9 @@ function createMCPServer(name, config = {}) {
1033
1397
  const instance = new McpServer({
1034
1398
  name,
1035
1399
  version: config.version || "1.0.0",
1036
- description: config.description
1400
+ description: config.description,
1401
+ host: config.host,
1402
+ baseUrl: config.baseUrl
1037
1403
  });
1038
1404
  return instance;
1039
1405
  }