@burdenoff/microfe-botmanor 2026.821.1 → 2026.925.1
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.
- package/dist/botlit/BotlitRoutes.js.map +1 -1
- package/dist/botlit/BotmanorRoot.js.map +1 -1
- package/dist/botlit/BotmanorRootInner.js +4 -4
- package/dist/botlit/BotmanorRootInner.js.map +1 -1
- package/dist/botlit/components/ErrorState.js +33 -29
- package/dist/botlit/components/ErrorState.js.map +1 -1
- package/dist/botlit/components/RouteLoader.js +52 -48
- package/dist/botlit/components/RouteLoader.js.map +1 -1
- package/dist/botlit/components/VersionHistoryPanel.js +74 -77
- package/dist/botlit/components/VersionHistoryPanel.js.map +1 -1
- package/dist/botlit/components/WorkspaceRequired.js +31 -30
- package/dist/botlit/components/WorkspaceRequired.js.map +1 -1
- package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -1
- package/dist/botlit/hooks/useConversations.js.map +1 -1
- package/dist/botlit/hooks/useLLMProviders.js.map +1 -1
- package/dist/botlit/pages/A2AAgentDetailPage.js +1 -1
- package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -1
- package/dist/botlit/pages/A2ARegistryPage.js +116 -124
- package/dist/botlit/pages/A2ARegistryPage.js.map +1 -1
- package/dist/botlit/pages/AgentDetailPage.js +169 -172
- package/dist/botlit/pages/AgentDetailPage.js.map +1 -1
- package/dist/botlit/pages/AgentsListPage.js +96 -90
- package/dist/botlit/pages/AgentsListPage.js.map +1 -1
- package/dist/botlit/pages/BotChannelsTab.js.map +1 -1
- package/dist/botlit/pages/BotDetailPage.js +228 -231
- package/dist/botlit/pages/BotDetailPage.js.map +1 -1
- package/dist/botlit/pages/BotWorkflowTab.js +84 -87
- package/dist/botlit/pages/BotWorkflowTab.js.map +1 -1
- package/dist/botlit/pages/BotsListPage.js +144 -147
- package/dist/botlit/pages/BotsListPage.js.map +1 -1
- package/dist/botlit/pages/BucketsPage.js +3 -3
- package/dist/botlit/pages/BucketsPage.js.map +1 -1
- package/dist/botlit/pages/ChannelDetailPage.js +1 -1
- package/dist/botlit/pages/ChannelDetailPage.js.map +1 -1
- package/dist/botlit/pages/ChannelsPage.js +156 -149
- package/dist/botlit/pages/ChannelsPage.js.map +1 -1
- package/dist/botlit/pages/ChatPage.js +126 -129
- package/dist/botlit/pages/ChatPage.js.map +1 -1
- package/dist/botlit/pages/DashboardPage.js +111 -114
- package/dist/botlit/pages/DashboardPage.js.map +1 -1
- package/dist/botlit/pages/ExecutionsPage.js +163 -159
- package/dist/botlit/pages/ExecutionsPage.js.map +1 -1
- package/dist/botlit/pages/InstalledPackagesPage.js +3 -3
- package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -1
- package/dist/botlit/pages/KnowledgeBasesPage.js +84 -78
- package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -1
- package/dist/botlit/pages/MCPServersPage.js +159 -154
- package/dist/botlit/pages/MCPServersPage.js.map +1 -1
- package/dist/botlit/pages/PoliciesPage.js +119 -114
- package/dist/botlit/pages/PoliciesPage.js.map +1 -1
- package/dist/botlit/pages/RetrievalProfilesPage.js +102 -109
- package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -1
- package/dist/botlit/pages/SettingsPage.js +144 -159
- package/dist/botlit/pages/SettingsPage.js.map +1 -1
- package/dist/botlit/pages/SkillsPage.js +122 -105
- package/dist/botlit/pages/SkillsPage.js.map +1 -1
- package/dist/botlit/pages/StorePage.js +176 -175
- package/dist/botlit/pages/StorePage.js.map +1 -1
- package/dist/botlit/providers/BotlitProvider.js.map +1 -1
- package/dist/botlit/store/botlitStore.js +1 -1
- package/dist/botlit/store/botlitStore.js.map +1 -1
- package/dist/botlit/utils/navigation.js.map +1 -1
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/package.json +33 -9
|
@@ -1,310 +1,315 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { useBotlit as t } from "../providers/BotlitProvider.js";
|
|
3
|
+
import { isMCPServerHealthy as n, mcpServerDescription as r, mcpServerEndpoint as i, useCreateMCPServer as a, useDeleteMCPServer as o, useMCPServers as s, useTestMCPConnection as c } from "../hooks/useMCPServers.js";
|
|
4
|
+
import { formatRelativeTime as l } from "../utils/formatters.js";
|
|
5
|
+
import { PageLayout as u } from "../components/PageLayout.js";
|
|
6
|
+
import { Card as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h } from "../components/Card.js";
|
|
7
|
+
import { Button as g } from "../components/Button.js";
|
|
8
|
+
import { Badge as _, StatusBadge as v } from "../components/Badge.js";
|
|
9
|
+
import { EmptyState as y } from "../components/EmptyState.js";
|
|
10
|
+
import { FormField as b, Input as x } from "../components/Input.js";
|
|
11
|
+
import { ErrorState as S } from "../components/ErrorState.js";
|
|
12
|
+
import { useState as C } from "react";
|
|
13
|
+
import { GlassCard as w, PagePurpose as T } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
15
|
+
import { Plug as O, PlugZap as k, Plus as A, Settings as j, Trash2 as M } from "lucide-react";
|
|
16
|
+
import { toast as N } from "sonner";
|
|
16
17
|
//#region src/botlit/pages/MCPServersPage.tsx
|
|
17
|
-
var
|
|
18
|
-
let { navigateTo:
|
|
18
|
+
var P = () => {
|
|
19
|
+
let P = e(), { navigateTo: F } = t(), { data: I, loading: L, error: R, refetch: z } = s(), [B, V] = a(), [H, U] = o(), [W, G] = c(), [K, q] = C(!1), [J, Y] = C({
|
|
19
20
|
name: "",
|
|
20
21
|
description: "",
|
|
21
22
|
transport: "HTTP_JSON",
|
|
22
23
|
baseUrl: ""
|
|
23
|
-
}),
|
|
24
|
-
if (!(!
|
|
24
|
+
}), X = async () => {
|
|
25
|
+
if (!(!J.name || !J.baseUrl)) {
|
|
25
26
|
try {
|
|
26
|
-
await
|
|
27
|
-
name:
|
|
28
|
-
type:
|
|
27
|
+
await B({
|
|
28
|
+
name: J.name,
|
|
29
|
+
type: J.transport,
|
|
29
30
|
config: {
|
|
30
|
-
url:
|
|
31
|
-
description:
|
|
31
|
+
url: J.baseUrl,
|
|
32
|
+
description: J.description
|
|
32
33
|
}
|
|
33
34
|
});
|
|
34
35
|
} catch (e) {
|
|
35
|
-
|
|
36
|
+
N.error(e instanceof Error ? e.message : P("botlit.mcpServers.toast.connectError", "Failed to connect MCP server"));
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
N.success(P("botlit.mcpServers.toast.connectSuccess", "Connected \"{{name}}\"", { name: J.name })), z(), Y({
|
|
39
40
|
name: "",
|
|
40
41
|
description: "",
|
|
41
42
|
transport: "HTTP_JSON",
|
|
42
43
|
baseUrl: ""
|
|
43
|
-
}),
|
|
44
|
+
}), q(!1);
|
|
44
45
|
}
|
|
45
|
-
},
|
|
46
|
+
}, Z = async (e) => {
|
|
46
47
|
try {
|
|
47
|
-
await
|
|
48
|
+
await H(e.id), N.success(P("botlit.mcpServers.toast.disconnectSuccess", "Disconnected \"{{name}}\"", { name: e.name })), z();
|
|
48
49
|
} catch (e) {
|
|
49
|
-
|
|
50
|
+
N.error(e instanceof Error ? e.message : P("botlit.mcpServers.toast.disconnectError", "Failed to disconnect MCP server"));
|
|
50
51
|
}
|
|
51
|
-
},
|
|
52
|
+
}, Q = async (e) => {
|
|
52
53
|
try {
|
|
53
|
-
await
|
|
54
|
+
await W(e.id) ? N.success(P("botlit.mcpServers.toast.reachable", "\"{{name}}\" is reachable", { name: e.name })) : N.error(P("botlit.mcpServers.toast.unreachable", "\"{{name}}\" did not respond", { name: e.name })), z();
|
|
54
55
|
} catch (e) {
|
|
55
|
-
|
|
56
|
+
N.error(e instanceof Error ? e.message : P("botlit.mcpServers.toast.testError", "Failed to test MCP connection"));
|
|
56
57
|
}
|
|
57
58
|
};
|
|
58
|
-
return /* @__PURE__ */
|
|
59
|
-
title: "MCP Servers",
|
|
60
|
-
description: "Connect Model Context Protocol servers to extend agent capabilities",
|
|
61
|
-
actions: /* @__PURE__ */
|
|
62
|
-
leftIcon: /* @__PURE__ */
|
|
63
|
-
onClick: () =>
|
|
64
|
-
children: "Add MCP Server"
|
|
59
|
+
return /* @__PURE__ */ E(u, {
|
|
60
|
+
title: P("botlit.mcpServers.title", "MCP Servers"),
|
|
61
|
+
description: P("botlit.mcpServers.description", "Connect Model Context Protocol servers to extend agent capabilities"),
|
|
62
|
+
actions: /* @__PURE__ */ E(g, {
|
|
63
|
+
leftIcon: /* @__PURE__ */ E(A, { size: 16 }),
|
|
64
|
+
onClick: () => q(!0),
|
|
65
|
+
children: P("botlit.mcpServers.actions.add", "Add MCP Server")
|
|
65
66
|
}),
|
|
66
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ D("div", {
|
|
67
68
|
className: "space-y-6",
|
|
68
69
|
children: [
|
|
69
|
-
/* @__PURE__ */ T
|
|
70
|
-
icon: /* @__PURE__ */
|
|
71
|
-
children: "MCP (Model Context Protocol) servers are how your agents reach the outside world — they expose real tools an agent can call, like searching the web, reading a GitHub repo, querying a database or posting to Slack. Connect a server here and its tools become available to your agents (gated by your tool policies), turning a chatbot into something that can take action."
|
|
70
|
+
/* @__PURE__ */ E(T, {
|
|
71
|
+
icon: /* @__PURE__ */ E(O, { size: 18 }),
|
|
72
|
+
children: P("botlit.mcpServers.purpose", "MCP (Model Context Protocol) servers are how your agents reach the outside world — they expose real tools an agent can call, like searching the web, reading a GitHub repo, querying a database or posting to Slack. Connect a server here and its tools become available to your agents (gated by your tool policies), turning a chatbot into something that can take action.")
|
|
72
73
|
}),
|
|
73
|
-
|
|
74
|
+
L ? /* @__PURE__ */ E("div", {
|
|
74
75
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
75
76
|
children: [
|
|
76
77
|
1,
|
|
77
78
|
2,
|
|
78
79
|
3
|
|
79
|
-
].map((e) => /* @__PURE__ */
|
|
80
|
-
}) :
|
|
80
|
+
].map((e) => /* @__PURE__ */ E("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
81
|
+
}) : R ? /* @__PURE__ */ E(S, {
|
|
81
82
|
resource: "MCP servers",
|
|
82
|
-
error:
|
|
83
|
-
onRetry: () => void
|
|
84
|
-
}) :
|
|
83
|
+
error: R,
|
|
84
|
+
onRetry: () => void z()
|
|
85
|
+
}) : I.length > 0 ? /* @__PURE__ */ E("div", {
|
|
85
86
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
86
|
-
children:
|
|
87
|
+
children: I.map((e) => /* @__PURE__ */ D(d, { children: [/* @__PURE__ */ D(m, {
|
|
87
88
|
className: "flex flex-row items-start justify-between",
|
|
88
|
-
children: [/* @__PURE__ */
|
|
89
|
+
children: [/* @__PURE__ */ D("div", {
|
|
89
90
|
className: "flex items-start gap-3",
|
|
90
|
-
children: [/* @__PURE__ */
|
|
91
|
-
className: `p-2 rounded-lg ${
|
|
92
|
-
children:
|
|
93
|
-
}), /* @__PURE__ */
|
|
91
|
+
children: [/* @__PURE__ */ E("div", {
|
|
92
|
+
className: `p-2 rounded-lg ${n(e.status) ? "bg-status-success-bg-subtle" : "bg-bg-sunken"}`,
|
|
93
|
+
children: n(e.status) ? /* @__PURE__ */ E(k, { className: "h-5 w-5 text-status-success-text" }) : /* @__PURE__ */ E(O, { className: "h-5 w-5 text-text-secondary" })
|
|
94
|
+
}), /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E(h, {
|
|
94
95
|
className: "text-base",
|
|
95
96
|
children: e.name
|
|
96
|
-
}), /* @__PURE__ */
|
|
97
|
-
}), /* @__PURE__ */
|
|
98
|
-
}), /* @__PURE__ */
|
|
97
|
+
}), /* @__PURE__ */ E(p, { children: r(e) })] })]
|
|
98
|
+
}), /* @__PURE__ */ E(v, { status: e.status })]
|
|
99
|
+
}), /* @__PURE__ */ E(f, { children: /* @__PURE__ */ D("div", {
|
|
99
100
|
className: "space-y-4",
|
|
100
101
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ D("div", {
|
|
102
103
|
className: "flex flex-wrap items-center gap-4 text-sm",
|
|
103
|
-
children: [/* @__PURE__ */
|
|
104
|
+
children: [/* @__PURE__ */ E(_, {
|
|
104
105
|
variant: "outline",
|
|
105
106
|
className: "capitalize",
|
|
106
107
|
children: e.type.toLowerCase().replace("_", " ")
|
|
107
|
-
}), e.lastConnectedAt && /* @__PURE__ */
|
|
108
|
+
}), e.lastConnectedAt && /* @__PURE__ */ D("span", {
|
|
108
109
|
className: "text-text-secondary",
|
|
109
|
-
children: [
|
|
110
|
+
children: [
|
|
111
|
+
P("botlit.botsList.createdLabel", "Created"),
|
|
112
|
+
" ",
|
|
113
|
+
l(e.lastConnectedAt)
|
|
114
|
+
]
|
|
110
115
|
})]
|
|
111
116
|
}),
|
|
112
|
-
|
|
117
|
+
i(e) && /* @__PURE__ */ E("p", {
|
|
113
118
|
className: "truncate text-sm text-text-secondary",
|
|
114
|
-
children:
|
|
119
|
+
children: i(e)
|
|
115
120
|
}),
|
|
116
|
-
e.errorMessage && /* @__PURE__ */
|
|
121
|
+
e.errorMessage && /* @__PURE__ */ E("p", {
|
|
117
122
|
className: "text-sm text-status-error-text",
|
|
118
123
|
children: e.errorMessage
|
|
119
124
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ D("div", {
|
|
121
126
|
className: "flex items-center gap-2 pt-2 border-t border-border-subtle",
|
|
122
127
|
children: [
|
|
123
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ E(g, {
|
|
124
129
|
variant: "outline",
|
|
125
130
|
size: "sm",
|
|
126
|
-
onClick: () => void
|
|
127
|
-
isLoading:
|
|
128
|
-
children: "Test connection"
|
|
131
|
+
onClick: () => void Q(e),
|
|
132
|
+
isLoading: G.loading,
|
|
133
|
+
children: P("botlit.mcpServers.actions.testConnection", "Test connection")
|
|
129
134
|
}),
|
|
130
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ E(g, {
|
|
131
136
|
variant: "ghost",
|
|
132
137
|
size: "sm",
|
|
133
|
-
leftIcon: /* @__PURE__ */
|
|
134
|
-
onClick: () =>
|
|
135
|
-
children: "Configure"
|
|
138
|
+
leftIcon: /* @__PURE__ */ E(j, { size: 14 }),
|
|
139
|
+
onClick: () => F(`mcp/${e.id}`),
|
|
140
|
+
children: P("botlit.mcpServers.actions.configure", "Configure")
|
|
136
141
|
}),
|
|
137
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ E(g, {
|
|
138
143
|
variant: "ghost",
|
|
139
144
|
size: "icon",
|
|
140
145
|
className: "ml-auto",
|
|
141
146
|
"aria-label": `Disconnect ${e.name}`,
|
|
142
|
-
onClick: () => void
|
|
143
|
-
isLoading:
|
|
144
|
-
children: /* @__PURE__ */
|
|
147
|
+
onClick: () => void Z(e),
|
|
148
|
+
isLoading: U.loading,
|
|
149
|
+
children: /* @__PURE__ */ E(M, { size: 16 })
|
|
145
150
|
})
|
|
146
151
|
]
|
|
147
152
|
})
|
|
148
153
|
]
|
|
149
154
|
}) })] }, e.id))
|
|
150
|
-
}) : /* @__PURE__ */
|
|
155
|
+
}) : /* @__PURE__ */ E(y, {
|
|
151
156
|
illustration: "empty-generic",
|
|
152
|
-
title: "No MCP servers connected",
|
|
153
|
-
description: "Connect MCP servers to give your agents access to external tools and resources.",
|
|
154
|
-
action: /* @__PURE__ */
|
|
155
|
-
leftIcon: /* @__PURE__ */
|
|
156
|
-
onClick: () =>
|
|
157
|
-
children: "Add MCP Server"
|
|
157
|
+
title: P("botlit.mcpServers.empty.title", "No MCP servers connected"),
|
|
158
|
+
description: P("botlit.mcpServers.empty.description", "Connect MCP servers to give your agents access to external tools and resources."),
|
|
159
|
+
action: /* @__PURE__ */ E(g, {
|
|
160
|
+
leftIcon: /* @__PURE__ */ E(A, { size: 16 }),
|
|
161
|
+
onClick: () => q(!0),
|
|
162
|
+
children: P("botlit.mcpServers.actions.add", "Add MCP Server")
|
|
158
163
|
})
|
|
159
164
|
}),
|
|
160
|
-
/* @__PURE__ */
|
|
165
|
+
/* @__PURE__ */ D(w, {
|
|
161
166
|
treatment: "glass",
|
|
162
167
|
glow: !0,
|
|
163
168
|
className: "p-6",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
169
|
+
children: [/* @__PURE__ */ D("div", {
|
|
165
170
|
className: "mb-4",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
171
|
+
children: [/* @__PURE__ */ E("h2", {
|
|
167
172
|
className: "text-lg font-semibold tracking-tight text-text-primary",
|
|
168
|
-
children: "Popular MCP Servers"
|
|
169
|
-
}), /* @__PURE__ */
|
|
173
|
+
children: P("botlit.mcpServers.presets.title", "Popular MCP Servers")
|
|
174
|
+
}), /* @__PURE__ */ E("p", {
|
|
170
175
|
className: "text-sm text-text-secondary",
|
|
171
|
-
children: "Quick-add common MCP servers"
|
|
176
|
+
children: P("botlit.mcpServers.presets.description", "Quick-add common MCP servers")
|
|
172
177
|
})]
|
|
173
|
-
}), /* @__PURE__ */
|
|
178
|
+
}), /* @__PURE__ */ E("div", {
|
|
174
179
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
175
180
|
children: [
|
|
176
181
|
{
|
|
177
|
-
name: "GitHub",
|
|
178
|
-
description: "Repository management and code operations",
|
|
182
|
+
name: P("botlit.mcpServers.presets.github", "GitHub"),
|
|
183
|
+
description: P("botlit.mcpServers.presets.githubDesc", "Repository management and code operations"),
|
|
179
184
|
baseUrl: "https://mcp.github.com"
|
|
180
185
|
},
|
|
181
186
|
{
|
|
182
|
-
name: "Filesystem",
|
|
183
|
-
description: "Local file system access",
|
|
187
|
+
name: P("botlit.mcpServers.presets.filesystem", "Filesystem"),
|
|
188
|
+
description: P("botlit.mcpServers.presets.filesystemDesc", "Local file system access"),
|
|
184
189
|
baseUrl: "http://localhost:3001"
|
|
185
190
|
},
|
|
186
191
|
{
|
|
187
|
-
name: "Brave Search",
|
|
188
|
-
description: "Web search capabilities",
|
|
192
|
+
name: P("botlit.mcpServers.presets.braveSearch", "Brave Search"),
|
|
193
|
+
description: P("botlit.mcpServers.presets.braveSearchDesc", "Web search capabilities"),
|
|
189
194
|
baseUrl: "https://mcp.search.brave.com"
|
|
190
195
|
},
|
|
191
196
|
{
|
|
192
|
-
name: "PostgreSQL",
|
|
193
|
-
description: "Database queries and management",
|
|
197
|
+
name: P("botlit.mcpServers.presets.postgres", "PostgreSQL"),
|
|
198
|
+
description: P("botlit.mcpServers.presets.postgresDesc", "Database queries and management"),
|
|
194
199
|
baseUrl: "http://localhost:3002"
|
|
195
200
|
},
|
|
196
201
|
{
|
|
197
|
-
name: "Slack",
|
|
198
|
-
description: "Slack messaging integration",
|
|
202
|
+
name: P("botlit.mcpServers.presets.slack", "Slack"),
|
|
203
|
+
description: P("botlit.mcpServers.presets.slackDesc", "Slack messaging integration"),
|
|
199
204
|
baseUrl: "https://mcp.slack.com"
|
|
200
205
|
},
|
|
201
206
|
{
|
|
202
|
-
name: "Puppeteer",
|
|
203
|
-
description: "Browser automation",
|
|
207
|
+
name: P("botlit.mcpServers.presets.puppeteer", "Puppeteer"),
|
|
208
|
+
description: P("botlit.mcpServers.presets.puppeteerDesc", "Browser automation"),
|
|
204
209
|
baseUrl: "http://localhost:3003"
|
|
205
210
|
}
|
|
206
|
-
].map((e) => /* @__PURE__ */
|
|
211
|
+
].map((e) => /* @__PURE__ */ D("button", {
|
|
207
212
|
className: "p-4 text-left border border-border-subtle rounded-lg hover:bg-accent transition-colors",
|
|
208
213
|
onClick: () => {
|
|
209
|
-
|
|
214
|
+
Y({
|
|
210
215
|
name: e.name,
|
|
211
216
|
description: e.description,
|
|
212
217
|
transport: "HTTP_JSON",
|
|
213
218
|
baseUrl: e.baseUrl
|
|
214
|
-
}),
|
|
219
|
+
}), q(!0);
|
|
215
220
|
},
|
|
216
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ E("p", {
|
|
217
222
|
className: "font-medium",
|
|
218
223
|
children: e.name
|
|
219
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ E("p", {
|
|
220
225
|
className: "text-sm text-text-secondary mt-1",
|
|
221
226
|
children: e.description
|
|
222
227
|
})]
|
|
223
228
|
}, e.name))
|
|
224
229
|
})]
|
|
225
230
|
}),
|
|
226
|
-
|
|
231
|
+
K && /* @__PURE__ */ E("div", {
|
|
227
232
|
className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50",
|
|
228
|
-
children: /* @__PURE__ */
|
|
233
|
+
children: /* @__PURE__ */ D(d, {
|
|
229
234
|
className: "w-full max-w-lg",
|
|
230
|
-
children: [/* @__PURE__ */
|
|
235
|
+
children: [/* @__PURE__ */ D(m, { children: [/* @__PURE__ */ E(h, { children: P("botlit.mcpServers.form.title", "Add MCP Server") }), /* @__PURE__ */ E(p, { children: P("botlit.mcpServers.form.description", "Connect a new MCP server") })] }), /* @__PURE__ */ D(f, {
|
|
231
236
|
className: "space-y-4",
|
|
232
237
|
children: [
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
label: "Server Name",
|
|
238
|
+
/* @__PURE__ */ E(b, {
|
|
239
|
+
label: P("botlit.mcpServers.form.nameLabel", "Server Name"),
|
|
235
240
|
required: !0,
|
|
236
|
-
children: /* @__PURE__ */
|
|
237
|
-
placeholder: "e.g., GitHub",
|
|
238
|
-
value:
|
|
239
|
-
onChange: (e) =>
|
|
240
|
-
...
|
|
241
|
+
children: /* @__PURE__ */ E(x, {
|
|
242
|
+
placeholder: P("botlit.mcpServers.form.namePlaceholder", "e.g., GitHub"),
|
|
243
|
+
value: J.name,
|
|
244
|
+
onChange: (e) => Y({
|
|
245
|
+
...J,
|
|
241
246
|
name: e.target.value
|
|
242
247
|
})
|
|
243
248
|
})
|
|
244
249
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
246
|
-
label: "Description",
|
|
247
|
-
children: /* @__PURE__ */
|
|
248
|
-
placeholder: "What does this server do?",
|
|
249
|
-
value:
|
|
250
|
-
onChange: (e) =>
|
|
251
|
-
...
|
|
250
|
+
/* @__PURE__ */ E(b, {
|
|
251
|
+
label: P("botlit.mcpServers.form.descriptionLabel", "Description"),
|
|
252
|
+
children: /* @__PURE__ */ E(x, {
|
|
253
|
+
placeholder: P("botlit.mcpServers.form.descriptionPlaceholder", "What does this server do?"),
|
|
254
|
+
value: J.description,
|
|
255
|
+
onChange: (e) => Y({
|
|
256
|
+
...J,
|
|
252
257
|
description: e.target.value
|
|
253
258
|
})
|
|
254
259
|
})
|
|
255
260
|
}),
|
|
256
|
-
/* @__PURE__ */
|
|
257
|
-
label: "Transport",
|
|
258
|
-
children: /* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ E(b, {
|
|
262
|
+
label: P("botlit.mcpServers.form.transportLabel", "Transport"),
|
|
263
|
+
children: /* @__PURE__ */ D("select", {
|
|
259
264
|
className: "flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm",
|
|
260
|
-
value:
|
|
261
|
-
onChange: (e) =>
|
|
262
|
-
...
|
|
265
|
+
value: J.transport,
|
|
266
|
+
onChange: (e) => Y({
|
|
267
|
+
...J,
|
|
263
268
|
transport: e.target.value
|
|
264
269
|
}),
|
|
265
270
|
children: [
|
|
266
|
-
/* @__PURE__ */
|
|
271
|
+
/* @__PURE__ */ E("option", {
|
|
267
272
|
value: "HTTP_JSON",
|
|
268
273
|
children: "HTTP JSON"
|
|
269
274
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ E("option", {
|
|
271
276
|
value: "JSON_RPC",
|
|
272
277
|
children: "JSON RPC"
|
|
273
278
|
}),
|
|
274
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ E("option", {
|
|
275
280
|
value: "SSE",
|
|
276
281
|
children: "Server-Sent Events"
|
|
277
282
|
}),
|
|
278
|
-
/* @__PURE__ */
|
|
283
|
+
/* @__PURE__ */ E("option", {
|
|
279
284
|
value: "CUSTOM",
|
|
280
285
|
children: "Custom"
|
|
281
286
|
})
|
|
282
287
|
]
|
|
283
288
|
})
|
|
284
289
|
}),
|
|
285
|
-
/* @__PURE__ */
|
|
286
|
-
label: "Base URL",
|
|
290
|
+
/* @__PURE__ */ E(b, {
|
|
291
|
+
label: P("botlit.mcpServers.form.baseUrlLabel", "Base URL"),
|
|
287
292
|
required: !0,
|
|
288
|
-
children: /* @__PURE__ */
|
|
289
|
-
placeholder: "e.g., https://mcp.example.com",
|
|
290
|
-
value:
|
|
291
|
-
onChange: (e) =>
|
|
292
|
-
...
|
|
293
|
+
children: /* @__PURE__ */ E(x, {
|
|
294
|
+
placeholder: P("botlit.mcpServers.form.baseUrlPlaceholder", "e.g., https://mcp.example.com"),
|
|
295
|
+
value: J.baseUrl,
|
|
296
|
+
onChange: (e) => Y({
|
|
297
|
+
...J,
|
|
293
298
|
baseUrl: e.target.value
|
|
294
299
|
})
|
|
295
300
|
})
|
|
296
301
|
}),
|
|
297
|
-
/* @__PURE__ */
|
|
302
|
+
/* @__PURE__ */ D("div", {
|
|
298
303
|
className: "flex justify-end gap-2 pt-4",
|
|
299
|
-
children: [/* @__PURE__ */
|
|
304
|
+
children: [/* @__PURE__ */ E(g, {
|
|
300
305
|
variant: "outline",
|
|
301
|
-
onClick: () =>
|
|
302
|
-
children: "Cancel"
|
|
303
|
-
}), /* @__PURE__ */
|
|
304
|
-
onClick:
|
|
305
|
-
isLoading:
|
|
306
|
-
disabled: !
|
|
307
|
-
children: "Connect"
|
|
306
|
+
onClick: () => q(!1),
|
|
307
|
+
children: P("botlit.mcpServers.actions.cancel", "Cancel")
|
|
308
|
+
}), /* @__PURE__ */ E(g, {
|
|
309
|
+
onClick: X,
|
|
310
|
+
isLoading: V.loading,
|
|
311
|
+
disabled: !J.name || !J.baseUrl,
|
|
312
|
+
children: P("botlit.mcpServers.actions.connect", "Connect")
|
|
308
313
|
})]
|
|
309
314
|
})
|
|
310
315
|
]
|
|
@@ -316,6 +321,6 @@ var N = () => {
|
|
|
316
321
|
});
|
|
317
322
|
};
|
|
318
323
|
//#endregion
|
|
319
|
-
export {
|
|
324
|
+
export { P as MCPServersPage };
|
|
320
325
|
|
|
321
326
|
//# sourceMappingURL=MCPServersPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MCPServersPage.js","names":[],"sources":["../../../src/botlit/pages/MCPServersPage.tsx"],"sourcesContent":["/**\n * MCP Servers Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { Plus, Plug, PlugZap, Settings, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, FormField } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useMCPServers,\n useCreateMCPServer,\n useDeleteMCPServer,\n useTestMCPConnection,\n isMCPServerHealthy,\n mcpServerDescription,\n mcpServerEndpoint,\n type MCPServerRecord,\n} from '../hooks/useMCPServers';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { MCPTransport } from '../types';\n\nexport const MCPServersPage: FC = () => {\n const { navigateTo } = useBotlit();\n const { data: servers, loading, error, refetch } = useMCPServers();\n const [connectServer, connectResult] = useCreateMCPServer();\n const [deleteServer, deleteResult] = useDeleteMCPServer();\n const [testConnection, testResult] = useTestMCPConnection();\n const [showAddModal, setShowAddModal] = useState(false);\n const [newServer, setNewServer] = useState({\n name: '',\n description: '',\n transport: 'HTTP_JSON' as MCPTransport,\n baseUrl: '',\n });\n\n const handleConnect = async () => {\n if (!newServer.name || !newServer.baseUrl) return;\n\n try {\n await connectServer({\n name: newServer.name,\n type: newServer.transport,\n config: {\n url: newServer.baseUrl,\n description: newServer.description,\n },\n });\n } catch (err) {\n // Keep the dialog open so the operator can correct and retry — closing it\n // here is what made failed writes look like successes.\n toast.error(err instanceof Error ? err.message : 'Failed to connect MCP server');\n return;\n }\n\n toast.success(`Connected \"${newServer.name}\"`);\n void refetch();\n setNewServer({ name: '', description: '', transport: 'HTTP_JSON', baseUrl: '' });\n setShowAddModal(false);\n };\n\n const handleDisconnect = async (server: MCPServerRecord) => {\n try {\n await deleteServer(server.id);\n toast.success(`Disconnected \"${server.name}\"`);\n void refetch();\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to disconnect MCP server');\n }\n };\n\n const handleTest = async (server: MCPServerRecord) => {\n try {\n const ok = await testConnection(server.id);\n if (ok) {\n toast.success(`\"${server.name}\" is reachable`);\n } else {\n toast.error(`\"${server.name}\" did not respond`);\n }\n void refetch();\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to test MCP connection');\n }\n };\n\n return (\n <PageLayout\n title=\"MCP Servers\"\n description=\"Connect Model Context Protocol servers to extend agent capabilities\"\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n Add MCP Server\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Plug size={18} />}>\n MCP (Model Context Protocol) servers are how your agents reach the outside world — they\n expose real tools an agent can call, like searching the web, reading a GitHub repo,\n querying a database or posting to Slack. Connect a server here and its tools become\n available to your agents (gated by your tool policies), turning a chatbot into something\n that can take action.\n </PagePurpose>\n\n {/* Server List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"MCP servers\" error={error} onRetry={() => void refetch()} />\n ) : servers.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {servers.map((server: MCPServerRecord) => (\n <Card key={server.id}>\n <CardHeader className=\"flex flex-row items-start justify-between\">\n <div className=\"flex items-start gap-3\">\n <div\n className={`p-2 rounded-lg ${\n isMCPServerHealthy(server.status)\n ? 'bg-status-success-bg-subtle'\n : 'bg-bg-sunken'\n }`}\n >\n {isMCPServerHealthy(server.status) ? (\n <PlugZap className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <Plug className=\"h-5 w-5 text-text-secondary\" />\n )}\n </div>\n <div>\n <CardTitle className=\"text-base\">{server.name}</CardTitle>\n <CardDescription>{mcpServerDescription(server)}</CardDescription>\n </div>\n </div>\n <StatusBadge status={server.status} />\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {/* Transport Info */}\n <div className=\"flex flex-wrap items-center gap-4 text-sm\">\n <Badge variant=\"outline\" className=\"capitalize\">\n {server.type.toLowerCase().replace('_', ' ')}\n </Badge>\n {server.lastConnectedAt && (\n <span className=\"text-text-secondary\">\n Last connected {formatRelativeTime(server.lastConnectedAt)}\n </span>\n )}\n </div>\n\n {/* Endpoint */}\n {mcpServerEndpoint(server) && (\n <p className=\"truncate text-sm text-text-secondary\">\n {mcpServerEndpoint(server)}\n </p>\n )}\n\n {server.errorMessage && (\n <p className=\"text-sm text-status-error-text\">{server.errorMessage}</p>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center gap-2 pt-2 border-t border-border-subtle\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void handleTest(server)}\n isLoading={testResult.loading}\n >\n Test connection\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Settings size={14} />}\n onClick={() => navigateTo(`mcp/${server.id}`)}\n >\n Configure\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto\"\n aria-label={`Disconnect ${server.name}`}\n onClick={() => void handleDisconnect(server)}\n isLoading={deleteResult.loading}\n >\n <Trash2 size={16} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No MCP servers connected\"\n description=\"Connect MCP servers to give your agents access to external tools and resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n Add MCP Server\n </Button>\n }\n />\n )}\n\n {/* Available MCP Servers */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n Popular MCP Servers\n </h2>\n <p className=\"text-sm text-text-secondary\">Quick-add common MCP servers</p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n {[\n {\n name: 'GitHub',\n description: 'Repository management and code operations',\n baseUrl: 'https://mcp.github.com',\n },\n {\n name: 'Filesystem',\n description: 'Local file system access',\n baseUrl: 'http://localhost:3001',\n },\n {\n name: 'Brave Search',\n description: 'Web search capabilities',\n baseUrl: 'https://mcp.search.brave.com',\n },\n {\n name: 'PostgreSQL',\n description: 'Database queries and management',\n baseUrl: 'http://localhost:3002',\n },\n {\n name: 'Slack',\n description: 'Slack messaging integration',\n baseUrl: 'https://mcp.slack.com',\n },\n {\n name: 'Puppeteer',\n description: 'Browser automation',\n baseUrl: 'http://localhost:3003',\n },\n ].map((preset) => (\n <button\n key={preset.name}\n className=\"p-4 text-left border border-border-subtle rounded-lg hover:bg-accent transition-colors\"\n onClick={() => {\n setNewServer({\n name: preset.name,\n description: preset.description,\n transport: 'HTTP_JSON',\n baseUrl: preset.baseUrl,\n });\n setShowAddModal(true);\n }}\n >\n <p className=\"font-medium\">{preset.name}</p>\n <p className=\"text-sm text-text-secondary mt-1\">{preset.description}</p>\n </button>\n ))}\n </div>\n </GlassCard>\n\n {/* Add Server Modal */}\n {showAddModal && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-lg\">\n <CardHeader>\n <CardTitle>Add MCP Server</CardTitle>\n <CardDescription>Connect a new MCP server</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Server Name\" required>\n <Input\n placeholder=\"e.g., GitHub\"\n value={newServer.name}\n onChange={(e) => setNewServer({ ...newServer, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Input\n placeholder=\"What does this server do?\"\n value={newServer.description}\n onChange={(e) => setNewServer({ ...newServer, description: e.target.value })}\n />\n </FormField>\n <FormField label=\"Transport\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={newServer.transport}\n onChange={(e) =>\n setNewServer({ ...newServer, transport: e.target.value as MCPTransport })\n }\n >\n <option value=\"HTTP_JSON\">HTTP JSON</option>\n <option value=\"JSON_RPC\">JSON RPC</option>\n <option value=\"SSE\">Server-Sent Events</option>\n <option value=\"CUSTOM\">Custom</option>\n </select>\n </FormField>\n <FormField label=\"Base URL\" required>\n <Input\n placeholder=\"e.g., https://mcp.example.com\"\n value={newServer.baseUrl}\n onChange={(e) => setNewServer({ ...newServer, baseUrl: e.target.value })}\n />\n </FormField>\n <div className=\"flex justify-end gap-2 pt-4\">\n <Button variant=\"outline\" onClick={() => setShowAddModal(false)}>\n Cancel\n </Button>\n <Button\n onClick={handleConnect}\n isLoading={connectResult.loading}\n disabled={!newServer.name || !newServer.baseUrl}\n >\n Connect\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MCPServersPage.js","names":[],"sources":["../../../src/botlit/pages/MCPServersPage.tsx"],"sourcesContent":["/**\n * MCP Servers Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { Plus, Plug, PlugZap, Settings, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, FormField } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useMCPServers,\n useCreateMCPServer,\n useDeleteMCPServer,\n useTestMCPConnection,\n isMCPServerHealthy,\n mcpServerDescription,\n mcpServerEndpoint,\n type MCPServerRecord,\n} from '../hooks/useMCPServers';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { MCPTransport } from '../types';\n\nexport const MCPServersPage: FC = () => {\n const t = useTr();\n const { navigateTo } = useBotlit();\n const { data: servers, loading, error, refetch } = useMCPServers();\n const [connectServer, connectResult] = useCreateMCPServer();\n const [deleteServer, deleteResult] = useDeleteMCPServer();\n const [testConnection, testResult] = useTestMCPConnection();\n const [showAddModal, setShowAddModal] = useState(false);\n const [newServer, setNewServer] = useState({\n name: '',\n description: '',\n transport: 'HTTP_JSON' as MCPTransport,\n baseUrl: '',\n });\n\n const handleConnect = async () => {\n if (!newServer.name || !newServer.baseUrl) return;\n\n try {\n await connectServer({\n name: newServer.name,\n type: newServer.transport,\n config: {\n url: newServer.baseUrl,\n description: newServer.description,\n },\n });\n } catch (err) {\n // Keep the dialog open so the operator can correct and retry — closing it\n // here is what made failed writes look like successes.\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.mcpServers.toast.connectError', 'Failed to connect MCP server')\n );\n return;\n }\n\n toast.success(\n t('botlit.mcpServers.toast.connectSuccess', 'Connected \"{{name}}\"', {\n name: newServer.name,\n })\n );\n void refetch();\n setNewServer({ name: '', description: '', transport: 'HTTP_JSON', baseUrl: '' });\n setShowAddModal(false);\n };\n\n const handleDisconnect = async (server: MCPServerRecord) => {\n try {\n await deleteServer(server.id);\n toast.success(\n t('botlit.mcpServers.toast.disconnectSuccess', 'Disconnected \"{{name}}\"', {\n name: server.name,\n })\n );\n void refetch();\n } catch (err) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.mcpServers.toast.disconnectError', 'Failed to disconnect MCP server')\n );\n }\n };\n\n const handleTest = async (server: MCPServerRecord) => {\n try {\n const ok = await testConnection(server.id);\n if (ok) {\n toast.success(\n t('botlit.mcpServers.toast.reachable', '\"{{name}}\" is reachable', {\n name: server.name,\n })\n );\n } else {\n toast.error(\n t('botlit.mcpServers.toast.unreachable', '\"{{name}}\" did not respond', {\n name: server.name,\n })\n );\n }\n void refetch();\n } catch (err) {\n toast.error(\n err instanceof Error\n ? err.message\n : t('botlit.mcpServers.toast.testError', 'Failed to test MCP connection')\n );\n }\n };\n\n return (\n <PageLayout\n title={t('botlit.mcpServers.title', 'MCP Servers')}\n description={t(\n 'botlit.mcpServers.description',\n 'Connect Model Context Protocol servers to extend agent capabilities'\n )}\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n {t('botlit.mcpServers.actions.add', 'Add MCP Server')}\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Plug size={18} />}>\n {t(\n 'botlit.mcpServers.purpose',\n 'MCP (Model Context Protocol) servers are how your agents reach the outside world — they expose real tools an agent can call, like searching the web, reading a GitHub repo, querying a database or posting to Slack. Connect a server here and its tools become available to your agents (gated by your tool policies), turning a chatbot into something that can take action.'\n )}\n </PagePurpose>\n\n {/* Server List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"MCP servers\" error={error} onRetry={() => void refetch()} />\n ) : servers.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {servers.map((server: MCPServerRecord) => (\n <Card key={server.id}>\n <CardHeader className=\"flex flex-row items-start justify-between\">\n <div className=\"flex items-start gap-3\">\n <div\n className={`p-2 rounded-lg ${\n isMCPServerHealthy(server.status)\n ? 'bg-status-success-bg-subtle'\n : 'bg-bg-sunken'\n }`}\n >\n {isMCPServerHealthy(server.status) ? (\n <PlugZap className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <Plug className=\"h-5 w-5 text-text-secondary\" />\n )}\n </div>\n <div>\n <CardTitle className=\"text-base\">{server.name}</CardTitle>\n <CardDescription>{mcpServerDescription(server)}</CardDescription>\n </div>\n </div>\n <StatusBadge status={server.status} />\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {/* Transport Info */}\n <div className=\"flex flex-wrap items-center gap-4 text-sm\">\n <Badge variant=\"outline\" className=\"capitalize\">\n {server.type.toLowerCase().replace('_', ' ')}\n </Badge>\n {server.lastConnectedAt && (\n <span className=\"text-text-secondary\">\n {t('botlit.botsList.createdLabel', 'Created')}{' '}\n {formatRelativeTime(server.lastConnectedAt)}\n </span>\n )}\n </div>\n\n {/* Endpoint */}\n {mcpServerEndpoint(server) && (\n <p className=\"truncate text-sm text-text-secondary\">\n {mcpServerEndpoint(server)}\n </p>\n )}\n\n {server.errorMessage && (\n <p className=\"text-sm text-status-error-text\">{server.errorMessage}</p>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center gap-2 pt-2 border-t border-border-subtle\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void handleTest(server)}\n isLoading={testResult.loading}\n >\n {t('botlit.mcpServers.actions.testConnection', 'Test connection')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Settings size={14} />}\n onClick={() => navigateTo(`mcp/${server.id}`)}\n >\n {t('botlit.mcpServers.actions.configure', 'Configure')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto\"\n aria-label={`Disconnect ${server.name}`}\n onClick={() => void handleDisconnect(server)}\n isLoading={deleteResult.loading}\n >\n <Trash2 size={16} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={t('botlit.mcpServers.empty.title', 'No MCP servers connected')}\n description={t(\n 'botlit.mcpServers.empty.description',\n 'Connect MCP servers to give your agents access to external tools and resources.'\n )}\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n {t('botlit.mcpServers.actions.add', 'Add MCP Server')}\n </Button>\n }\n />\n )}\n\n {/* Available MCP Servers */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {t('botlit.mcpServers.presets.title', 'Popular MCP Servers')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.mcpServers.presets.description', 'Quick-add common MCP servers')}\n </p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n {[\n {\n name: t('botlit.mcpServers.presets.github', 'GitHub'),\n description: t(\n 'botlit.mcpServers.presets.githubDesc',\n 'Repository management and code operations'\n ),\n baseUrl: 'https://mcp.github.com',\n },\n {\n name: t('botlit.mcpServers.presets.filesystem', 'Filesystem'),\n description: t(\n 'botlit.mcpServers.presets.filesystemDesc',\n 'Local file system access'\n ),\n baseUrl: 'http://localhost:3001',\n },\n {\n name: t('botlit.mcpServers.presets.braveSearch', 'Brave Search'),\n description: t(\n 'botlit.mcpServers.presets.braveSearchDesc',\n 'Web search capabilities'\n ),\n baseUrl: 'https://mcp.search.brave.com',\n },\n {\n name: t('botlit.mcpServers.presets.postgres', 'PostgreSQL'),\n description: t(\n 'botlit.mcpServers.presets.postgresDesc',\n 'Database queries and management'\n ),\n baseUrl: 'http://localhost:3002',\n },\n {\n name: t('botlit.mcpServers.presets.slack', 'Slack'),\n description: t(\n 'botlit.mcpServers.presets.slackDesc',\n 'Slack messaging integration'\n ),\n baseUrl: 'https://mcp.slack.com',\n },\n {\n name: t('botlit.mcpServers.presets.puppeteer', 'Puppeteer'),\n description: t('botlit.mcpServers.presets.puppeteerDesc', 'Browser automation'),\n baseUrl: 'http://localhost:3003',\n },\n ].map((preset) => (\n <button\n key={preset.name}\n className=\"p-4 text-left border border-border-subtle rounded-lg hover:bg-accent transition-colors\"\n onClick={() => {\n setNewServer({\n name: preset.name,\n description: preset.description,\n transport: 'HTTP_JSON',\n baseUrl: preset.baseUrl,\n });\n setShowAddModal(true);\n }}\n >\n <p className=\"font-medium\">{preset.name}</p>\n <p className=\"text-sm text-text-secondary mt-1\">{preset.description}</p>\n </button>\n ))}\n </div>\n </GlassCard>\n\n {/* Add Server Modal */}\n {showAddModal && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-lg\">\n <CardHeader>\n <CardTitle>{t('botlit.mcpServers.form.title', 'Add MCP Server')}</CardTitle>\n <CardDescription>\n {t('botlit.mcpServers.form.description', 'Connect a new MCP server')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label={t('botlit.mcpServers.form.nameLabel', 'Server Name')} required>\n <Input\n placeholder={t('botlit.mcpServers.form.namePlaceholder', 'e.g., GitHub')}\n value={newServer.name}\n onChange={(e) => setNewServer({ ...newServer, name: e.target.value })}\n />\n </FormField>\n <FormField label={t('botlit.mcpServers.form.descriptionLabel', 'Description')}>\n <Input\n placeholder={t(\n 'botlit.mcpServers.form.descriptionPlaceholder',\n 'What does this server do?'\n )}\n value={newServer.description}\n onChange={(e) => setNewServer({ ...newServer, description: e.target.value })}\n />\n </FormField>\n <FormField label={t('botlit.mcpServers.form.transportLabel', 'Transport')}>\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={newServer.transport}\n onChange={(e) =>\n setNewServer({ ...newServer, transport: e.target.value as MCPTransport })\n }\n >\n <option value=\"HTTP_JSON\">HTTP JSON</option>\n <option value=\"JSON_RPC\">JSON RPC</option>\n <option value=\"SSE\">Server-Sent Events</option>\n <option value=\"CUSTOM\">Custom</option>\n </select>\n </FormField>\n <FormField label={t('botlit.mcpServers.form.baseUrlLabel', 'Base URL')} required>\n <Input\n placeholder={t(\n 'botlit.mcpServers.form.baseUrlPlaceholder',\n 'e.g., https://mcp.example.com'\n )}\n value={newServer.baseUrl}\n onChange={(e) => setNewServer({ ...newServer, baseUrl: e.target.value })}\n />\n </FormField>\n <div className=\"flex justify-end gap-2 pt-4\">\n <Button variant=\"outline\" onClick={() => setShowAddModal(false)}>\n {t('botlit.mcpServers.actions.cancel', 'Cancel')}\n </Button>\n <Button\n onClick={handleConnect}\n isLoading={connectResult.loading}\n disabled={!newServer.name || !newServer.baseUrl}\n >\n {t('botlit.mcpServers.actions.connect', 'Connect')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|