@burtson-labs/bandit-engine 2.0.107 → 2.0.108

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.
@@ -4,7 +4,7 @@ import {
4
4
  getHighlightTree,
5
5
  markdownSanitizeSchema,
6
6
  renderLowlightChildren
7
- } from "./chunk-VIKZPBVO.mjs";
7
+ } from "./chunk-3WKPBIRD.mjs";
8
8
 
9
9
  // src/components/StreamingMarkdown.tsx
10
10
  import React, { useEffect, useMemo, useRef, useState } from "react";
@@ -495,4 +495,4 @@ var StreamingMarkdown_default = React.memo(StreamingMarkdown, arePropsEqual);
495
495
  export {
496
496
  StreamingMarkdown_default
497
497
  };
498
- //# sourceMappingURL=chunk-KYC7CC6C.mjs.map
498
+ //# sourceMappingURL=chunk-VR2ZWFTN.mjs.map
@@ -24,7 +24,7 @@ import {
24
24
  useNotificationService,
25
25
  useTTS,
26
26
  useVoiceStore
27
- } from "./chunk-VIKZPBVO.mjs";
27
+ } from "./chunk-3WKPBIRD.mjs";
28
28
  import {
29
29
  brandingService_default,
30
30
  toTitleCase,
@@ -2803,4 +2803,4 @@ export {
2803
2803
  MAX_WINDOWED_HEIGHT,
2804
2804
  chat_modal_default
2805
2805
  };
2806
- //# sourceMappingURL=chunk-RN3AKXKI.mjs.map
2806
+ //# sourceMappingURL=chunk-XPNXECXM.mjs.map
package/dist/index.js CHANGED
@@ -43658,15 +43658,85 @@ init_mcpServersService();
43658
43658
  init_mcpToolsStore();
43659
43659
  var import_jsx_runtime50 = require("react/jsx-runtime");
43660
43660
  var emptyForm = { name: "", url: "", authType: "none", authValue: "", headerName: "" };
43661
+ var CATALOG = [
43662
+ {
43663
+ key: "linear",
43664
+ name: "Linear",
43665
+ blurb: "Create and track issues, projects, and cycles",
43666
+ letter: "L",
43667
+ accent: "#5E6AD2",
43668
+ url: "https://mcp.linear.app/sse",
43669
+ authType: "bearer",
43670
+ tokenLabel: "Linear API key",
43671
+ tokenHelp: "https://linear.app/settings/api"
43672
+ },
43673
+ {
43674
+ key: "notion",
43675
+ name: "Notion",
43676
+ blurb: "Search and update pages across your workspace",
43677
+ letter: "N",
43678
+ accent: "#0f0f0f",
43679
+ url: "https://mcp.notion.com/mcp",
43680
+ authType: "bearer",
43681
+ tokenLabel: "Notion integration token",
43682
+ tokenHelp: "https://www.notion.so/my-integrations"
43683
+ },
43684
+ {
43685
+ key: "github",
43686
+ name: "GitHub",
43687
+ blurb: "Issues, pull requests, code search, and actions",
43688
+ letter: "G",
43689
+ accent: "#24292f",
43690
+ url: "https://api.githubcopilot.com/mcp/",
43691
+ authType: "bearer",
43692
+ tokenLabel: "GitHub personal access token",
43693
+ tokenHelp: "https://github.com/settings/tokens"
43694
+ },
43695
+ {
43696
+ key: "sentry",
43697
+ name: "Sentry",
43698
+ blurb: "Triage errors and inspect production issues",
43699
+ letter: "S",
43700
+ accent: "#362D59",
43701
+ url: "https://mcp.sentry.dev/mcp",
43702
+ authType: "bearer",
43703
+ tokenLabel: "Sentry auth token",
43704
+ tokenHelp: "https://sentry.io/settings/auth-tokens/"
43705
+ },
43706
+ {
43707
+ key: "atlassian",
43708
+ name: "Jira & Confluence",
43709
+ blurb: "Atlassian issues, boards, and docs",
43710
+ letter: "J",
43711
+ accent: "#0052CC",
43712
+ url: "https://mcp.atlassian.com/v1/sse",
43713
+ authType: "bearer",
43714
+ tokenLabel: "Atlassian API token",
43715
+ tokenHelp: "https://id.atlassian.com/manage-profile/security/api-tokens"
43716
+ },
43717
+ {
43718
+ key: "stripe",
43719
+ name: "Stripe",
43720
+ blurb: "Payments, customers, and invoices",
43721
+ letter: "S",
43722
+ accent: "#635BFF",
43723
+ url: "https://mcp.stripe.com",
43724
+ authType: "bearer",
43725
+ tokenLabel: "Stripe restricted key",
43726
+ tokenHelp: "https://dashboard.stripe.com/apikeys"
43727
+ }
43728
+ ];
43661
43729
  var McpServersSection = () => {
43662
43730
  const [servers, setServers] = (0, import_react60.useState)([]);
43663
43731
  const [loading, setLoading] = (0, import_react60.useState)(false);
43664
43732
  const [error, setError] = (0, import_react60.useState)(null);
43665
43733
  const [form, setForm] = (0, import_react60.useState)(emptyForm);
43734
+ const [activeEntry, setActiveEntry] = (0, import_react60.useState)(null);
43666
43735
  const [adding, setAdding] = (0, import_react60.useState)(false);
43667
43736
  const [showForm, setShowForm] = (0, import_react60.useState)(false);
43668
43737
  const [tools, setTools] = (0, import_react60.useState)({});
43669
43738
  const reloadChatTools = useMCPToolsStore((s) => s.loadMcpServerTools);
43739
+ const formRef = (0, import_react60.useRef)(null);
43670
43740
  const refresh = (0, import_react60.useCallback)(async () => {
43671
43741
  setLoading(true);
43672
43742
  setError(null);
@@ -43681,6 +43751,20 @@ var McpServersSection = () => {
43681
43751
  (0, import_react60.useEffect)(() => {
43682
43752
  refresh();
43683
43753
  }, [refresh]);
43754
+ const connectedKeys = new Set(servers.map((s) => s.url.replace(/\/+$/, "")));
43755
+ const openForCatalog = (entry) => {
43756
+ setActiveEntry(entry);
43757
+ setForm({ name: entry.name, url: entry.url, authType: entry.authType, authValue: "", headerName: "" });
43758
+ setShowForm(true);
43759
+ setError(null);
43760
+ requestAnimationFrame(() => formRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }));
43761
+ };
43762
+ const openCustom = () => {
43763
+ setActiveEntry(null);
43764
+ setForm(emptyForm);
43765
+ setShowForm((v) => !v);
43766
+ setError(null);
43767
+ };
43684
43768
  const handleAdd = async () => {
43685
43769
  if (!form.name.trim() || !form.url.trim()) {
43686
43770
  setError("Name and URL are required.");
@@ -43697,6 +43781,7 @@ var McpServersSection = () => {
43697
43781
  headerName: form.authType === "header" ? form.headerName : void 0
43698
43782
  });
43699
43783
  setForm(emptyForm);
43784
+ setActiveEntry(null);
43700
43785
  setShowForm(false);
43701
43786
  await refresh();
43702
43787
  void reloadChatTools();
@@ -43735,101 +43820,185 @@ var McpServersSection = () => {
43735
43820
  setTools((prev) => ({ ...prev, [id]: { error: e instanceof Error ? e.message : "Could not connect." } }));
43736
43821
  }
43737
43822
  };
43738
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Paper, { sx: { p: 2, mb: 2 }, children: [
43739
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1, gap: 1, flexWrap: "wrap" }, children: [
43740
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43741
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(CloudIcon, {}),
43742
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "subtitle1", sx: { fontWeight: 700 }, children: "MCP Servers" }),
43743
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Chip, { size: "small", label: String(servers.length) })
43744
- ] }),
43745
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
43746
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.IconButton, { onClick: refresh, size: "small", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(RefreshIcon, {}) }) }),
43747
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Button, { size: "small", variant: "contained", startIcon: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(AddIcon, {}), onClick: () => setShowForm((v) => !v), children: "Add server" })
43748
- ] })
43823
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { children: [
43824
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { mb: 2.5 }, children: [
43825
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "h6", sx: { fontWeight: 700, mb: 0.5 }, children: "Connect your tools" }),
43826
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "body2", color: "text.secondary", sx: { maxWidth: 680, lineHeight: 1.6 }, children: "Let Bandit work inside the apps you already use \u2014 open a Linear issue, search Notion, or triage a Sentry error right from chat. Connect a service once; the gateway holds the connection securely, so your browser never talks to it directly." })
43749
43827
  ] }),
43750
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: "Connect a remote Model Context Protocol server to give the assistant its tools. The gateway holds the connection and proxies calls \u2014 your browser never talks to the server directly." }),
43751
43828
  error && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Alert, { severity: "error", sx: { mb: 2 }, onClose: () => setError(null), children: error }),
43752
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Collapse, { in: showForm, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Paper, { variant: "outlined", sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Stack, { spacing: 2, children: [
43753
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43754
- import_material50.TextField,
43755
- {
43756
- label: "Name",
43757
- size: "small",
43758
- value: form.name,
43759
- onChange: (e) => setForm({ ...form, name: e.target.value }),
43760
- placeholder: "e.g. github",
43761
- fullWidth: true
43762
- }
43763
- ),
43764
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43765
- import_material50.TextField,
43766
- {
43767
- label: "Server URL",
43768
- size: "small",
43769
- value: form.url,
43770
- onChange: (e) => setForm({ ...form, url: e.target.value }),
43771
- placeholder: "https://mcp.example.com/mcp",
43772
- fullWidth: true
43773
- }
43774
- ),
43775
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
43776
- import_material50.TextField,
43777
- {
43778
- select: true,
43779
- label: "Auth",
43780
- size: "small",
43781
- value: form.authType,
43782
- onChange: (e) => setForm({ ...form, authType: e.target.value }),
43783
- sx: { maxWidth: 220 },
43784
- children: [
43785
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "none", children: "None" }),
43786
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "bearer", children: "Bearer token" }),
43787
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "header", children: "Custom header" })
43788
- ]
43789
- }
43790
- ),
43791
- form.authType === "header" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43792
- import_material50.TextField,
43793
- {
43794
- label: "Header name",
43795
- size: "small",
43796
- value: form.headerName,
43797
- onChange: (e) => setForm({ ...form, headerName: e.target.value }),
43798
- placeholder: "X-Api-Key",
43799
- fullWidth: true
43800
- }
43801
- ),
43802
- form.authType !== "none" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43803
- import_material50.TextField,
43804
- {
43805
- label: form.authType === "bearer" ? "Token" : "Header value",
43806
- size: "small",
43807
- type: "password",
43808
- value: form.authValue,
43809
- onChange: (e) => setForm({ ...form, authValue: e.target.value }),
43810
- fullWidth: true
43811
- }
43812
- ),
43813
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", gap: 1 }, children: [
43814
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Button, { variant: "contained", onClick: handleAdd, disabled: adding, children: adding ? "Adding\u2026" : "Add server" }),
43829
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: "Popular integrations" }),
43830
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43831
+ import_material50.Box,
43832
+ {
43833
+ sx: {
43834
+ mt: 1,
43835
+ mb: 3,
43836
+ display: "grid",
43837
+ gridTemplateColumns: { xs: "1fr", sm: "repeat(2, 1fr)", lg: "repeat(3, 1fr)" },
43838
+ gap: 1.25
43839
+ },
43840
+ children: CATALOG.map((entry) => {
43841
+ const connected = connectedKeys.has(entry.url.replace(/\/+$/, ""));
43842
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
43843
+ import_material50.Paper,
43844
+ {
43845
+ variant: "outlined",
43846
+ sx: {
43847
+ p: 1.5,
43848
+ display: "flex",
43849
+ alignItems: "center",
43850
+ gap: 1.25,
43851
+ borderRadius: 2,
43852
+ transition: "border-color 0.15s ease, transform 0.15s ease",
43853
+ "&:hover": { borderColor: "primary.main", transform: "translateY(-1px)" }
43854
+ },
43855
+ children: [
43856
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43857
+ import_material50.Box,
43858
+ {
43859
+ sx: {
43860
+ width: 36,
43861
+ height: 36,
43862
+ borderRadius: 1.5,
43863
+ flexShrink: 0,
43864
+ display: "grid",
43865
+ placeItems: "center",
43866
+ color: "#fff",
43867
+ fontWeight: 700,
43868
+ fontSize: 16,
43869
+ bgcolor: entry.accent
43870
+ },
43871
+ children: entry.letter
43872
+ }
43873
+ ),
43874
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { minWidth: 0, flex: 1 }, children: [
43875
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "subtitle2", sx: { fontWeight: 700, lineHeight: 1.2 }, children: entry.name }),
43876
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43877
+ import_material50.Typography,
43878
+ {
43879
+ variant: "caption",
43880
+ color: "text.secondary",
43881
+ sx: { display: "block", lineHeight: 1.35 },
43882
+ children: entry.blurb
43883
+ }
43884
+ )
43885
+ ] }),
43886
+ connected ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Chip, { size: "small", color: "success", label: "Added", sx: { flexShrink: 0 } }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43887
+ import_material50.Button,
43888
+ {
43889
+ size: "small",
43890
+ variant: "outlined",
43891
+ onClick: () => openForCatalog(entry),
43892
+ sx: { flexShrink: 0, minWidth: 0 },
43893
+ children: "Connect"
43894
+ }
43895
+ )
43896
+ ]
43897
+ },
43898
+ entry.key
43899
+ );
43900
+ })
43901
+ }
43902
+ ),
43903
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Box, { ref: formRef, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Collapse, { in: showForm, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Paper, { variant: "outlined", sx: { p: 2, mb: 2, borderRadius: 2 }, children: [
43904
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "subtitle2", sx: { fontWeight: 700, mb: 0.5 }, children: activeEntry ? `Connect ${activeEntry.name}` : "Add a custom server" }),
43905
+ activeEntry?.tokenHelp && /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1.5 }, children: [
43906
+ "Paste your ",
43907
+ activeEntry.tokenLabel,
43908
+ ".",
43909
+ " ",
43910
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Link, { href: activeEntry.tokenHelp, target: "_blank", rel: "noopener noreferrer", children: "Get one here \u2192" })
43911
+ ] }),
43912
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Stack, { spacing: 1.75, children: [
43815
43913
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43816
- import_material50.Button,
43914
+ import_material50.TextField,
43817
43915
  {
43818
- onClick: () => {
43819
- setShowForm(false);
43820
- setForm(emptyForm);
43821
- },
43822
- children: "Cancel"
43916
+ label: "Name",
43917
+ size: "small",
43918
+ value: form.name,
43919
+ onChange: (e) => setForm({ ...form, name: e.target.value }),
43920
+ placeholder: "e.g. Linear",
43921
+ fullWidth: true
43823
43922
  }
43824
- )
43923
+ ),
43924
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43925
+ import_material50.TextField,
43926
+ {
43927
+ label: "Server URL",
43928
+ size: "small",
43929
+ value: form.url,
43930
+ onChange: (e) => setForm({ ...form, url: e.target.value }),
43931
+ placeholder: "https://mcp.example.com/mcp",
43932
+ fullWidth: true
43933
+ }
43934
+ ),
43935
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
43936
+ import_material50.TextField,
43937
+ {
43938
+ select: true,
43939
+ label: "Auth",
43940
+ size: "small",
43941
+ value: form.authType,
43942
+ onChange: (e) => setForm({ ...form, authType: e.target.value }),
43943
+ sx: { maxWidth: 220 },
43944
+ children: [
43945
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "none", children: "None" }),
43946
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "bearer", children: "Bearer token" }),
43947
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.MenuItem, { value: "header", children: "Custom header" })
43948
+ ]
43949
+ }
43950
+ ),
43951
+ form.authType === "header" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43952
+ import_material50.TextField,
43953
+ {
43954
+ label: "Header name",
43955
+ size: "small",
43956
+ value: form.headerName,
43957
+ onChange: (e) => setForm({ ...form, headerName: e.target.value }),
43958
+ placeholder: "X-Api-Key",
43959
+ fullWidth: true
43960
+ }
43961
+ ),
43962
+ form.authType !== "none" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43963
+ import_material50.TextField,
43964
+ {
43965
+ label: activeEntry?.tokenLabel ?? (form.authType === "bearer" ? "Token" : "Header value"),
43966
+ size: "small",
43967
+ type: "password",
43968
+ value: form.authValue,
43969
+ onChange: (e) => setForm({ ...form, authValue: e.target.value }),
43970
+ fullWidth: true
43971
+ }
43972
+ ),
43973
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", gap: 1 }, children: [
43974
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Button, { variant: "contained", onClick: handleAdd, disabled: adding, children: adding ? "Connecting\u2026" : "Connect" }),
43975
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
43976
+ import_material50.Button,
43977
+ {
43978
+ onClick: () => {
43979
+ setShowForm(false);
43980
+ setActiveEntry(null);
43981
+ setForm(emptyForm);
43982
+ },
43983
+ children: "Cancel"
43984
+ }
43985
+ )
43986
+ ] })
43825
43987
  ] })
43826
43988
  ] }) }) }),
43989
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1 }, children: [
43990
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: [
43991
+ "Your connections",
43992
+ servers.length ? ` (${servers.length})` : ""
43993
+ ] }),
43994
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Button, { size: "small", startIcon: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(AddIcon, {}), onClick: openCustom, children: "Custom server" })
43995
+ ] }),
43827
43996
  loading && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.LinearProgress, { sx: { mb: 2 } }),
43828
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Stack, { spacing: 1.5, children: [
43829
- servers.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "body2", color: "text.secondary", children: "No MCP servers connected yet." }),
43997
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Stack, { spacing: 1.25, children: [
43998
+ servers.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "body2", color: "text.secondary", sx: { py: 1 }, children: "Nothing connected yet \u2014 pick a tool above to get started." }),
43830
43999
  servers.map((server) => {
43831
44000
  const toolState = tools[server.id];
43832
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Paper, { variant: "outlined", sx: { p: 1.5 }, children: [
44001
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Paper, { variant: "outlined", sx: { p: 1.5, borderRadius: 2 }, children: [
43833
44002
  /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1 }, children: [
43834
44003
  /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Box, { sx: { minWidth: 0 }, children: [
43835
44004
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Typography, { variant: "subtitle2", sx: { fontWeight: 700 }, children: server.name }),
@@ -43857,6 +44026,11 @@ var McpServersSection = () => {
43857
44026
  toolState && !Array.isArray(toolState) && toolState !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_material50.Alert, { severity: "warning", sx: { mt: 1 }, children: toolState.error })
43858
44027
  ] }, server.id);
43859
44028
  })
44029
+ ] }),
44030
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_material50.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 2, lineHeight: 1.5 }, children: [
44031
+ "Running a local server (Figma Dev Mode, Azure DevOps)? Add it as a custom server \u2014 note the cloud gateway can't reach ",
44032
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("code", { children: "localhost" }),
44033
+ ", so local servers need the Bandit desktop app."
43860
44034
  ] })
43861
44035
  ] });
43862
44036
  };
@@ -43953,78 +44127,91 @@ var MCPToolsTabV2 = () => {
43953
44127
  return map23;
43954
44128
  }, [localTools]);
43955
44129
  return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { children: [
43956
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2 }, children: [
43957
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "h5", sx: { fontWeight: 600, color: "primary.main" }, children: "Available Tools" }),
43958
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.IconButton, { onClick: refresh, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RefreshIcon, {}) }) }) })
43959
- ] }),
43960
44130
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(McpServersSection_default, {}),
43961
- !gatewayConfigured && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "body2", color: "text.secondary", children: "Gateway API URL isn\u2019t configured. The controller endpoints will be fetched relative to this origin." }) }),
43962
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43963
- health?.status === "healthy" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(HealthAndSafetyIcon, { color: "success" }) : health?.status === "unhealthy" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ErrorOutlineIcon, { color: "error" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ErrorOutlineIcon, { color: "disabled" }),
43964
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "subtitle1", sx: { fontWeight: 600 }, children: "Controller Health" }),
43965
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
43966
- import_material51.Chip,
43967
- {
43968
- size: "small",
43969
- label: (health?.status || "unknown").toString(),
43970
- color: health?.status === "healthy" ? "success" : health?.status === "unhealthy" ? "error" : "default",
43971
- sx: { ml: 1 }
43972
- }
43973
- ),
43974
- health?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "caption", color: "text.secondary", sx: { ml: 1 }, children: new Date(health.timestamp).toLocaleString() })
43975
- ] }) }),
43976
- loading && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Box, { sx: { mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.LinearProgress, {}) }),
43977
- error && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { color: "error", children: error }) }),
43978
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Stack, { spacing: 2, children: tools.map((tool) => {
43979
- let locallyEnabled = localEnabledMap.get(tool.id);
43980
- if (locallyEnabled === void 0) {
43981
- locallyEnabled = localEnabledMap.get(tool.name);
43982
- }
43983
- if (locallyEnabled === void 0) {
43984
- const directLookup = localTools.find(
43985
- (t) => t.id === tool.id || t.function.name === tool.id || t.name === tool.name
43986
- );
43987
- locallyEnabled = directLookup?.enabled ?? tool.isEnabled;
43988
- }
43989
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Paper, { sx: { p: 2 }, children: [
43990
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
43991
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { children: [
43992
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "h6", sx: { fontWeight: 700 }, children: tool.name }),
43993
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: tool.description })
43994
- ] }),
43995
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43996
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
43997
- import_material51.FormControlLabel,
43998
- {
43999
- control: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Switch, { checked: !!locallyEnabled, onChange: () => {
44000
- let local = localTools.find((t) => t.function.name === tool.id);
44001
- if (!local) {
44002
- local = localTools.find((t) => t.function.name === tool.name);
44003
- }
44004
- if (!local) {
44005
- local = localTools.find((t) => t.id === tool.id);
44006
- }
44007
- if (!local) {
44008
- local = localTools.find((t) => t.name === tool.name);
44009
- }
44010
- if (local) {
44011
- toggleTool(local.id);
44012
- } else {
44013
- console.warn("Could not find local tool for server tool:", tool);
44014
- }
44015
- } }),
44016
- label: locallyEnabled ? "Enabled" : "Disabled"
44131
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { mt: 4 }, children: [
44132
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 0.5 }, children: [
44133
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: "Built-in capabilities" }),
44134
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { display: "flex", alignItems: "center", gap: 0.75 }, children: [
44135
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Tooltip, { title: `Controller: ${health?.status || "unknown"}`, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
44136
+ import_material51.Box,
44137
+ {
44138
+ sx: {
44139
+ width: 8,
44140
+ height: 8,
44141
+ borderRadius: "50%",
44142
+ bgcolor: health?.status === "healthy" ? "success.main" : health?.status === "unhealthy" ? "error.main" : "grey.500"
44017
44143
  }
44018
- ),
44019
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Tooltip, { title: "Controller-driven tools (read-only schema)", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(SettingsIcon, { color: "disabled" }) })
44020
- ] })
44021
- ] }),
44022
- !!tool.supportedParameters?.length && /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { mt: 1.5 }, children: [
44023
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "caption", color: "text.secondary", children: "Supported parameters" }),
44024
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Box, { sx: { mt: 0.5, display: "flex", flexWrap: "wrap", gap: 1 }, children: tool.supportedParameters.map((p) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Chip, { size: "small", label: p }, p)) })
44144
+ }
44145
+ ) }),
44146
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.IconButton, { size: "small", onClick: refresh, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RefreshIcon, { fontSize: "small" }) }) })
44025
44147
  ] })
44026
- ] }, tool.id);
44027
- }) })
44148
+ ] }),
44149
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1.5 }, children: "Things Bandit can do on its own \u2014 toggle what it\u2019s allowed to use." }),
44150
+ loading && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.LinearProgress, { sx: { mb: 2 } }),
44151
+ error && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Alert, { severity: "warning", sx: { mb: 2 }, children: error }),
44152
+ !gatewayConfigured && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Alert, { severity: "info", sx: { mb: 2 }, children: "Using this origin for tool endpoints (no gateway URL configured)." }),
44153
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
44154
+ import_material51.Box,
44155
+ {
44156
+ sx: {
44157
+ display: "grid",
44158
+ gridTemplateColumns: { xs: "1fr", sm: "repeat(2, 1fr)" },
44159
+ gap: 1.25
44160
+ },
44161
+ children: [
44162
+ tools.map((tool) => {
44163
+ let locallyEnabled = localEnabledMap.get(tool.id);
44164
+ if (locallyEnabled === void 0) {
44165
+ locallyEnabled = localEnabledMap.get(tool.name);
44166
+ }
44167
+ if (locallyEnabled === void 0) {
44168
+ const directLookup = localTools.find(
44169
+ (t) => t.id === tool.id || t.function.name === tool.id || t.name === tool.name
44170
+ );
44171
+ locallyEnabled = directLookup?.enabled ?? tool.isEnabled;
44172
+ }
44173
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
44174
+ import_material51.Paper,
44175
+ {
44176
+ variant: "outlined",
44177
+ sx: {
44178
+ p: 1.5,
44179
+ borderRadius: 2,
44180
+ display: "flex",
44181
+ alignItems: "flex-start",
44182
+ justifyContent: "space-between",
44183
+ gap: 1
44184
+ },
44185
+ children: [
44186
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_material51.Box, { sx: { minWidth: 0 }, children: [
44187
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "subtitle2", sx: { fontWeight: 700 }, children: tool.name }),
44188
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", lineHeight: 1.4 }, children: tool.description })
44189
+ ] }),
44190
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
44191
+ import_material51.Switch,
44192
+ {
44193
+ size: "small",
44194
+ checked: !!locallyEnabled,
44195
+ sx: { flexShrink: 0 },
44196
+ onChange: () => {
44197
+ let local = localTools.find((t) => t.function.name === tool.id);
44198
+ if (!local) local = localTools.find((t) => t.function.name === tool.name);
44199
+ if (!local) local = localTools.find((t) => t.id === tool.id);
44200
+ if (!local) local = localTools.find((t) => t.name === tool.name);
44201
+ if (local) toggleTool(local.id);
44202
+ }
44203
+ }
44204
+ )
44205
+ ]
44206
+ },
44207
+ tool.id
44208
+ );
44209
+ }),
44210
+ !loading && tools.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_material51.Typography, { variant: "body2", color: "text.secondary", children: "No built-in tools reported." })
44211
+ ]
44212
+ }
44213
+ )
44214
+ ] })
44028
44215
  ] });
44029
44216
  };
44030
44217
  var MCPToolsTabV2_default = MCPToolsTabV2;