@executor-js/plugin-mcp 1.4.32 → 1.5.0

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.
Files changed (57) hide show
  1. package/dist/AddMcpSource-4LLERUW5.js +602 -0
  2. package/dist/AddMcpSource-4LLERUW5.js.map +1 -0
  3. package/dist/EditMcpSource-GKJRP75X.js +313 -0
  4. package/dist/EditMcpSource-GKJRP75X.js.map +1 -0
  5. package/dist/McpAccountsPanel-UX7MHEIG.js +132 -0
  6. package/dist/McpAccountsPanel-UX7MHEIG.js.map +1 -0
  7. package/dist/api/group.d.ts +79 -143
  8. package/dist/api/index.d.ts +99 -155
  9. package/dist/chunk-2TXHTMKM.js +1298 -0
  10. package/dist/chunk-2TXHTMKM.js.map +1 -0
  11. package/dist/chunk-6OEQZ72N.js +124 -0
  12. package/dist/chunk-6OEQZ72N.js.map +1 -0
  13. package/dist/chunk-7FJ3PUUL.js +21 -0
  14. package/dist/chunk-7FJ3PUUL.js.map +1 -0
  15. package/dist/chunk-N4EAF5CA.js +146 -0
  16. package/dist/chunk-N4EAF5CA.js.map +1 -0
  17. package/dist/client.js +9 -9
  18. package/dist/client.js.map +1 -1
  19. package/dist/core.js +36 -26
  20. package/dist/index.js +2 -2
  21. package/dist/promise.d.ts +1 -1
  22. package/dist/react/AddMcpSource.d.ts +1 -1
  23. package/dist/react/McpAccountsPanel.d.ts +6 -0
  24. package/dist/react/McpRemoteSourceFields.d.ts +4 -2
  25. package/dist/react/McpSignInButton.d.ts +2 -0
  26. package/dist/react/atoms.d.ts +93 -313
  27. package/dist/react/auth-method-config.d.ts +8 -0
  28. package/dist/react/client.d.ts +78 -142
  29. package/dist/react/index.d.ts +3 -3
  30. package/dist/react/source-plugin.d.ts +5 -5
  31. package/dist/sdk/connection.d.ts +4 -4
  32. package/dist/sdk/errors.d.ts +0 -19
  33. package/dist/sdk/index.d.ts +4 -3
  34. package/dist/sdk/invoke.d.ts +9 -16
  35. package/dist/sdk/plugin.d.ts +101 -236
  36. package/dist/sdk/types.d.ts +25 -130
  37. package/package.json +5 -4
  38. package/dist/AddMcpSource-PADMBVX2.js +0 -688
  39. package/dist/AddMcpSource-PADMBVX2.js.map +0 -1
  40. package/dist/EditMcpSource-L5GC2B4J.js +0 -281
  41. package/dist/EditMcpSource-L5GC2B4J.js.map +0 -1
  42. package/dist/McpSourceSummary-LE3WXFUE.js +0 -170
  43. package/dist/McpSourceSummary-LE3WXFUE.js.map +0 -1
  44. package/dist/chunk-6OYEXHU3.js +0 -156
  45. package/dist/chunk-6OYEXHU3.js.map +0 -1
  46. package/dist/chunk-FMTVLO5L.js +0 -179
  47. package/dist/chunk-FMTVLO5L.js.map +0 -1
  48. package/dist/chunk-LEGVPKYH.js +0 -2391
  49. package/dist/chunk-LEGVPKYH.js.map +0 -1
  50. package/dist/chunk-ZIRGIRGP.js +0 -115
  51. package/dist/chunk-ZIRGIRGP.js.map +0 -1
  52. package/dist/react/McpSourceSummary.d.ts +0 -5
  53. package/dist/sdk/binding-store.d.ts +0 -31
  54. package/dist/sdk/stored-source.d.ts +0 -42
  55. /package/dist/{sdk/connection-pool.test.d.ts → react/auth-method-config.test.d.ts} +0 -0
  56. /package/dist/sdk/{cross-user-isolation.test.d.ts → describe-auth-methods.test.d.ts} +0 -0
  57. /package/dist/sdk/{per-user-auth-isolation.test.d.ts → owner-isolation.test.d.ts} +0 -0
@@ -0,0 +1,602 @@
1
+ import {
2
+ mcpPresets
3
+ } from "./chunk-TW44CBXJ.js";
4
+ import {
5
+ mcpAuthTemplateFromEditorValue
6
+ } from "./chunk-7FJ3PUUL.js";
7
+ import {
8
+ addMcpServer,
9
+ probeMcpEndpoint
10
+ } from "./chunk-N4EAF5CA.js";
11
+ import "./chunk-6OEQZ72N.js";
12
+
13
+ // src/react/AddMcpSource.tsx
14
+ import { useReducer, useCallback, useEffect, useMemo, useRef, useState } from "react";
15
+ import { useAtomSet, useAtomValue } from "@effect/atom-react";
16
+ import { Link } from "@tanstack/react-router";
17
+ import * as Exit from "effect/Exit";
18
+ import * as Match from "effect/Match";
19
+ import * as Option from "effect/Option";
20
+ import * as Predicate from "effect/Predicate";
21
+ import * as Schema from "effect/Schema";
22
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
23
+ import { integrationsOptimisticAtom } from "@executor-js/react/api/atoms";
24
+ import { Button as Button2 } from "@executor-js/react/components/button";
25
+ import {
26
+ AuthTemplateEditor
27
+ } from "@executor-js/react/components/auth-template-editor";
28
+ import {
29
+ CardStack as CardStack2,
30
+ CardStackContent as CardStackContent2,
31
+ CardStackEntryField as CardStackEntryField2
32
+ } from "@executor-js/react/components/card-stack";
33
+ import { FieldLabel } from "@executor-js/react/components/field";
34
+ import { FloatActions } from "@executor-js/react/components/float-actions";
35
+ import { Input as Input2 } from "@executor-js/react/components/input";
36
+ import { Spinner } from "@executor-js/react/components/spinner";
37
+ import { Textarea } from "@executor-js/react/components/textarea";
38
+ import {
39
+ integrationDisplayNameFromUrl,
40
+ slugifyNamespace,
41
+ IntegrationIdentityFields,
42
+ useIntegrationIdentity
43
+ } from "@executor-js/react/plugins/integration-identity";
44
+ import { integrationWriteKeys } from "@executor-js/react/api/reactivity-keys";
45
+
46
+ // src/react/McpRemoteSourceFields.tsx
47
+ import { Badge } from "@executor-js/react/components/badge";
48
+ import {
49
+ CardStack,
50
+ CardStackContent,
51
+ CardStackEntry,
52
+ CardStackEntryActions,
53
+ CardStackEntryContent,
54
+ CardStackEntryDescription,
55
+ CardStackEntryField,
56
+ CardStackEntryMedia,
57
+ CardStackEntryTitle
58
+ } from "@executor-js/react/components/card-stack";
59
+ import { FieldError } from "@executor-js/react/components/field";
60
+ import { Input } from "@executor-js/react/components/input";
61
+ import { Skeleton } from "@executor-js/react/components/skeleton";
62
+ import { IntegrationFavicon } from "@executor-js/react/components/integration-favicon";
63
+ import { IOSSpinner } from "@executor-js/react/components/spinner";
64
+ import { Button } from "@executor-js/react/components/button";
65
+ import {
66
+ IntegrationIdentityFieldRows
67
+ } from "@executor-js/react/plugins/integration-identity";
68
+ import { jsx, jsxs } from "react/jsx-runtime";
69
+ function McpRemoteSourceFields(props) {
70
+ const previewDescription = props.preview ? props.preview.connected ? props.preview.toolCount === null ? null : `${props.preview.toolCount} tool${props.preview.toolCount !== 1 ? "s" : ""} available` : props.preview.requiresOAuth ? "OAuth required to discover tools" : props.preview.requiresAuthentication ? "Authentication required to discover tools" : "Ready to add" : null;
71
+ if (props.preview) {
72
+ return /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsxs(CardStackContent, { className: "border-t-0", children: [
73
+ /* @__PURE__ */ jsxs(CardStackEntry, { children: [
74
+ /* @__PURE__ */ jsx(CardStackEntryMedia, { children: /* @__PURE__ */ jsx(IntegrationFavicon, { url: props.url, size: 32 }) }),
75
+ /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
76
+ /* @__PURE__ */ jsx(CardStackEntryTitle, { children: props.preview.serverName ?? props.preview.name }),
77
+ previewDescription ? /* @__PURE__ */ jsx(CardStackEntryDescription, { children: previewDescription }) : null
78
+ ] }),
79
+ /* @__PURE__ */ jsx(CardStackEntryActions, { children: props.preview.connected ? /* @__PURE__ */ jsx(
80
+ Badge,
81
+ {
82
+ variant: "outline",
83
+ className: "border-emerald-500/20 bg-emerald-500/10 text-[10px] text-emerald-600 dark:text-emerald-400",
84
+ children: "Connected"
85
+ }
86
+ ) : props.preview.requiresOAuth ? /* @__PURE__ */ jsx(
87
+ Badge,
88
+ {
89
+ variant: "outline",
90
+ className: "border-amber-500/20 bg-amber-500/10 text-[10px] text-amber-600 dark:text-amber-400",
91
+ children: "OAuth required"
92
+ }
93
+ ) : /* @__PURE__ */ jsx(
94
+ Badge,
95
+ {
96
+ variant: "outline",
97
+ className: "border-amber-500/20 bg-amber-500/10 text-[10px] text-amber-600 dark:text-amber-400",
98
+ children: "Auth required"
99
+ }
100
+ ) })
101
+ ] }),
102
+ /* @__PURE__ */ jsx(
103
+ IntegrationIdentityFieldRows,
104
+ {
105
+ identity: props.identity,
106
+ namePlaceholder: "e.g. Linear",
107
+ namespaceReadOnly: props.namespaceReadOnly
108
+ }
109
+ ),
110
+ /* @__PURE__ */ jsx(CardStackEntryField, { label: "Server URL", children: /* @__PURE__ */ jsx(
111
+ Input,
112
+ {
113
+ value: props.url,
114
+ onChange: (e) => props.onUrlChange(e.target.value),
115
+ placeholder: "https://mcp.example.com",
116
+ className: "w-full font-mono text-sm",
117
+ disabled: props.urlDisabled
118
+ }
119
+ ) })
120
+ ] }) });
121
+ }
122
+ if (props.probing) {
123
+ return /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsx(CardStackContent, { className: "border-t-0", children: /* @__PURE__ */ jsxs(CardStackEntry, { children: [
124
+ /* @__PURE__ */ jsx(CardStackEntryMedia, { children: /* @__PURE__ */ jsx(Skeleton, { className: "size-4 rounded" }) }),
125
+ /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
126
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-40" }),
127
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-1 h-3 w-32" })
128
+ ] }),
129
+ /* @__PURE__ */ jsx(CardStackEntryActions, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20 rounded-full" }) })
130
+ ] }) }) });
131
+ }
132
+ return /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsx(CardStackContent, { className: "border-t-0", children: /* @__PURE__ */ jsxs(CardStackEntryField, { label: "Server URL", children: [
133
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
134
+ /* @__PURE__ */ jsx(
135
+ Input,
136
+ {
137
+ value: props.url,
138
+ onChange: (e) => props.onUrlChange(e.target.value),
139
+ placeholder: "https://mcp.example.com",
140
+ className: "w-full pr-9 font-mono text-sm",
141
+ "aria-invalid": props.error ? true : void 0,
142
+ disabled: props.urlDisabled
143
+ }
144
+ ),
145
+ props.probing && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx(IOSSpinner, { className: "size-4" }) })
146
+ ] }),
147
+ props.error && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2", children: [
148
+ /* @__PURE__ */ jsx(FieldError, { children: props.error }),
149
+ props.onRetry && /* @__PURE__ */ jsx(
150
+ Button,
151
+ {
152
+ type: "button",
153
+ variant: "outline",
154
+ size: "sm",
155
+ onClick: props.onRetry,
156
+ className: "h-7 px-2 text-xs",
157
+ children: "Try again"
158
+ }
159
+ )
160
+ ] })
161
+ ] }) }) });
162
+ }
163
+
164
+ // src/react/AddMcpSource.tsx
165
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
166
+ var ErrorMessage = Schema.Struct({ message: Schema.String });
167
+ var decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage);
168
+ var STDIO_ENV_ESCAPE_REPLACEMENTS = {
169
+ "\\": "\\",
170
+ n: "\n",
171
+ r: "\r",
172
+ t: " ",
173
+ '"': '"'
174
+ };
175
+ var errorMessageFromExit = (exit, fallback) => Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), {
176
+ onNone: () => fallback,
177
+ onSome: ({ message }) => message
178
+ });
179
+ var isIntegrationAlreadyExistsExit = (exit) => Option.match(Exit.findErrorOption(exit), {
180
+ onNone: () => false,
181
+ onSome: Predicate.isTagged("IntegrationAlreadyExistsError")
182
+ });
183
+ var integrationExistsMessage = (slug) => `An integration named "${slug}" already exists. To add more authentication, update your existing integration.`;
184
+ function findPreset(id) {
185
+ if (!id) return void 0;
186
+ return mcpPresets.find((p) => p.id === id);
187
+ }
188
+ var init = { step: "url", url: "" };
189
+ function reducer(state, action) {
190
+ return Match.value(action).pipe(
191
+ Match.discriminator("type")("set-url", (a) => ({ step: "url", url: a.url })),
192
+ Match.discriminator("type")(
193
+ "probe-start",
194
+ () => ({
195
+ step: "probing",
196
+ url: state.url,
197
+ probe: "probe" in state ? state.probe : null
198
+ })
199
+ ),
200
+ Match.discriminator("type")(
201
+ "probe-ok",
202
+ (a) => ({ step: "probed", url: state.url, probe: a.probe })
203
+ ),
204
+ Match.discriminator("type")(
205
+ "probe-fail",
206
+ (a) => ({
207
+ step: "error",
208
+ url: state.url,
209
+ probe: null,
210
+ error: a.error
211
+ })
212
+ ),
213
+ Match.discriminator("type")("add-start", () => {
214
+ const probe = "probe" in state ? state.probe : null;
215
+ if (!probe) return state;
216
+ return { step: "adding", url: state.url, probe };
217
+ }),
218
+ Match.discriminator("type")("add-fail", (a) => {
219
+ if (state.step !== "adding") return state;
220
+ return {
221
+ step: "error",
222
+ url: state.url,
223
+ probe: state.probe,
224
+ error: a.error
225
+ };
226
+ }),
227
+ Match.discriminator("type")("retry", () => {
228
+ if (state.step !== "error") return state;
229
+ return state.probe ? { step: "probed", url: state.url, probe: state.probe } : { step: "url", url: state.url };
230
+ }),
231
+ Match.exhaustive
232
+ );
233
+ }
234
+ function AddMcpSource(props) {
235
+ const allowStdio = props.allowStdio ?? false;
236
+ const rawPreset = findPreset(props.initialPreset);
237
+ const preset = rawPreset?.transport === "stdio" && !allowStdio ? void 0 : rawPreset;
238
+ const isStdioPreset = preset?.transport === "stdio";
239
+ const [transport, setTransport] = useState(
240
+ isStdioPreset && allowStdio ? "stdio" : "remote"
241
+ );
242
+ const [stdioCommand, setStdioCommand] = useState(isStdioPreset ? preset.command : "");
243
+ const [stdioArgs, setStdioArgs] = useState(
244
+ isStdioPreset && preset.args ? preset.args.join(" ") : ""
245
+ );
246
+ const [stdioEnv, setStdioEnv] = useState("");
247
+ const stdioIdentity = useIntegrationIdentity({
248
+ fallbackName: isStdioPreset ? preset.name : stdioCommand
249
+ });
250
+ const [stdioAdding, setStdioAdding] = useState(false);
251
+ const [stdioError, setStdioError] = useState(null);
252
+ const remoteUrl = !isStdioPreset && preset?.transport === void 0 && preset?.url ? preset.url : props.initialUrl ?? "";
253
+ const [state, dispatch] = useReducer(
254
+ reducer,
255
+ remoteUrl ? { step: "url", url: remoteUrl } : init
256
+ );
257
+ const doProbe = useAtomSet(probeMcpEndpoint, { mode: "promiseExit" });
258
+ const doAddServer = useAtomSet(addMcpServer, { mode: "promiseExit" });
259
+ const [authValue, setAuthValue] = useState({ kind: "none" });
260
+ const probe = "probe" in state ? state.probe : null;
261
+ const allowedAuthKinds = probe?.requiresOAuth && probe.supportsDynamicRegistration ? ["oauth"] : probe?.requiresAuthentication ? ["apikey", "oauth"] : ["none", "apikey", "oauth"];
262
+ const remoteIdentity = useIntegrationIdentity({
263
+ fallbackName: integrationDisplayNameFromUrl(state.url, "MCP") ?? probe?.serverName ?? probe?.name ?? ""
264
+ });
265
+ const isProbing = state.step === "probing";
266
+ const isAdding = state.step === "adding";
267
+ const integrationsResult = useAtomValue(integrationsOptimisticAtom);
268
+ const existingSlugs = useMemo(
269
+ () => AsyncResult.isSuccess(integrationsResult) ? integrationsResult.value.map((integration) => String(integration.slug)) : [],
270
+ [integrationsResult]
271
+ );
272
+ const remoteSlug = slugifyNamespace(remoteIdentity.namespace);
273
+ const stdioSlug = slugifyNamespace(stdioIdentity.namespace);
274
+ const remoteSlugExists = remoteSlug.length > 0 && existingSlugs.includes(remoteSlug);
275
+ const stdioSlugExists = stdioSlug.length > 0 && existingSlugs.includes(stdioSlug);
276
+ const canAdd = Boolean(probe) && !isAdding && !remoteSlugExists;
277
+ const probeError = state.step === "error" && state.probe === null ? state.error : null;
278
+ const otherError = state.step === "error" && state.probe !== null ? state.error : null;
279
+ const handleProbe = useCallback(async () => {
280
+ dispatch({ type: "probe-start" });
281
+ const exit = await doProbe({
282
+ payload: { endpoint: state.url.trim() }
283
+ });
284
+ if (Exit.isFailure(exit)) {
285
+ dispatch({
286
+ type: "probe-fail",
287
+ error: errorMessageFromExit(exit, "Failed to connect")
288
+ });
289
+ return;
290
+ }
291
+ setAuthValue(
292
+ exit.value.requiresOAuth ? { kind: "oauth", authorizationUrl: "", tokenUrl: "", scopes: [] } : exit.value.requiresAuthentication ? {
293
+ kind: "apikey",
294
+ placements: [{ carrier: "header", name: "Authorization", prefix: "Bearer " }]
295
+ } : { kind: "none" }
296
+ );
297
+ dispatch({ type: "probe-ok", probe: exit.value });
298
+ }, [state.url, doProbe]);
299
+ const handleProbeRef = useRef(handleProbe);
300
+ handleProbeRef.current = handleProbe;
301
+ useEffect(() => {
302
+ if (transport !== "remote") return;
303
+ if (state.step !== "url") return;
304
+ const trimmed = state.url.trim();
305
+ if (!trimmed) return;
306
+ const handle = setTimeout(() => {
307
+ handleProbeRef.current();
308
+ }, 400);
309
+ return () => clearTimeout(handle);
310
+ }, [transport, state.step, state.url]);
311
+ const registerIntegration = useCallback(
312
+ async (auth) => {
313
+ const displayName = remoteIdentity.name.trim() || probe?.serverName || probe?.name || "MCP";
314
+ const slug = slugifyNamespace(remoteIdentity.namespace) || void 0;
315
+ const exit = await doAddServer({
316
+ payload: {
317
+ transport: "remote",
318
+ name: displayName,
319
+ endpoint: state.url.trim(),
320
+ ...slug ? { slug } : {},
321
+ auth
322
+ },
323
+ reactivityKeys: integrationWriteKeys
324
+ });
325
+ if (Exit.isFailure(exit)) {
326
+ dispatch({
327
+ type: "add-fail",
328
+ error: isIntegrationAlreadyExistsExit(exit) ? integrationExistsMessage(slug ?? displayName) : errorMessageFromExit(exit, "Failed to add server")
329
+ });
330
+ return null;
331
+ }
332
+ return exit.value.slug;
333
+ },
334
+ [doAddServer, probe, remoteIdentity, state.url]
335
+ );
336
+ const handleAddRemote = useCallback(async () => {
337
+ if (!probe) return;
338
+ dispatch({ type: "add-start" });
339
+ const slug = await registerIntegration(mcpAuthTemplateFromEditorValue(authValue));
340
+ if (slug === null) return;
341
+ props.onComplete(slug);
342
+ }, [probe, authValue, registerIntegration, props]);
343
+ const parseStdioArgs = (raw) => {
344
+ if (!raw.trim()) return [];
345
+ const args = [];
346
+ const regex = /[^\s"]+|"([^"]*)"/g;
347
+ let match2;
348
+ while ((match2 = regex.exec(raw)) !== null) {
349
+ args.push(match2[1] ?? match2[0]);
350
+ }
351
+ return args;
352
+ };
353
+ const parseStdioEnvValue = (raw) => {
354
+ const value2 = raw.trim();
355
+ if (value2.length < 2) return value2;
356
+ const quote = value2[0];
357
+ if (quote !== '"' && quote !== "'" || value2[value2.length - 1] !== quote) {
358
+ return value2;
359
+ }
360
+ const inner = value2.slice(1, -1);
361
+ if (quote === "'") return inner;
362
+ return inner.replace(
363
+ /\\([\\nrt"])/g,
364
+ (_, escaped) => STDIO_ENV_ESCAPE_REPLACEMENTS[escaped] ?? escaped
365
+ );
366
+ };
367
+ const parseStdioEnv = (raw) => {
368
+ if (!raw.trim()) return void 0;
369
+ const env = {};
370
+ for (const line of raw.split("\n")) {
371
+ const eq = line.indexOf("=");
372
+ if (eq > 0) {
373
+ env[line.slice(0, eq).trim()] = parseStdioEnvValue(line.slice(eq + 1));
374
+ }
375
+ }
376
+ return Object.keys(env).length > 0 ? env : void 0;
377
+ };
378
+ const handleAddStdio = useCallback(async () => {
379
+ const cmd = stdioCommand.trim();
380
+ if (!cmd) return;
381
+ setStdioAdding(true);
382
+ setStdioError(null);
383
+ const displayName = stdioIdentity.name.trim() || cmd;
384
+ const slug = slugifyNamespace(stdioIdentity.namespace) || void 0;
385
+ const exit = await doAddServer({
386
+ payload: {
387
+ transport: "stdio",
388
+ name: displayName,
389
+ ...slug ? { slug } : {},
390
+ command: cmd,
391
+ args: parseStdioArgs(stdioArgs),
392
+ env: parseStdioEnv(stdioEnv)
393
+ },
394
+ reactivityKeys: integrationWriteKeys
395
+ });
396
+ if (Exit.isFailure(exit)) {
397
+ setStdioError(
398
+ isIntegrationAlreadyExistsExit(exit) ? integrationExistsMessage(slug ?? displayName) : errorMessageFromExit(exit, "Failed to add server")
399
+ );
400
+ setStdioAdding(false);
401
+ return;
402
+ }
403
+ props.onComplete(exit.value.slug);
404
+ }, [stdioCommand, stdioArgs, stdioEnv, stdioIdentity, doAddServer, props]);
405
+ return /* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-6", children: [
406
+ /* @__PURE__ */ jsxs2("div", { children: [
407
+ /* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold text-foreground", children: "Add MCP Source" }),
408
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 text-[13px] text-muted-foreground", children: "Connect to an MCP server to discover and use its tools." })
409
+ ] }),
410
+ allowStdio && /* @__PURE__ */ jsxs2("div", { className: "flex gap-1 rounded-lg border border-border bg-muted/30 p-1", children: [
411
+ /* @__PURE__ */ jsx2(
412
+ Button2,
413
+ {
414
+ variant: "ghost",
415
+ type: "button",
416
+ onClick: () => setTransport("remote"),
417
+ className: `flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${transport === "remote" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
418
+ children: "Remote"
419
+ }
420
+ ),
421
+ /* @__PURE__ */ jsx2(
422
+ Button2,
423
+ {
424
+ variant: "ghost",
425
+ type: "button",
426
+ onClick: () => setTransport("stdio"),
427
+ className: `flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${transport === "stdio" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
428
+ children: "Stdio"
429
+ }
430
+ )
431
+ ] }),
432
+ transport === "remote" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
433
+ /* @__PURE__ */ jsx2(
434
+ McpRemoteSourceFields,
435
+ {
436
+ url: state.url,
437
+ onUrlChange: (url) => dispatch({ type: "set-url", url }),
438
+ identity: remoteIdentity,
439
+ preview: probe,
440
+ probing: isProbing,
441
+ error: probeError,
442
+ onRetry: handleProbe
443
+ }
444
+ ),
445
+ probe && /* @__PURE__ */ jsxs2("section", { className: "space-y-2.5", children: [
446
+ /* @__PURE__ */ jsx2(FieldLabel, { children: "How does this server authenticate?" }),
447
+ /* @__PURE__ */ jsx2(
448
+ AuthTemplateEditor,
449
+ {
450
+ value: authValue,
451
+ onChange: setAuthValue,
452
+ allowedKinds: allowedAuthKinds,
453
+ oauthMetadata: "discovered"
454
+ }
455
+ )
456
+ ] }),
457
+ otherError && /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
458
+ /* @__PURE__ */ jsx2("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-[12px] text-destructive", children: otherError }) }),
459
+ /* @__PURE__ */ jsx2(
460
+ Button2,
461
+ {
462
+ type: "button",
463
+ variant: "outline",
464
+ size: "sm",
465
+ onClick: () => dispatch({ type: "retry" }),
466
+ className: "text-xs",
467
+ children: "Try again"
468
+ }
469
+ )
470
+ ] }),
471
+ remoteSlugExists && !isAdding && /* @__PURE__ */ jsx2("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsxs2("p", { className: "text-[12px] text-destructive", children: [
472
+ 'An integration named "',
473
+ remoteSlug,
474
+ '" already exists. To add more authentication, update your existing integration.',
475
+ " ",
476
+ /* @__PURE__ */ jsx2(
477
+ Link,
478
+ {
479
+ to: "/integrations/$namespace",
480
+ params: { namespace: remoteSlug },
481
+ className: "font-medium underline underline-offset-2",
482
+ children: "Open it"
483
+ }
484
+ )
485
+ ] }) }),
486
+ /* @__PURE__ */ jsxs2(FloatActions, { children: [
487
+ /* @__PURE__ */ jsx2(
488
+ Button2,
489
+ {
490
+ type: "button",
491
+ variant: "ghost",
492
+ onClick: () => props.onCancel(),
493
+ disabled: isAdding,
494
+ children: "Cancel"
495
+ }
496
+ ),
497
+ (probe || isProbing) && /* @__PURE__ */ jsx2(Button2, { type: "button", onClick: handleAddRemote, disabled: !canAdd, children: isAdding ? /* @__PURE__ */ jsxs2(Fragment, { children: [
498
+ /* @__PURE__ */ jsx2(Spinner, { className: "size-3.5" }),
499
+ " Adding\u2026"
500
+ ] }) : "Add source" })
501
+ ] })
502
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
503
+ /* @__PURE__ */ jsx2(CardStack2, { children: /* @__PURE__ */ jsxs2(CardStackContent2, { className: "border-t-0", children: [
504
+ /* @__PURE__ */ jsx2(
505
+ CardStackEntryField2,
506
+ {
507
+ label: "Command",
508
+ description: "- The executable to run (e.g. npx, uvx, node).",
509
+ children: /* @__PURE__ */ jsx2(
510
+ Input2,
511
+ {
512
+ value: stdioCommand,
513
+ onChange: (e) => setStdioCommand(e.target.value),
514
+ placeholder: "npx",
515
+ className: "font-mono text-sm"
516
+ }
517
+ )
518
+ }
519
+ ),
520
+ /* @__PURE__ */ jsx2(
521
+ CardStackEntryField2,
522
+ {
523
+ label: "Arguments",
524
+ description: "- Space-separated arguments passed to the command.",
525
+ children: /* @__PURE__ */ jsx2(
526
+ Input2,
527
+ {
528
+ value: stdioArgs,
529
+ onChange: (e) => setStdioArgs(e.target.value),
530
+ placeholder: "-y chrome-devtools-mcp@latest",
531
+ className: "font-mono text-sm"
532
+ }
533
+ )
534
+ }
535
+ ),
536
+ /* @__PURE__ */ jsx2(
537
+ CardStackEntryField2,
538
+ {
539
+ label: "Environment variables",
540
+ description: "- One per line, KEY=value format.",
541
+ children: /* @__PURE__ */ jsx2(
542
+ Textarea,
543
+ {
544
+ value: stdioEnv,
545
+ onChange: (e) => setStdioEnv(e.target.value),
546
+ placeholder: "KEY=value\nANOTHER=value",
547
+ rows: 3,
548
+ maxRows: 10,
549
+ className: "font-mono text-sm"
550
+ }
551
+ )
552
+ }
553
+ )
554
+ ] }) }),
555
+ /* @__PURE__ */ jsx2(IntegrationIdentityFields, { identity: stdioIdentity, namePlaceholder: "My MCP Server" }),
556
+ stdioError && /* @__PURE__ */ jsx2("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-[12px] text-destructive", children: stdioError }) }),
557
+ stdioSlugExists && !stdioAdding && /* @__PURE__ */ jsx2("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsxs2("p", { className: "text-[12px] text-destructive", children: [
558
+ 'An integration named "',
559
+ stdioSlug,
560
+ '" already exists. To add more authentication, update your existing integration.',
561
+ " ",
562
+ /* @__PURE__ */ jsx2(
563
+ Link,
564
+ {
565
+ to: "/integrations/$namespace",
566
+ params: { namespace: stdioSlug },
567
+ className: "font-medium underline underline-offset-2",
568
+ children: "Open it"
569
+ }
570
+ )
571
+ ] }) }),
572
+ /* @__PURE__ */ jsxs2(FloatActions, { children: [
573
+ /* @__PURE__ */ jsx2(
574
+ Button2,
575
+ {
576
+ type: "button",
577
+ variant: "ghost",
578
+ onClick: () => props.onCancel(),
579
+ disabled: stdioAdding,
580
+ children: "Cancel"
581
+ }
582
+ ),
583
+ /* @__PURE__ */ jsx2(
584
+ Button2,
585
+ {
586
+ type: "button",
587
+ onClick: handleAddStdio,
588
+ disabled: !stdioCommand.trim() || stdioAdding || stdioSlugExists,
589
+ children: stdioAdding ? /* @__PURE__ */ jsxs2(Fragment, { children: [
590
+ /* @__PURE__ */ jsx2(Spinner, { className: "size-3.5" }),
591
+ " Adding\u2026"
592
+ ] }) : "Add source"
593
+ }
594
+ )
595
+ ] })
596
+ ] })
597
+ ] });
598
+ }
599
+ export {
600
+ AddMcpSource as default
601
+ };
602
+ //# sourceMappingURL=AddMcpSource-4LLERUW5.js.map