@burtson-labs/bandit-engine 2.0.106 → 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.
@@ -34434,7 +34434,7 @@ var PersonalitiesTab = ({
34434
34434
  import_material19.Card,
34435
34435
  {
34436
34436
  sx: {
34437
- mb: { xs: 1.5, md: 2 },
34437
+ mb: { xs: 1, md: 1.25 },
34438
34438
  background: "linear-gradient(135deg, #1976d2 0%, #42a5f5 100%)",
34439
34439
  border: "2px solid transparent",
34440
34440
  borderRadius: { xs: 2.25, sm: 3 },
@@ -34471,7 +34471,7 @@ var PersonalitiesTab = ({
34471
34471
  setPersonalityTabIndex(1);
34472
34472
  },
34473
34473
  children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_material19.CardContent, { sx: {
34474
- p: { xs: 1.5, sm: 1.75 },
34474
+ p: { xs: 1, sm: 1.25 },
34475
34475
  color: "white",
34476
34476
  textAlign: "left",
34477
34477
  position: "relative",
@@ -34549,7 +34549,7 @@ var PersonalitiesTab = ({
34549
34549
  lg: "repeat(4, 1fr)",
34550
34550
  xl: "repeat(4, 1fr)"
34551
34551
  },
34552
- gap: { xs: 1.25, sm: 2.5, md: 3 },
34552
+ gap: { xs: 1, sm: 1.5, md: 1.75 },
34553
34553
  alignItems: "stretch"
34554
34554
  }, children: promptTemplates.map((template, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
34555
34555
  import_material19.Card,
@@ -34603,7 +34603,7 @@ var PersonalitiesTab = ({
34603
34603
  },
34604
34604
  onClick: () => handleTemplateSelect(template),
34605
34605
  children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_material19.CardContent, { sx: {
34606
- p: { xs: 1.5, sm: 2 },
34606
+ p: { xs: 1.25, sm: 1.5 },
34607
34607
  display: "flex",
34608
34608
  flexDirection: "column",
34609
34609
  height: "100%",
@@ -34622,8 +34622,8 @@ var PersonalitiesTab = ({
34622
34622
  src: template.avatar,
34623
34623
  alt: template.name,
34624
34624
  sx: {
34625
- width: { xs: 40, sm: 48, md: 52 },
34626
- height: { xs: 40, sm: 48, md: 52 },
34625
+ width: { xs: 38, sm: 44, md: 46 },
34626
+ height: { xs: 38, sm: 44, md: 46 },
34627
34627
  mr: { xs: 1.2, md: 2 },
34628
34628
  transition: "transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
34629
34629
  boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
@@ -42998,15 +42998,85 @@ init_mcpServersService();
42998
42998
  init_mcpToolsStore();
42999
42999
  var import_jsx_runtime29 = require("react/jsx-runtime");
43000
43000
  var emptyForm = { name: "", url: "", authType: "none", authValue: "", headerName: "" };
43001
+ var CATALOG = [
43002
+ {
43003
+ key: "linear",
43004
+ name: "Linear",
43005
+ blurb: "Create and track issues, projects, and cycles",
43006
+ letter: "L",
43007
+ accent: "#5E6AD2",
43008
+ url: "https://mcp.linear.app/sse",
43009
+ authType: "bearer",
43010
+ tokenLabel: "Linear API key",
43011
+ tokenHelp: "https://linear.app/settings/api"
43012
+ },
43013
+ {
43014
+ key: "notion",
43015
+ name: "Notion",
43016
+ blurb: "Search and update pages across your workspace",
43017
+ letter: "N",
43018
+ accent: "#0f0f0f",
43019
+ url: "https://mcp.notion.com/mcp",
43020
+ authType: "bearer",
43021
+ tokenLabel: "Notion integration token",
43022
+ tokenHelp: "https://www.notion.so/my-integrations"
43023
+ },
43024
+ {
43025
+ key: "github",
43026
+ name: "GitHub",
43027
+ blurb: "Issues, pull requests, code search, and actions",
43028
+ letter: "G",
43029
+ accent: "#24292f",
43030
+ url: "https://api.githubcopilot.com/mcp/",
43031
+ authType: "bearer",
43032
+ tokenLabel: "GitHub personal access token",
43033
+ tokenHelp: "https://github.com/settings/tokens"
43034
+ },
43035
+ {
43036
+ key: "sentry",
43037
+ name: "Sentry",
43038
+ blurb: "Triage errors and inspect production issues",
43039
+ letter: "S",
43040
+ accent: "#362D59",
43041
+ url: "https://mcp.sentry.dev/mcp",
43042
+ authType: "bearer",
43043
+ tokenLabel: "Sentry auth token",
43044
+ tokenHelp: "https://sentry.io/settings/auth-tokens/"
43045
+ },
43046
+ {
43047
+ key: "atlassian",
43048
+ name: "Jira & Confluence",
43049
+ blurb: "Atlassian issues, boards, and docs",
43050
+ letter: "J",
43051
+ accent: "#0052CC",
43052
+ url: "https://mcp.atlassian.com/v1/sse",
43053
+ authType: "bearer",
43054
+ tokenLabel: "Atlassian API token",
43055
+ tokenHelp: "https://id.atlassian.com/manage-profile/security/api-tokens"
43056
+ },
43057
+ {
43058
+ key: "stripe",
43059
+ name: "Stripe",
43060
+ blurb: "Payments, customers, and invoices",
43061
+ letter: "S",
43062
+ accent: "#635BFF",
43063
+ url: "https://mcp.stripe.com",
43064
+ authType: "bearer",
43065
+ tokenLabel: "Stripe restricted key",
43066
+ tokenHelp: "https://dashboard.stripe.com/apikeys"
43067
+ }
43068
+ ];
43001
43069
  var McpServersSection = () => {
43002
43070
  const [servers, setServers] = (0, import_react38.useState)([]);
43003
43071
  const [loading, setLoading] = (0, import_react38.useState)(false);
43004
43072
  const [error, setError] = (0, import_react38.useState)(null);
43005
43073
  const [form, setForm] = (0, import_react38.useState)(emptyForm);
43074
+ const [activeEntry, setActiveEntry] = (0, import_react38.useState)(null);
43006
43075
  const [adding, setAdding] = (0, import_react38.useState)(false);
43007
43076
  const [showForm, setShowForm] = (0, import_react38.useState)(false);
43008
43077
  const [tools, setTools] = (0, import_react38.useState)({});
43009
43078
  const reloadChatTools = useMCPToolsStore((s) => s.loadMcpServerTools);
43079
+ const formRef = (0, import_react38.useRef)(null);
43010
43080
  const refresh = (0, import_react38.useCallback)(async () => {
43011
43081
  setLoading(true);
43012
43082
  setError(null);
@@ -43021,6 +43091,20 @@ var McpServersSection = () => {
43021
43091
  (0, import_react38.useEffect)(() => {
43022
43092
  refresh();
43023
43093
  }, [refresh]);
43094
+ const connectedKeys = new Set(servers.map((s) => s.url.replace(/\/+$/, "")));
43095
+ const openForCatalog = (entry) => {
43096
+ setActiveEntry(entry);
43097
+ setForm({ name: entry.name, url: entry.url, authType: entry.authType, authValue: "", headerName: "" });
43098
+ setShowForm(true);
43099
+ setError(null);
43100
+ requestAnimationFrame(() => formRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }));
43101
+ };
43102
+ const openCustom = () => {
43103
+ setActiveEntry(null);
43104
+ setForm(emptyForm);
43105
+ setShowForm((v) => !v);
43106
+ setError(null);
43107
+ };
43024
43108
  const handleAdd = async () => {
43025
43109
  if (!form.name.trim() || !form.url.trim()) {
43026
43110
  setError("Name and URL are required.");
@@ -43037,6 +43121,7 @@ var McpServersSection = () => {
43037
43121
  headerName: form.authType === "header" ? form.headerName : void 0
43038
43122
  });
43039
43123
  setForm(emptyForm);
43124
+ setActiveEntry(null);
43040
43125
  setShowForm(false);
43041
43126
  await refresh();
43042
43127
  void reloadChatTools();
@@ -43075,101 +43160,185 @@ var McpServersSection = () => {
43075
43160
  setTools((prev) => ({ ...prev, [id]: { error: e instanceof Error ? e.message : "Could not connect." } }));
43076
43161
  }
43077
43162
  };
43078
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Paper, { sx: { p: 2, mb: 2 }, children: [
43079
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1, gap: 1, flexWrap: "wrap" }, children: [
43080
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43081
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CloudIcon, {}),
43082
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "subtitle1", sx: { fontWeight: 700 }, children: "MCP Servers" }),
43083
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Chip, { size: "small", label: String(servers.length) })
43084
- ] }),
43085
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
43086
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.IconButton, { onClick: refresh, size: "small", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RefreshIcon, {}) }) }),
43087
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Button, { size: "small", variant: "contained", startIcon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AddIcon, {}), onClick: () => setShowForm((v) => !v), children: "Add server" })
43088
- ] })
43163
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { children: [
43164
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { mb: 2.5 }, children: [
43165
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "h6", sx: { fontWeight: 700, mb: 0.5 }, children: "Connect your tools" }),
43166
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.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." })
43089
43167
  ] }),
43090
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.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." }),
43091
43168
  error && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Alert, { severity: "error", sx: { mb: 2 }, onClose: () => setError(null), children: error }),
43092
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Collapse, { in: showForm, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Paper, { variant: "outlined", sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Stack, { spacing: 2, children: [
43093
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43094
- import_material30.TextField,
43095
- {
43096
- label: "Name",
43097
- size: "small",
43098
- value: form.name,
43099
- onChange: (e) => setForm({ ...form, name: e.target.value }),
43100
- placeholder: "e.g. github",
43101
- fullWidth: true
43102
- }
43103
- ),
43104
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43105
- import_material30.TextField,
43106
- {
43107
- label: "Server URL",
43108
- size: "small",
43109
- value: form.url,
43110
- onChange: (e) => setForm({ ...form, url: e.target.value }),
43111
- placeholder: "https://mcp.example.com/mcp",
43112
- fullWidth: true
43113
- }
43114
- ),
43115
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
43116
- import_material30.TextField,
43117
- {
43118
- select: true,
43119
- label: "Auth",
43120
- size: "small",
43121
- value: form.authType,
43122
- onChange: (e) => setForm({ ...form, authType: e.target.value }),
43123
- sx: { maxWidth: 220 },
43124
- children: [
43125
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "none", children: "None" }),
43126
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "bearer", children: "Bearer token" }),
43127
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "header", children: "Custom header" })
43128
- ]
43129
- }
43130
- ),
43131
- form.authType === "header" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43132
- import_material30.TextField,
43133
- {
43134
- label: "Header name",
43135
- size: "small",
43136
- value: form.headerName,
43137
- onChange: (e) => setForm({ ...form, headerName: e.target.value }),
43138
- placeholder: "X-Api-Key",
43139
- fullWidth: true
43140
- }
43141
- ),
43142
- form.authType !== "none" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43143
- import_material30.TextField,
43144
- {
43145
- label: form.authType === "bearer" ? "Token" : "Header value",
43146
- size: "small",
43147
- type: "password",
43148
- value: form.authValue,
43149
- onChange: (e) => setForm({ ...form, authValue: e.target.value }),
43150
- fullWidth: true
43151
- }
43152
- ),
43153
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", gap: 1 }, children: [
43154
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Button, { variant: "contained", onClick: handleAdd, disabled: adding, children: adding ? "Adding\u2026" : "Add server" }),
43169
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: "Popular integrations" }),
43170
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43171
+ import_material30.Box,
43172
+ {
43173
+ sx: {
43174
+ mt: 1,
43175
+ mb: 3,
43176
+ display: "grid",
43177
+ gridTemplateColumns: { xs: "1fr", sm: "repeat(2, 1fr)", lg: "repeat(3, 1fr)" },
43178
+ gap: 1.25
43179
+ },
43180
+ children: CATALOG.map((entry) => {
43181
+ const connected = connectedKeys.has(entry.url.replace(/\/+$/, ""));
43182
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
43183
+ import_material30.Paper,
43184
+ {
43185
+ variant: "outlined",
43186
+ sx: {
43187
+ p: 1.5,
43188
+ display: "flex",
43189
+ alignItems: "center",
43190
+ gap: 1.25,
43191
+ borderRadius: 2,
43192
+ transition: "border-color 0.15s ease, transform 0.15s ease",
43193
+ "&:hover": { borderColor: "primary.main", transform: "translateY(-1px)" }
43194
+ },
43195
+ children: [
43196
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43197
+ import_material30.Box,
43198
+ {
43199
+ sx: {
43200
+ width: 36,
43201
+ height: 36,
43202
+ borderRadius: 1.5,
43203
+ flexShrink: 0,
43204
+ display: "grid",
43205
+ placeItems: "center",
43206
+ color: "#fff",
43207
+ fontWeight: 700,
43208
+ fontSize: 16,
43209
+ bgcolor: entry.accent
43210
+ },
43211
+ children: entry.letter
43212
+ }
43213
+ ),
43214
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { minWidth: 0, flex: 1 }, children: [
43215
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "subtitle2", sx: { fontWeight: 700, lineHeight: 1.2 }, children: entry.name }),
43216
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43217
+ import_material30.Typography,
43218
+ {
43219
+ variant: "caption",
43220
+ color: "text.secondary",
43221
+ sx: { display: "block", lineHeight: 1.35 },
43222
+ children: entry.blurb
43223
+ }
43224
+ )
43225
+ ] }),
43226
+ connected ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Chip, { size: "small", color: "success", label: "Added", sx: { flexShrink: 0 } }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43227
+ import_material30.Button,
43228
+ {
43229
+ size: "small",
43230
+ variant: "outlined",
43231
+ onClick: () => openForCatalog(entry),
43232
+ sx: { flexShrink: 0, minWidth: 0 },
43233
+ children: "Connect"
43234
+ }
43235
+ )
43236
+ ]
43237
+ },
43238
+ entry.key
43239
+ );
43240
+ })
43241
+ }
43242
+ ),
43243
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Box, { ref: formRef, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Collapse, { in: showForm, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Paper, { variant: "outlined", sx: { p: 2, mb: 2, borderRadius: 2 }, children: [
43244
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "subtitle2", sx: { fontWeight: 700, mb: 0.5 }, children: activeEntry ? `Connect ${activeEntry.name}` : "Add a custom server" }),
43245
+ activeEntry?.tokenHelp && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1.5 }, children: [
43246
+ "Paste your ",
43247
+ activeEntry.tokenLabel,
43248
+ ".",
43249
+ " ",
43250
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Link, { href: activeEntry.tokenHelp, target: "_blank", rel: "noopener noreferrer", children: "Get one here \u2192" })
43251
+ ] }),
43252
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Stack, { spacing: 1.75, children: [
43155
43253
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43156
- import_material30.Button,
43254
+ import_material30.TextField,
43157
43255
  {
43158
- onClick: () => {
43159
- setShowForm(false);
43160
- setForm(emptyForm);
43161
- },
43162
- children: "Cancel"
43256
+ label: "Name",
43257
+ size: "small",
43258
+ value: form.name,
43259
+ onChange: (e) => setForm({ ...form, name: e.target.value }),
43260
+ placeholder: "e.g. Linear",
43261
+ fullWidth: true
43163
43262
  }
43164
- )
43263
+ ),
43264
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43265
+ import_material30.TextField,
43266
+ {
43267
+ label: "Server URL",
43268
+ size: "small",
43269
+ value: form.url,
43270
+ onChange: (e) => setForm({ ...form, url: e.target.value }),
43271
+ placeholder: "https://mcp.example.com/mcp",
43272
+ fullWidth: true
43273
+ }
43274
+ ),
43275
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
43276
+ import_material30.TextField,
43277
+ {
43278
+ select: true,
43279
+ label: "Auth",
43280
+ size: "small",
43281
+ value: form.authType,
43282
+ onChange: (e) => setForm({ ...form, authType: e.target.value }),
43283
+ sx: { maxWidth: 220 },
43284
+ children: [
43285
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "none", children: "None" }),
43286
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "bearer", children: "Bearer token" }),
43287
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.MenuItem, { value: "header", children: "Custom header" })
43288
+ ]
43289
+ }
43290
+ ),
43291
+ form.authType === "header" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43292
+ import_material30.TextField,
43293
+ {
43294
+ label: "Header name",
43295
+ size: "small",
43296
+ value: form.headerName,
43297
+ onChange: (e) => setForm({ ...form, headerName: e.target.value }),
43298
+ placeholder: "X-Api-Key",
43299
+ fullWidth: true
43300
+ }
43301
+ ),
43302
+ form.authType !== "none" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43303
+ import_material30.TextField,
43304
+ {
43305
+ label: activeEntry?.tokenLabel ?? (form.authType === "bearer" ? "Token" : "Header value"),
43306
+ size: "small",
43307
+ type: "password",
43308
+ value: form.authValue,
43309
+ onChange: (e) => setForm({ ...form, authValue: e.target.value }),
43310
+ fullWidth: true
43311
+ }
43312
+ ),
43313
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", gap: 1 }, children: [
43314
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Button, { variant: "contained", onClick: handleAdd, disabled: adding, children: adding ? "Connecting\u2026" : "Connect" }),
43315
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
43316
+ import_material30.Button,
43317
+ {
43318
+ onClick: () => {
43319
+ setShowForm(false);
43320
+ setActiveEntry(null);
43321
+ setForm(emptyForm);
43322
+ },
43323
+ children: "Cancel"
43324
+ }
43325
+ )
43326
+ ] })
43165
43327
  ] })
43166
43328
  ] }) }) }),
43329
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1 }, children: [
43330
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: [
43331
+ "Your connections",
43332
+ servers.length ? ` (${servers.length})` : ""
43333
+ ] }),
43334
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Button, { size: "small", startIcon: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AddIcon, {}), onClick: openCustom, children: "Custom server" })
43335
+ ] }),
43167
43336
  loading && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.LinearProgress, { sx: { mb: 2 } }),
43168
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Stack, { spacing: 1.5, children: [
43169
- servers.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "body2", color: "text.secondary", children: "No MCP servers connected yet." }),
43337
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Stack, { spacing: 1.25, children: [
43338
+ servers.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "body2", color: "text.secondary", sx: { py: 1 }, children: "Nothing connected yet \u2014 pick a tool above to get started." }),
43170
43339
  servers.map((server) => {
43171
43340
  const toolState = tools[server.id];
43172
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Paper, { variant: "outlined", sx: { p: 1.5 }, children: [
43341
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Paper, { variant: "outlined", sx: { p: 1.5, borderRadius: 2 }, children: [
43173
43342
  /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1 }, children: [
43174
43343
  /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Box, { sx: { minWidth: 0 }, children: [
43175
43344
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Typography, { variant: "subtitle2", sx: { fontWeight: 700 }, children: server.name }),
@@ -43197,6 +43366,11 @@ var McpServersSection = () => {
43197
43366
  toolState && !Array.isArray(toolState) && toolState !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material30.Alert, { severity: "warning", sx: { mt: 1 }, children: toolState.error })
43198
43367
  ] }, server.id);
43199
43368
  })
43369
+ ] }),
43370
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material30.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 2, lineHeight: 1.5 }, children: [
43371
+ "Running a local server (Figma Dev Mode, Azure DevOps)? Add it as a custom server \u2014 note the cloud gateway can't reach ",
43372
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("code", { children: "localhost" }),
43373
+ ", so local servers need the Bandit desktop app."
43200
43374
  ] })
43201
43375
  ] });
43202
43376
  };
@@ -43293,78 +43467,91 @@ var MCPToolsTabV2 = () => {
43293
43467
  return map23;
43294
43468
  }, [localTools]);
43295
43469
  return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { children: [
43296
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2 }, children: [
43297
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "h5", sx: { fontWeight: 600, color: "primary.main" }, children: "Available Tools" }),
43298
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.IconButton, { onClick: refresh, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RefreshIcon, {}) }) }) })
43299
- ] }),
43300
43470
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(McpServersSection_default, {}),
43301
- !gatewayConfigured && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "body2", color: "text.secondary", children: "Gateway API URL isn\u2019t configured. The controller endpoints will be fetched relative to this origin." }) }),
43302
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43303
- health?.status === "healthy" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(HealthAndSafetyIcon, { color: "success" }) : health?.status === "unhealthy" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ErrorOutlineIcon, { color: "error" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ErrorOutlineIcon, { color: "disabled" }),
43304
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "subtitle1", sx: { fontWeight: 600 }, children: "Controller Health" }),
43305
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
43306
- import_material31.Chip,
43307
- {
43308
- size: "small",
43309
- label: (health?.status || "unknown").toString(),
43310
- color: health?.status === "healthy" ? "success" : health?.status === "unhealthy" ? "error" : "default",
43311
- sx: { ml: 1 }
43312
- }
43313
- ),
43314
- health?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "caption", color: "text.secondary", sx: { ml: 1 }, children: new Date(health.timestamp).toLocaleString() })
43315
- ] }) }),
43316
- loading && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Box, { sx: { mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.LinearProgress, {}) }),
43317
- error && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Paper, { sx: { p: 2, mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { color: "error", children: error }) }),
43318
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Stack, { spacing: 2, children: tools.map((tool) => {
43319
- let locallyEnabled = localEnabledMap.get(tool.id);
43320
- if (locallyEnabled === void 0) {
43321
- locallyEnabled = localEnabledMap.get(tool.name);
43322
- }
43323
- if (locallyEnabled === void 0) {
43324
- const directLookup = localTools.find(
43325
- (t) => t.id === tool.id || t.function.name === tool.id || t.name === tool.name
43326
- );
43327
- locallyEnabled = directLookup?.enabled ?? tool.isEnabled;
43328
- }
43329
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Paper, { sx: { p: 2 }, children: [
43330
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
43331
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { children: [
43332
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "h6", sx: { fontWeight: 700 }, children: tool.name }),
43333
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: tool.description })
43334
- ] }),
43335
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
43336
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
43337
- import_material31.FormControlLabel,
43338
- {
43339
- control: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Switch, { checked: !!locallyEnabled, onChange: () => {
43340
- let local = localTools.find((t) => t.function.name === tool.id);
43341
- if (!local) {
43342
- local = localTools.find((t) => t.function.name === tool.name);
43343
- }
43344
- if (!local) {
43345
- local = localTools.find((t) => t.id === tool.id);
43346
- }
43347
- if (!local) {
43348
- local = localTools.find((t) => t.name === tool.name);
43349
- }
43350
- if (local) {
43351
- toggleTool(local.id);
43352
- } else {
43353
- console.warn("Could not find local tool for server tool:", tool);
43354
- }
43355
- } }),
43356
- label: locallyEnabled ? "Enabled" : "Disabled"
43471
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { mt: 4 }, children: [
43472
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 0.5 }, children: [
43473
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "overline", color: "text.secondary", sx: { fontWeight: 700, letterSpacing: 0.6 }, children: "Built-in capabilities" }),
43474
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { display: "flex", alignItems: "center", gap: 0.75 }, children: [
43475
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Tooltip, { title: `Controller: ${health?.status || "unknown"}`, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
43476
+ import_material31.Box,
43477
+ {
43478
+ sx: {
43479
+ width: 8,
43480
+ height: 8,
43481
+ borderRadius: "50%",
43482
+ bgcolor: health?.status === "healthy" ? "success.main" : health?.status === "unhealthy" ? "error.main" : "grey.500"
43357
43483
  }
43358
- ),
43359
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Tooltip, { title: "Controller-driven tools (read-only schema)", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(SettingsIcon, { color: "disabled" }) })
43360
- ] })
43361
- ] }),
43362
- !!tool.supportedParameters?.length && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { mt: 1.5 }, children: [
43363
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "caption", color: "text.secondary", children: "Supported parameters" }),
43364
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Box, { sx: { mt: 0.5, display: "flex", flexWrap: "wrap", gap: 1 }, children: tool.supportedParameters.map((p) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Chip, { size: "small", label: p }, p)) })
43484
+ }
43485
+ ) }),
43486
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Tooltip, { title: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.IconButton, { size: "small", onClick: refresh, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RefreshIcon, { fontSize: "small" }) }) })
43365
43487
  ] })
43366
- ] }, tool.id);
43367
- }) })
43488
+ ] }),
43489
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.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." }),
43490
+ loading && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.LinearProgress, { sx: { mb: 2 } }),
43491
+ error && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Alert, { severity: "warning", sx: { mb: 2 }, children: error }),
43492
+ !gatewayConfigured && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Alert, { severity: "info", sx: { mb: 2 }, children: "Using this origin for tool endpoints (no gateway URL configured)." }),
43493
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
43494
+ import_material31.Box,
43495
+ {
43496
+ sx: {
43497
+ display: "grid",
43498
+ gridTemplateColumns: { xs: "1fr", sm: "repeat(2, 1fr)" },
43499
+ gap: 1.25
43500
+ },
43501
+ children: [
43502
+ tools.map((tool) => {
43503
+ let locallyEnabled = localEnabledMap.get(tool.id);
43504
+ if (locallyEnabled === void 0) {
43505
+ locallyEnabled = localEnabledMap.get(tool.name);
43506
+ }
43507
+ if (locallyEnabled === void 0) {
43508
+ const directLookup = localTools.find(
43509
+ (t) => t.id === tool.id || t.function.name === tool.id || t.name === tool.name
43510
+ );
43511
+ locallyEnabled = directLookup?.enabled ?? tool.isEnabled;
43512
+ }
43513
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
43514
+ import_material31.Paper,
43515
+ {
43516
+ variant: "outlined",
43517
+ sx: {
43518
+ p: 1.5,
43519
+ borderRadius: 2,
43520
+ display: "flex",
43521
+ alignItems: "flex-start",
43522
+ justifyContent: "space-between",
43523
+ gap: 1
43524
+ },
43525
+ children: [
43526
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material31.Box, { sx: { minWidth: 0 }, children: [
43527
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "subtitle2", sx: { fontWeight: 700 }, children: tool.name }),
43528
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", lineHeight: 1.4 }, children: tool.description })
43529
+ ] }),
43530
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
43531
+ import_material31.Switch,
43532
+ {
43533
+ size: "small",
43534
+ checked: !!locallyEnabled,
43535
+ sx: { flexShrink: 0 },
43536
+ onChange: () => {
43537
+ let local = localTools.find((t) => t.function.name === tool.id);
43538
+ if (!local) local = localTools.find((t) => t.function.name === tool.name);
43539
+ if (!local) local = localTools.find((t) => t.id === tool.id);
43540
+ if (!local) local = localTools.find((t) => t.name === tool.name);
43541
+ if (local) toggleTool(local.id);
43542
+ }
43543
+ }
43544
+ )
43545
+ ]
43546
+ },
43547
+ tool.id
43548
+ );
43549
+ }),
43550
+ !loading && tools.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material31.Typography, { variant: "body2", color: "text.secondary", children: "No built-in tools reported." })
43551
+ ]
43552
+ }
43553
+ )
43554
+ ] })
43368
43555
  ] });
43369
43556
  };
43370
43557
  var MCPToolsTabV2_default = MCPToolsTabV2;