@trops/dash-core 0.1.447 → 0.1.448

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.
@@ -424,6 +424,11 @@ const MCP_GET_CATALOG$1 = "mcp-get-catalog";
424
424
  const MCP_GET_CATALOG_COMPLETE = "mcp-get-catalog-complete";
425
425
  const MCP_GET_CATALOG_ERROR = "mcp-get-catalog-error";
426
426
 
427
+ const MCP_GET_KNOWN_EXTERNAL$1 = "mcp-get-known-external";
428
+
429
+ const MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM$2 = "mcp-install-known-external-confirm";
430
+ const MCP_INSTALL_KNOWN_EXTERNAL_RESULT$2 = "mcp-install-known-external-result";
431
+
427
432
  const MCP_RUN_AUTH$1 = "mcp-run-auth";
428
433
  const MCP_RUN_AUTH_COMPLETE = "mcp-run-auth-complete";
429
434
  const MCP_RUN_AUTH_ERROR = "mcp-run-auth-error";
@@ -453,6 +458,9 @@ var mcpEvents$1 = {
453
458
  MCP_GET_CATALOG: MCP_GET_CATALOG$1,
454
459
  MCP_GET_CATALOG_COMPLETE,
455
460
  MCP_GET_CATALOG_ERROR,
461
+ MCP_GET_KNOWN_EXTERNAL: MCP_GET_KNOWN_EXTERNAL$1,
462
+ MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM: MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM$2,
463
+ MCP_INSTALL_KNOWN_EXTERNAL_RESULT: MCP_INSTALL_KNOWN_EXTERNAL_RESULT$2,
456
464
  MCP_RUN_AUTH: MCP_RUN_AUTH$1,
457
465
  MCP_RUN_AUTH_COMPLETE,
458
466
  MCP_RUN_AUTH_ERROR,
@@ -5296,7 +5304,7 @@ const layoutController$1 = {
5296
5304
 
5297
5305
  var layoutController_1 = layoutController$1;
5298
5306
 
5299
- var mcpController$3 = {exports: {}};
5307
+ var mcpController$4 = {exports: {}};
5300
5308
 
5301
5309
  var streamableHttp$1 = {};
5302
5310
 
@@ -26032,7 +26040,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
26032
26040
  console.log("[mcpController] Google OAuth token refreshed successfully");
26033
26041
  }
26034
26042
 
26035
- const mcpController$2 = {
26043
+ const mcpController$3 = {
26036
26044
  /**
26037
26045
  * startServer
26038
26046
  * Start an MCP server with the given config and credentials
@@ -26070,13 +26078,13 @@ const mcpController$2 = {
26070
26078
  try {
26071
26079
  // Stop if in stale/error state
26072
26080
  if (activeServers.has(serverName)) {
26073
- await mcpController$2.stopServer(win, serverName);
26081
+ await mcpController$3.stopServer(win, serverName);
26074
26082
  }
26075
26083
 
26076
26084
  // Merge with catalog entry to pick up updated command/args
26077
26085
  // (saved provider config may reference a stale or archived package)
26078
26086
  try {
26079
- const { catalog } = mcpController$2.getCatalog(win);
26087
+ const { catalog } = mcpController$3.getCatalog(win);
26080
26088
  const catalogEntry = (catalog || []).find(
26081
26089
  (entry) => entry.name === serverName,
26082
26090
  );
@@ -26602,6 +26610,48 @@ const mcpController$2 = {
26602
26610
  }
26603
26611
  },
26604
26612
 
26613
+ /**
26614
+ * getKnownExternalCatalog
26615
+ * Load the curated allow-list of MCP servers known to exist outside the
26616
+ * built-in catalog. Used by the AI Widget Builder to suggest installable
26617
+ * servers and as the trust boundary for `install_known_mcp_server` —
26618
+ * the install tool will reject any id that doesn't appear here.
26619
+ *
26620
+ * @returns {{ success, servers } | { error, message, servers }}
26621
+ */
26622
+ getKnownExternalCatalog: () => {
26623
+ try {
26624
+ const catalogPath = path$c.join(
26625
+ __dirname,
26626
+ "..",
26627
+ "mcp",
26628
+ "knownExternalMcpServers.json",
26629
+ );
26630
+
26631
+ if (!fs$8.existsSync(catalogPath)) {
26632
+ return { success: true, servers: [] };
26633
+ }
26634
+
26635
+ const catalogData = fs$8.readFileSync(catalogPath, "utf8");
26636
+ const catalog = JSON.parse(catalogData);
26637
+
26638
+ return {
26639
+ success: true,
26640
+ servers: catalog.servers || [],
26641
+ };
26642
+ } catch (error) {
26643
+ console.error(
26644
+ "[mcpController] Error loading known-external catalog:",
26645
+ error,
26646
+ );
26647
+ return {
26648
+ error: true,
26649
+ message: error.message,
26650
+ servers: [],
26651
+ };
26652
+ }
26653
+ },
26654
+
26605
26655
  /**
26606
26656
  * listConnectedServers
26607
26657
  * Returns all connected servers with their cached tool lists.
@@ -26765,17 +26815,17 @@ const mcpController$2 = {
26765
26815
  );
26766
26816
  const promises = [];
26767
26817
  for (const [serverName] of activeServers) {
26768
- promises.push(mcpController$2.stopServer(null, serverName));
26818
+ promises.push(mcpController$3.stopServer(null, serverName));
26769
26819
  }
26770
26820
  await Promise.allSettled(promises);
26771
26821
  console.log("[mcpController] All servers stopped");
26772
26822
  },
26773
26823
  };
26774
26824
 
26775
- mcpController$3.exports = mcpController$2;
26776
- mcpController$3.exports.refreshGoogleOAuthToken = refreshGoogleOAuthToken;
26825
+ mcpController$4.exports = mcpController$3;
26826
+ mcpController$4.exports.refreshGoogleOAuthToken = refreshGoogleOAuthToken;
26777
26827
 
26778
- var mcpControllerExports = mcpController$3.exports;
26828
+ var mcpControllerExports = mcpController$4.exports;
26779
26829
 
26780
26830
  /**
26781
26831
  * Scoped package identity utilities.
@@ -51231,7 +51281,7 @@ var jsonSchemaToZod_1 = { jsonSchemaToZod: jsonSchemaToZod$1, jsonSchemaProperty
51231
51281
 
51232
51282
  const https$2 = require$$8$1;
51233
51283
  const { randomUUID } = require$$1$6;
51234
- const { BrowserWindow } = require$$0$1;
51284
+ const { BrowserWindow: BrowserWindow$1 } = require$$0$1;
51235
51285
  const { McpServer } = mcp;
51236
51286
  const {
51237
51287
  StreamableHTTPServerTransport,
@@ -51275,7 +51325,7 @@ function broadcastStateChanged(toolName, result) {
51275
51325
  /* leave null */
51276
51326
  }
51277
51327
  const payload = { toolName, result: parsed };
51278
- for (const win of BrowserWindow.getAllWindows()) {
51328
+ for (const win of BrowserWindow$1.getAllWindows()) {
51279
51329
  if (!win.isDestroyed()) {
51280
51330
  try {
51281
51331
  win.webContents.send("dash-mcp:state-changed", payload);
@@ -51341,7 +51391,7 @@ const registeredPrompts = [];
51341
51391
  * Register a tool to be exposed via the MCP server.
51342
51392
  * Call this before starting the server (or restart after registering).
51343
51393
  */
51344
- function registerTool$6(toolDef) {
51394
+ function registerTool$7(toolDef) {
51345
51395
  registeredTools.push(toolDef);
51346
51396
  }
51347
51397
 
@@ -51722,7 +51772,7 @@ const mcpDashServerController$4 = {
51722
51772
  },
51723
51773
 
51724
51774
  // Expose registration functions for other controllers
51725
- registerTool: registerTool$6,
51775
+ registerTool: registerTool$7,
51726
51776
  registerResource: registerResource$1,
51727
51777
  registerPrompt: registerPrompt$1,
51728
51778
  getServerContext,
@@ -61842,7 +61892,7 @@ async function handleListProviders$1() {
61842
61892
  * add_provider — Adds a new provider with encrypted credentials.
61843
61893
  * Credentials are accepted on input but never returned in the response.
61844
61894
  */
61845
- async function handleAddProvider$1({
61895
+ async function handleAddProvider$2({
61846
61896
  name,
61847
61897
  type,
61848
61898
  providerClass,
@@ -62667,7 +62717,7 @@ var toolHandlers$1 = {
62667
62717
  handleSearchRegistryThemes: handleSearchRegistryThemes$1,
62668
62718
  handleSearchRegistryDashboards: handleSearchRegistryDashboards$1,
62669
62719
  handleListProviders: handleListProviders$1,
62670
- handleAddProvider: handleAddProvider$1,
62720
+ handleAddProvider: handleAddProvider$2,
62671
62721
  handleRemoveProvider: handleRemoveProvider$1,
62672
62722
  handleGetSetupGuide: handleGetSetupGuide$1,
62673
62723
  handleSetLayout: handleSetLayout$1,
@@ -62692,7 +62742,7 @@ var toolHandlers$1 = {
62692
62742
  */
62693
62743
 
62694
62744
  const Anthropic = require$$0$9;
62695
- const mcpController$1 = mcpControllerExports;
62745
+ const mcpController$2 = mcpControllerExports;
62696
62746
  const cliController$1 = cliController_1;
62697
62747
  const toolDefinitions = toolDefinitions$1;
62698
62748
  const toolHandlers = toolHandlers$1;
@@ -62988,7 +63038,7 @@ const llmController$1 = {
62988
63038
  isError = true;
62989
63039
  } else {
62990
63040
  try {
62991
- const mcpResult = await mcpController$1.callTool(
63041
+ const mcpResult = await mcpController$2.callTool(
62992
63042
  win,
62993
63043
  serverName,
62994
63044
  toolBlock.name,
@@ -75880,6 +75930,9 @@ const {
75880
75930
  MCP_READ_RESOURCE,
75881
75931
  MCP_SERVER_STATUS,
75882
75932
  MCP_GET_CATALOG,
75933
+ MCP_GET_KNOWN_EXTERNAL,
75934
+ MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM: MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM$1,
75935
+ MCP_INSTALL_KNOWN_EXTERNAL_RESULT: MCP_INSTALL_KNOWN_EXTERNAL_RESULT$1,
75883
75936
  MCP_RUN_AUTH,
75884
75937
  } = events$8;
75885
75938
 
@@ -75976,6 +76029,45 @@ const mcpApi$2 = {
75976
76029
  */
75977
76030
  getCatalog: () => ipcRenderer$i.invoke(MCP_GET_CATALOG),
75978
76031
 
76032
+ /**
76033
+ * getKnownExternalCatalog
76034
+ * Load the curated allow-list of MCP servers known to exist outside the
76035
+ * built-in catalog. The AI Widget Builder reads this to advertise
76036
+ * "you can install <X> via Add Custom MCP" and as the trust boundary
76037
+ * for the `install_known_mcp_server` dash MCP tool — only ids in this
76038
+ * list are installable via that path.
76039
+ *
76040
+ * @returns {Promise<{ success, servers } | { error, message, servers }>}
76041
+ */
76042
+ getKnownExternalCatalog: () => ipcRenderer$i.invoke(MCP_GET_KNOWN_EXTERNAL),
76043
+
76044
+ /**
76045
+ * onInstallKnownExternalConfirm
76046
+ * Subscribe to install-confirm requests emitted by the dash MCP server
76047
+ * tool `install_known_mcp_server`. The renderer renders a confirmation
76048
+ * modal and replies with { confirmed, credentials } via
76049
+ * sendInstallKnownExternalResult().
76050
+ *
76051
+ * @param {(payload: { id, requestId, server }) => void} callback
76052
+ * @returns {() => void} cleanup
76053
+ */
76054
+ onInstallKnownExternalConfirm: (callback) => {
76055
+ const handler = (_e, data) => callback(data);
76056
+ ipcRenderer$i.on(MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM$1, handler);
76057
+ return () =>
76058
+ ipcRenderer$i.removeListener(MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM$1, handler);
76059
+ },
76060
+
76061
+ /**
76062
+ * sendInstallKnownExternalResult
76063
+ * Reply to a confirm request with the user's decision + credentials.
76064
+ *
76065
+ * @param {string} requestId
76066
+ * @param {{ confirmed: boolean, credentials?: object, error?: string }} result
76067
+ */
76068
+ sendInstallKnownExternalResult: (requestId, result) =>
76069
+ ipcRenderer$i.send(MCP_INSTALL_KNOWN_EXTERNAL_RESULT$1, { requestId, result }),
76070
+
75979
76071
  /**
75980
76072
  * runAuth
75981
76073
  * Run a one-shot auth command for an MCP server (e.g., OAuth browser flow)
@@ -77284,7 +77376,7 @@ var mcpDashServerApi_1 = mcpDashServerApi$2;
77284
77376
  * Call registerDashboardTools() during app startup (before or after server start).
77285
77377
  */
77286
77378
 
77287
- const { registerTool: registerTool$5 } = mcpDashServerController_1;
77379
+ const { registerTool: registerTool$6 } = mcpDashServerController_1;
77288
77380
  const { dashboardTools } = toolDefinitions$1;
77289
77381
  const {
77290
77382
  handleListDashboards,
@@ -77315,7 +77407,7 @@ function registerDashboardTools$1() {
77315
77407
  console.warn(`[dashboardTools] No handler found for tool: ${tool.name}`);
77316
77408
  continue;
77317
77409
  }
77318
- registerTool$5({
77410
+ registerTool$6({
77319
77411
  name: tool.name,
77320
77412
  description: tool.description,
77321
77413
  inputSchema: tool.inputSchema,
@@ -77336,7 +77428,7 @@ var dashboardTools_1 = { registerDashboardTools: registerDashboardTools$1 };
77336
77428
  * Call registerWidgetTools() during app startup (before or after server start).
77337
77429
  */
77338
77430
 
77339
- const { registerTool: registerTool$4 } = mcpDashServerController_1;
77431
+ const { registerTool: registerTool$5 } = mcpDashServerController_1;
77340
77432
  const { widgetTools } = toolDefinitions$1;
77341
77433
  const {
77342
77434
  handleAddWidget,
@@ -77367,7 +77459,7 @@ function registerWidgetTools$1() {
77367
77459
  console.warn(`[widgetTools] No handler found for tool: ${tool.name}`);
77368
77460
  continue;
77369
77461
  }
77370
- registerTool$4({
77462
+ registerTool$5({
77371
77463
  name: tool.name,
77372
77464
  description: tool.description,
77373
77465
  inputSchema: tool.inputSchema,
@@ -77386,7 +77478,7 @@ var widgetTools_1 = { registerWidgetTools: registerWidgetTools$1 };
77386
77478
  * Call registerThemeTools() during app startup (before or after server start).
77387
77479
  */
77388
77480
 
77389
- const { registerTool: registerTool$3 } = mcpDashServerController_1;
77481
+ const { registerTool: registerTool$4 } = mcpDashServerController_1;
77390
77482
  const { themeTools } = toolDefinitions$1;
77391
77483
  const {
77392
77484
  handleListThemes,
@@ -77417,7 +77509,7 @@ function registerThemeTools$1() {
77417
77509
  console.warn(`[themeTools] No handler found for tool: ${tool.name}`);
77418
77510
  continue;
77419
77511
  }
77420
- registerTool$3({
77512
+ registerTool$4({
77421
77513
  name: tool.name,
77422
77514
  description: tool.description,
77423
77515
  inputSchema: tool.inputSchema,
@@ -77436,18 +77528,18 @@ var themeTools_1 = { registerThemeTools: registerThemeTools$1 };
77436
77528
  * Call registerProviderTools() during app startup (before or after server start).
77437
77529
  */
77438
77530
 
77439
- const { registerTool: registerTool$2 } = mcpDashServerController_1;
77531
+ const { registerTool: registerTool$3 } = mcpDashServerController_1;
77440
77532
  const { providerTools } = toolDefinitions$1;
77441
77533
  const {
77442
77534
  handleListProviders,
77443
- handleAddProvider,
77535
+ handleAddProvider: handleAddProvider$1,
77444
77536
  handleRemoveProvider,
77445
77537
  } = toolHandlers$1;
77446
77538
 
77447
77539
  // Map tool names to handler functions
77448
77540
  const handlerMap$4 = {
77449
77541
  list_providers: handleListProviders,
77450
- add_provider: handleAddProvider,
77542
+ add_provider: handleAddProvider$1,
77451
77543
  remove_provider: handleRemoveProvider,
77452
77544
  };
77453
77545
 
@@ -77461,7 +77553,7 @@ function registerProviderTools$1() {
77461
77553
  console.warn(`[providerTools] No handler found for tool: ${tool.name}`);
77462
77554
  continue;
77463
77555
  }
77464
- registerTool$2({
77556
+ registerTool$3({
77465
77557
  name: tool.name,
77466
77558
  description: tool.description,
77467
77559
  inputSchema: tool.inputSchema,
@@ -77482,7 +77574,7 @@ var providerTools_1 = { registerProviderTools: registerProviderTools$1 };
77482
77574
  * Call registerGuideTools() during app startup.
77483
77575
  */
77484
77576
 
77485
- const { registerTool: registerTool$1 } = mcpDashServerController_1;
77577
+ const { registerTool: registerTool$2 } = mcpDashServerController_1;
77486
77578
  const { guideTools } = toolDefinitions$1;
77487
77579
  const { handleGetSetupGuide } = toolHandlers$1;
77488
77580
 
@@ -77497,7 +77589,7 @@ function registerGuideTools$1() {
77497
77589
  console.warn(`[guideTools] No handler found for tool: ${tool.name}`);
77498
77590
  continue;
77499
77591
  }
77500
- registerTool$1({
77592
+ registerTool$2({
77501
77593
  name: tool.name,
77502
77594
  description: tool.description,
77503
77595
  inputSchema: tool.inputSchema,
@@ -77516,7 +77608,7 @@ var guideTools_1 = { registerGuideTools: registerGuideTools$1 };
77516
77608
  * Call registerLayoutTools() during app startup (before or after server start).
77517
77609
  */
77518
77610
 
77519
- const { registerTool } = mcpDashServerController_1;
77611
+ const { registerTool: registerTool$1 } = mcpDashServerController_1;
77520
77612
  const { layoutTools } = toolDefinitions$1;
77521
77613
  const {
77522
77614
  handleSetLayout,
@@ -77540,7 +77632,7 @@ function registerLayoutTools$1() {
77540
77632
  console.warn(`[layoutTools] No handler found for tool: ${tool.name}`);
77541
77633
  continue;
77542
77634
  }
77543
- registerTool({
77635
+ registerTool$1({
77544
77636
  name: tool.name,
77545
77637
  description: tool.description,
77546
77638
  inputSchema: tool.inputSchema,
@@ -77552,6 +77644,194 @@ function registerLayoutTools$1() {
77552
77644
 
77553
77645
  var layoutTools_1 = { registerLayoutTools: registerLayoutTools$1 };
77554
77646
 
77647
+ /**
77648
+ * installExternalMcpTool.js
77649
+ *
77650
+ * Registers the `install_known_mcp_server` tool on Dash's own MCP server.
77651
+ *
77652
+ * Why this tool exists:
77653
+ * The AI Widget Builder asks Claude to use MCP-first when a user requests
77654
+ * a widget for an external service. The built-in catalog covers 13 servers;
77655
+ * for anything else the AI consults the curated allow-list at
77656
+ * `electron/mcp/knownExternalMcpServers.json`. To keep the user in control
77657
+ * (npm install + spawning a child process is a non-trivial trust grant),
77658
+ * the actual install is gated by a renderer-side confirmation modal: this
77659
+ * tool emits an IPC event with the curated entry, waits for the user's
77660
+ * response, and only then routes through the existing add-provider flow.
77661
+ *
77662
+ * Trust boundary: the `id` argument MUST match an entry in
77663
+ * knownExternalMcpServers.json. Any other id is rejected before the
77664
+ * confirmation modal is even shown.
77665
+ *
77666
+ * Returns one of:
77667
+ * - { success: true, name } — installed
77668
+ * - { success: false, declined } — user clicked Cancel
77669
+ * - { success: false, error } — id not in allow-list, IPC timeout, or
77670
+ * install error from add-provider flow
77671
+ */
77672
+
77673
+ const { BrowserWindow } = require$$0$1;
77674
+ const { registerTool } = mcpDashServerController_1;
77675
+ const mcpController$1 = mcpControllerExports;
77676
+ const {
77677
+ MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM,
77678
+ MCP_INSTALL_KNOWN_EXTERNAL_RESULT,
77679
+ } = mcpEvents$1;
77680
+ const { handleAddProvider } = toolHandlers$1;
77681
+ const { ipcMain } = require$$0$1;
77682
+
77683
+ const CONFIRM_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes — user may stop to read
77684
+
77685
+ // Pending requests keyed by requestId so we can resolve when the result IPC arrives.
77686
+ const pendingRequests = new Map();
77687
+
77688
+ let resultListenerInstalled = false;
77689
+ function ensureResultListener() {
77690
+ if (resultListenerInstalled) return;
77691
+ resultListenerInstalled = true;
77692
+ ipcMain.on(MCP_INSTALL_KNOWN_EXTERNAL_RESULT, (_event, payload) => {
77693
+ const { requestId, result } = payload || {};
77694
+ const pending = pendingRequests.get(requestId);
77695
+ if (!pending) return;
77696
+ pendingRequests.delete(requestId);
77697
+ clearTimeout(pending.timer);
77698
+ pending.resolve(result || { confirmed: false });
77699
+ });
77700
+ }
77701
+
77702
+ function findEntryInAllowList(id) {
77703
+ const { servers } = mcpController$1.getKnownExternalCatalog();
77704
+ if (!Array.isArray(servers)) return null;
77705
+ return servers.find((s) => s && s.id === id) || null;
77706
+ }
77707
+
77708
+ function newRequestId() {
77709
+ return `mcp-install-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
77710
+ }
77711
+
77712
+ async function awaitUserConfirmation(server) {
77713
+ ensureResultListener();
77714
+ const requestId = newRequestId();
77715
+ return new Promise((resolve) => {
77716
+ const timer = setTimeout(() => {
77717
+ if (pendingRequests.has(requestId)) {
77718
+ pendingRequests.delete(requestId);
77719
+ resolve({ confirmed: false, error: "Install confirmation timed out" });
77720
+ }
77721
+ }, CONFIRM_TIMEOUT_MS);
77722
+ pendingRequests.set(requestId, { resolve, timer });
77723
+
77724
+ // Broadcast to all open windows; whichever has the modal mounted picks it up.
77725
+ const wins = BrowserWindow.getAllWindows();
77726
+ if (wins.length === 0) {
77727
+ pendingRequests.delete(requestId);
77728
+ clearTimeout(timer);
77729
+ resolve({ confirmed: false, error: "No window available" });
77730
+ return;
77731
+ }
77732
+ for (const win of wins) {
77733
+ if (!win.isDestroyed()) {
77734
+ win.webContents.send(MCP_INSTALL_KNOWN_EXTERNAL_CONFIRM, {
77735
+ requestId,
77736
+ id: server.id,
77737
+ server,
77738
+ });
77739
+ }
77740
+ }
77741
+ });
77742
+ }
77743
+
77744
+ function ok(payload) {
77745
+ return {
77746
+ content: [{ type: "text", text: JSON.stringify(payload) }],
77747
+ };
77748
+ }
77749
+
77750
+ function fail(payload) {
77751
+ return {
77752
+ content: [{ type: "text", text: JSON.stringify(payload) }],
77753
+ isError: true,
77754
+ };
77755
+ }
77756
+
77757
+ async function handleInstallKnownMcpServer({ id, name }) {
77758
+ if (!id || typeof id !== "string") {
77759
+ return fail({ success: false, error: "id is required" });
77760
+ }
77761
+ const server = findEntryInAllowList(id);
77762
+ if (!server) {
77763
+ return fail({
77764
+ success: false,
77765
+ error: `id "${id}" is not in the known-external MCP allow-list. The user can only install servers explicitly listed in knownExternalMcpServers.json.`,
77766
+ });
77767
+ }
77768
+
77769
+ const decision = await awaitUserConfirmation(server);
77770
+ if (!decision || !decision.confirmed) {
77771
+ if (decision?.error) {
77772
+ return fail({ success: false, error: decision.error });
77773
+ }
77774
+ return ok({ success: false, declined: true });
77775
+ }
77776
+
77777
+ // Route through the existing add-provider tool handler. The renderer
77778
+ // collected credentials in its modal — we trust those to match the
77779
+ // curated `credentialSchema`.
77780
+ const providerName = (name && name.trim()) || server.name || server.id;
77781
+ try {
77782
+ const addResult = await handleAddProvider({
77783
+ name: providerName,
77784
+ type: server.id,
77785
+ providerClass: "mcp",
77786
+ credentials: decision.credentials || {},
77787
+ mcpConfig: server.mcpConfig,
77788
+ });
77789
+ if (addResult?.isError) {
77790
+ // Surface add-provider's error text verbatim.
77791
+ return addResult;
77792
+ }
77793
+ return ok({ success: true, name: providerName, type: server.id });
77794
+ } catch (err) {
77795
+ return fail({ success: false, error: err.message });
77796
+ }
77797
+ }
77798
+
77799
+ const installExternalMcpToolDef = {
77800
+ name: "install_known_mcp_server",
77801
+ description:
77802
+ "Install an MCP server from Dash's curated known-external allow-list. The user is shown a confirmation modal before any install runs. Use this when the user asks for a widget that needs a service NOT in the built-in MCP catalog but IS in the known-external list. Returns { success, name } on install, { success: false, declined: true } if the user cancels, or an error if the id isn't allow-listed.",
77803
+ inputSchema: {
77804
+ type: "object",
77805
+ properties: {
77806
+ id: {
77807
+ type: "string",
77808
+ description:
77809
+ "The id of the server in the known-external catalog (e.g. 'trello', 'asana', 'stripe').",
77810
+ },
77811
+ name: {
77812
+ type: "string",
77813
+ description:
77814
+ "Optional display name for the resulting provider entry. Defaults to the catalog entry's name.",
77815
+ },
77816
+ },
77817
+ required: ["id"],
77818
+ },
77819
+ };
77820
+
77821
+ function registerInstallKnownMcpServerTool$1() {
77822
+ registerTool({
77823
+ ...installExternalMcpToolDef,
77824
+ handler: handleInstallKnownMcpServer,
77825
+ });
77826
+ console.log("[installExternalMcpTool] Registered install_known_mcp_server");
77827
+ }
77828
+
77829
+ var installExternalMcpTool = {
77830
+ registerInstallKnownMcpServerTool: registerInstallKnownMcpServerTool$1,
77831
+ // Exported for tests
77832
+ handleInstallKnownMcpServer,
77833
+ };
77834
+
77555
77835
  /**
77556
77836
  * resourceDefinitions.js
77557
77837
  *
@@ -78522,6 +78802,9 @@ const { registerThemeTools } = themeTools_1;
78522
78802
  const { registerProviderTools } = providerTools_1;
78523
78803
  const { registerGuideTools } = guideTools_1;
78524
78804
  const { registerLayoutTools } = layoutTools_1;
78805
+ const {
78806
+ registerInstallKnownMcpServerTool,
78807
+ } = installExternalMcpTool;
78525
78808
  const { registerResources } = resources;
78526
78809
  const { registerPrompts } = promptRegistration;
78527
78810
  registerDashboardTools();
@@ -78530,6 +78813,7 @@ registerThemeTools();
78530
78813
  registerProviderTools();
78531
78814
  registerGuideTools();
78532
78815
  registerLayoutTools();
78816
+ registerInstallKnownMcpServerTool();
78533
78817
  registerResources();
78534
78818
  registerPrompts();
78535
78819