@executor-js/plugin-mcp 1.5.10 → 1.5.12

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.
@@ -6,7 +6,7 @@ import {
6
6
  mcpAuthMethodInputFromEditorValue,
7
7
  mcpWireAuthInput,
8
8
  probeMcpEndpoint
9
- } from "./chunk-3AOD4VAW.js";
9
+ } from "./chunk-AL7N323J.js";
10
10
  import "./chunk-3H5Y7JCQ.js";
11
11
 
12
12
  // src/react/AddMcpSource.tsx
@@ -27,7 +27,7 @@ import {
27
27
  import { FloatActions } from "@executor-js/react/components/float-actions";
28
28
  import { Input as Input2 } from "@executor-js/react/components/input";
29
29
  import { Spinner } from "@executor-js/react/components/spinner";
30
- import { Textarea } from "@executor-js/react/components/textarea";
30
+ import { Textarea as Textarea2 } from "@executor-js/react/components/textarea";
31
31
  import {
32
32
  integrationDisplayNameFromUrl,
33
33
  slugifyNamespace,
@@ -58,6 +58,7 @@ import {
58
58
  } from "@executor-js/react/components/card-stack";
59
59
  import { FieldError } from "@executor-js/react/components/field";
60
60
  import { Input } from "@executor-js/react/components/input";
61
+ import { Textarea } from "@executor-js/react/components/textarea";
61
62
  import { Skeleton } from "@executor-js/react/components/skeleton";
62
63
  import { IntegrationFavicon } from "@executor-js/react/components/integration-favicon";
63
64
  import { IOSSpinner } from "@executor-js/react/components/spinner";
@@ -107,6 +108,20 @@ function McpRemoteSourceFields(props) {
107
108
  namespaceReadOnly: props.namespaceReadOnly
108
109
  }
109
110
  ),
111
+ props.onDescriptionChange && /* @__PURE__ */ jsxs(CardStackEntryField, { label: "Description", children: [
112
+ /* @__PURE__ */ jsx(
113
+ Textarea,
114
+ {
115
+ value: props.description ?? "",
116
+ onChange: (e) => props.onDescriptionChange?.(e.target.value),
117
+ placeholder: "What this server offers and when to reach for it",
118
+ rows: 2,
119
+ maxRows: 6,
120
+ className: "text-sm"
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "Agent-visible. Prefilled from the server's instructions when it sends any." })
124
+ ] }),
110
125
  /* @__PURE__ */ jsx(CardStackEntryField, { label: "Server URL", children: /* @__PURE__ */ jsx(
111
126
  Input,
112
127
  {
@@ -273,6 +288,8 @@ function AddMcpSource(props) {
273
288
  const remoteIdentity = useIntegrationIdentity({
274
289
  fallbackName: integrationDisplayNameFromUrl(state.url, "MCP") ?? probe?.serverName ?? probe?.name ?? ""
275
290
  });
291
+ const [descriptionDraft, setDescriptionDraft] = useState(null);
292
+ const resolvedDescription = descriptionDraft ?? probe?.instructions ?? "";
276
293
  const isProbing = state.step === "probing";
277
294
  const isAdding = state.step === "adding";
278
295
  const remoteSlug = slugifyNamespace(remoteIdentity.namespace);
@@ -316,6 +333,7 @@ function AddMcpSource(props) {
316
333
  payload: {
317
334
  transport: "remote",
318
335
  name: displayName,
336
+ ...resolvedDescription.trim().length > 0 ? { description: resolvedDescription.trim() } : {},
319
337
  endpoint: state.url.trim(),
320
338
  ...slug ? { slug } : {},
321
339
  authenticationTemplate
@@ -331,7 +349,7 @@ function AddMcpSource(props) {
331
349
  }
332
350
  return exit.value.slug;
333
351
  },
334
- [doAddServer, probe, remoteIdentity, state.url]
352
+ [doAddServer, probe, remoteIdentity, resolvedDescription, state.url]
335
353
  );
336
354
  const handleAddRemote = useCallback(async () => {
337
355
  if (!probe) return;
@@ -439,6 +457,8 @@ function AddMcpSource(props) {
439
457
  url: state.url,
440
458
  onUrlChange: (url) => dispatch({ type: "set-url", url }),
441
459
  identity: remoteIdentity,
460
+ description: resolvedDescription,
461
+ onDescriptionChange: setDescriptionDraft,
442
462
  preview: probe,
443
463
  probing: isProbing,
444
464
  error: probeError,
@@ -526,7 +546,7 @@ function AddMcpSource(props) {
526
546
  label: "Environment variables",
527
547
  description: "- One per line, KEY=value format.",
528
548
  children: /* @__PURE__ */ jsx2(
529
- Textarea,
549
+ Textarea2,
530
550
  {
531
551
  value: stdioEnv,
532
552
  onChange: (e) => setStdioEnv(e.target.value),
@@ -572,4 +592,4 @@ function AddMcpSource(props) {
572
592
  export {
573
593
  AddMcpSource as default
574
594
  };
575
- //# sourceMappingURL=AddMcpSource-ZDNQ7F6I.js.map
595
+ //# sourceMappingURL=AddMcpSource-HCJNPYGW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/AddMcpSource.tsx","../src/react/McpRemoteSourceFields.tsx"],"sourcesContent":["import { useReducer, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAtomSet } from \"@effect/atom-react\";\nimport * as Exit from \"effect/Exit\";\nimport * as Match from \"effect/Match\";\n\nimport { Button } from \"@executor-js/react/components/button\";\nimport {\n AuthMethodListEditor,\n useAuthMethodList,\n type AuthMethodRow,\n type AuthMethodSeed,\n} from \"@executor-js/react/components/auth-method-list-editor\";\nimport {\n CardStack,\n CardStackContent,\n CardStackEntryField,\n} from \"@executor-js/react/components/card-stack\";\nimport { FloatActions } from \"@executor-js/react/components/float-actions\";\nimport { Input } from \"@executor-js/react/components/input\";\nimport { Spinner } from \"@executor-js/react/components/spinner\";\nimport { Textarea } from \"@executor-js/react/components/textarea\";\nimport {\n integrationDisplayNameFromUrl,\n slugifyNamespace,\n IntegrationIdentityFields,\n useIntegrationIdentity,\n} from \"@executor-js/react/plugins/integration-identity\";\nimport {\n addIntegrationErrorMessage,\n errorMessageFromExit,\n FormErrorAlert,\n SlugCollisionAlert,\n useSlugAlreadyExists,\n} from \"@executor-js/react/lib/integration-add\";\n\nimport { integrationWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport type { McpAuthMethodInput } from \"../sdk/types\";\nimport { probeMcpEndpoint, addMcpServer } from \"./atoms\";\nimport { McpRemoteSourceFields } from \"./McpRemoteSourceFields\";\nimport { mcpAuthMethodInputFromEditorValue, mcpWireAuthInput } from \"./auth-method-config\";\nimport { mcpPresets, type McpPreset } from \"../sdk/presets\";\n\n// The remote add flow REGISTERS the server's declared auth methods through the\n// shared `AuthMethodListEditor` — accounts (the API key value / OAuth sign-in)\n// are added later from the integration's detail hub (P6: add without auth,\n// connect later). The probe SEEDS the list (detected OAuth → an OAuth row; a\n// 401 without OAuth → a bearer-header row; open server → a no-auth row) and\n// the user can add alternate methods (e.g. an API key alongside OAuth, or a\n// declared method on a server that advertises none).\n\nconst STDIO_ENV_ESCAPE_REPLACEMENTS: Readonly<Record<string, string>> = {\n \"\\\\\": \"\\\\\",\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n '\"': '\"',\n};\n\n// ---------------------------------------------------------------------------\n// Preset lookup\n// ---------------------------------------------------------------------------\n\nfunction findPreset(id: string | undefined): McpPreset | undefined {\n if (!id) return undefined;\n return mcpPresets.find((p) => p.id === id);\n}\n\n// ---------------------------------------------------------------------------\n// State machine (remote flow)\n// ---------------------------------------------------------------------------\n\ntype ProbeResult = {\n connected: boolean;\n requiresAuthentication: boolean;\n requiresOAuth: boolean;\n supportsDynamicRegistration: boolean;\n name: string;\n slug: string;\n toolCount: number | null;\n serverName: string | null;\n instructions: string | null;\n};\n\ntype State =\n | { step: \"url\"; url: string }\n | { step: \"probing\"; url: string; probe: ProbeResult | null }\n | { step: \"probed\"; url: string; probe: ProbeResult }\n | { step: \"adding\"; url: string; probe: ProbeResult }\n | {\n step: \"error\";\n url: string;\n probe: ProbeResult | null;\n error: string;\n };\n\ntype Action =\n | { type: \"set-url\"; url: string }\n | { type: \"probe-start\" }\n | { type: \"probe-ok\"; probe: ProbeResult }\n | { type: \"probe-fail\"; error: string }\n | { type: \"add-start\" }\n | { type: \"add-fail\"; error: string }\n | { type: \"retry\" };\n\nconst init: State = { step: \"url\", url: \"\" };\n\nfunction reducer(state: State, action: Action): State {\n return Match.value(action).pipe(\n Match.discriminator(\"type\")(\"set-url\", (a): State => ({ step: \"url\", url: a.url })),\n Match.discriminator(\"type\")(\n \"probe-start\",\n (): State => ({\n step: \"probing\",\n url: state.url,\n probe: \"probe\" in state ? state.probe : null,\n }),\n ),\n Match.discriminator(\"type\")(\n \"probe-ok\",\n (a): State => ({ step: \"probed\", url: state.url, probe: a.probe }),\n ),\n Match.discriminator(\"type\")(\n \"probe-fail\",\n (a): State => ({\n step: \"error\",\n url: state.url,\n probe: null,\n error: a.error,\n }),\n ),\n Match.discriminator(\"type\")(\"add-start\", (): State => {\n const probe = \"probe\" in state ? state.probe : null;\n if (!probe) return state;\n return { step: \"adding\", url: state.url, probe };\n }),\n Match.discriminator(\"type\")(\"add-fail\", (a): State => {\n if (state.step !== \"adding\") return state;\n return {\n step: \"error\",\n url: state.url,\n probe: state.probe,\n error: a.error,\n };\n }),\n Match.discriminator(\"type\")(\"retry\", (): State => {\n if (state.step !== \"error\") return state;\n return state.probe\n ? { step: \"probed\", url: state.url, probe: state.probe }\n : { step: \"url\", url: state.url };\n }),\n Match.exhaustive,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport default function AddMcpSource(props: {\n onComplete: (slug?: string) => void;\n onCancel: () => void;\n initialUrl?: string;\n initialPreset?: string;\n /** Whether the stdio transport is enabled on the server. */\n allowStdio?: boolean;\n}) {\n const allowStdio = props.allowStdio ?? false;\n const rawPreset = findPreset(props.initialPreset);\n // Drop stdio presets when stdio is disabled — the caller should have\n // already filtered these out, but defence-in-depth.\n const preset = rawPreset?.transport === \"stdio\" && !allowStdio ? undefined : rawPreset;\n const isStdioPreset = preset?.transport === \"stdio\";\n\n const [transport, setTransport] = useState<\"remote\" | \"stdio\">(\n isStdioPreset && allowStdio ? \"stdio\" : \"remote\",\n );\n\n // --- Stdio state ---\n const [stdioCommand, setStdioCommand] = useState(isStdioPreset ? preset.command : \"\");\n const [stdioArgs, setStdioArgs] = useState(\n isStdioPreset && preset.args ? preset.args.join(\" \") : \"\",\n );\n const [stdioEnv, setStdioEnv] = useState(\"\");\n const stdioIdentity = useIntegrationIdentity({\n fallbackName: isStdioPreset ? preset.name : stdioCommand,\n });\n const [stdioAdding, setStdioAdding] = useState(false);\n const [stdioError, setStdioError] = useState<string | null>(null);\n\n // --- Remote state ---\n const remoteUrl =\n !isStdioPreset && preset?.transport === undefined && preset?.url\n ? preset.url\n : (props.initialUrl ?? \"\");\n\n const [state, dispatch] = useReducer(\n reducer,\n remoteUrl ? { step: \"url\" as const, url: remoteUrl } : init,\n );\n\n const doProbe = useAtomSet(probeMcpEndpoint, { mode: \"promiseExit\" });\n const doAddServer = useAtomSet(addMcpServer, { mode: \"promiseExit\" });\n\n const probe = \"probe\" in state ? state.probe : null;\n\n // The probe seeds the method list: detected OAuth → an OAuth row; a 401\n // without OAuth metadata → a bearer-header row; an open server → a no-auth\n // row. The user can edit any row or add alternate methods alongside.\n const authMethodSeeds: readonly AuthMethodSeed[] = useMemo(() => {\n if (!probe) return [];\n if (probe.requiresOAuth) {\n return [\n {\n value: { kind: \"oauth\", authorizationUrl: \"\", tokenUrl: \"\", scopes: [] },\n label: \"Detected\",\n },\n ];\n }\n if (probe.requiresAuthentication) {\n return [\n {\n value: {\n kind: \"apikey\",\n placements: [{ carrier: \"header\", name: \"Authorization\", prefix: \"Bearer \" }],\n },\n label: \"Detected\",\n },\n ];\n }\n return [{ value: { kind: \"none\" }, label: \"Detected\" }];\n }, [probe]);\n const authMethodList = useAuthMethodList(authMethodSeeds);\n\n const remoteIdentity = useIntegrationIdentity({\n fallbackName:\n integrationDisplayNameFromUrl(state.url, \"MCP\") ?? probe?.serverName ?? probe?.name ?? \"\",\n });\n // Agent-visible description: prefilled from the server's `instructions`\n // until the user types (null = untouched, keep deriving from the probe).\n const [descriptionDraft, setDescriptionDraft] = useState<string | null>(null);\n const resolvedDescription = descriptionDraft ?? probe?.instructions ?? \"\";\n const isProbing = state.step === \"probing\";\n const isAdding = state.step === \"adding\";\n\n // Pre-empt the API's `IntegrationAlreadyExistsError`: adding an integration\n // whose slug already exists clobbers the existing one's connections/policies,\n // so the API blocks it. Surface that here from the tenant-scoped catalog list.\n // A blank derived namespace lets the server assign the slug, so only flag a\n // collision when the user-derived slug is non-empty.\n const remoteSlug = slugifyNamespace(remoteIdentity.namespace);\n const stdioSlug = slugifyNamespace(stdioIdentity.namespace);\n const remoteSlugExists = useSlugAlreadyExists(remoteSlug);\n const stdioSlugExists = useSlugAlreadyExists(stdioSlug);\n\n const canAdd = Boolean(probe) && !isAdding && !remoteSlugExists;\n // Probe failures are shown inline on the URL field; other failures\n // (add server) render in the bottom error block.\n const probeError = state.step === \"error\" && state.probe === null ? state.error : null;\n const otherError = state.step === \"error\" && state.probe !== null ? state.error : null;\n\n // ---- Remote actions ----\n\n const handleProbe = useCallback(async () => {\n dispatch({ type: \"probe-start\" });\n const exit = await doProbe({\n payload: { endpoint: state.url.trim() },\n });\n if (Exit.isFailure(exit)) {\n dispatch({\n type: \"probe-fail\",\n error: errorMessageFromExit(exit, \"Failed to connect\"),\n });\n return;\n }\n dispatch({ type: \"probe-ok\", probe: exit.value });\n }, [state.url, doProbe]);\n\n // Keep the latest handleProbe in a ref so the debounced effect can call it\n // without depending on its identity (which changes every render).\n const handleProbeRef = useRef(handleProbe);\n handleProbeRef.current = handleProbe;\n\n // Auto-probe whenever the URL changes (debounced) while we're on the\n // remote transport and not already probing/probed.\n useEffect(() => {\n if (transport !== \"remote\") return;\n if (state.step !== \"url\") return;\n const trimmed = state.url.trim();\n if (!trimmed) return;\n const handle = setTimeout(() => {\n handleProbeRef.current();\n }, 400);\n return () => clearTimeout(handle);\n }, [transport, state.step, state.url]);\n\n // Register the integration with the declared auth methods, returning the\n // assigned slug (or null on failure — an error is dispatched in that case).\n const registerIntegration = useCallback(\n async (authenticationTemplate: readonly McpAuthMethodInput[]): Promise<string | null> => {\n const displayName = remoteIdentity.name.trim() || probe?.serverName || probe?.name || \"MCP\";\n const slug = slugifyNamespace(remoteIdentity.namespace) || undefined;\n const exit = await doAddServer({\n payload: {\n transport: \"remote\" as const,\n name: displayName,\n ...(resolvedDescription.trim().length > 0\n ? { description: resolvedDescription.trim() }\n : {}),\n endpoint: state.url.trim(),\n ...(slug ? { slug } : {}),\n authenticationTemplate,\n },\n reactivityKeys: integrationWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n dispatch({\n type: \"add-fail\",\n error: addIntegrationErrorMessage(exit, slug ?? displayName, \"Failed to add server\"),\n });\n return null;\n }\n return exit.value.slug;\n },\n [doAddServer, probe, remoteIdentity, resolvedDescription, state.url],\n );\n\n const handleAddRemote = useCallback(async () => {\n if (!probe) return;\n dispatch({ type: \"add-start\" });\n // Every row registers as a declared method (a lone no-auth row registers\n // the open-server method). Slugs are assigned server-side by kind.\n const methods = authMethodList.rows.map((row: AuthMethodRow) =>\n mcpWireAuthInput(mcpAuthMethodInputFromEditorValue(row.value)),\n );\n const slug = await registerIntegration(\n methods.length > 0 ? methods : [{ kind: \"none\" as const }],\n );\n if (slug === null) return;\n props.onComplete(slug);\n }, [probe, authMethodList.rows, registerIntegration, props]);\n\n // ---- Stdio actions ----\n\n const parseStdioArgs = (raw: string): string[] => {\n if (!raw.trim()) return [];\n const args: string[] = [];\n const regex = /[^\\s\"]+|\"([^\"]*)\"/g;\n let match;\n while ((match = regex.exec(raw)) !== null) {\n args.push(match[1] ?? match[0]);\n }\n return args;\n };\n\n const parseStdioEnvValue = (raw: string): string => {\n const value = raw.trim();\n if (value.length < 2) return value;\n\n const quote = value[0];\n if ((quote !== '\"' && quote !== \"'\") || value[value.length - 1] !== quote) {\n return value;\n }\n\n const inner = value.slice(1, -1);\n if (quote === \"'\") return inner;\n\n return inner.replace(\n /\\\\([\\\\nrt\"])/g,\n (_, escaped: string) => STDIO_ENV_ESCAPE_REPLACEMENTS[escaped] ?? escaped,\n );\n };\n\n const parseStdioEnv = (raw: string): Record<string, string> | undefined => {\n if (!raw.trim()) return undefined;\n const env: Record<string, string> = {};\n for (const line of raw.split(\"\\n\")) {\n const eq = line.indexOf(\"=\");\n if (eq > 0) {\n env[line.slice(0, eq).trim()] = parseStdioEnvValue(line.slice(eq + 1));\n }\n }\n return Object.keys(env).length > 0 ? env : undefined;\n };\n\n const handleAddStdio = useCallback(async () => {\n const cmd = stdioCommand.trim();\n if (!cmd) return;\n setStdioAdding(true);\n setStdioError(null);\n const displayName = stdioIdentity.name.trim() || cmd;\n const slug = slugifyNamespace(stdioIdentity.namespace) || undefined;\n const exit = await doAddServer({\n payload: {\n transport: \"stdio\" as const,\n name: displayName,\n ...(slug ? { slug } : {}),\n command: cmd,\n args: parseStdioArgs(stdioArgs),\n env: parseStdioEnv(stdioEnv),\n },\n reactivityKeys: integrationWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setStdioError(addIntegrationErrorMessage(exit, slug ?? displayName, \"Failed to add server\"));\n setStdioAdding(false);\n return;\n }\n props.onComplete(exit.value.slug);\n }, [stdioCommand, stdioArgs, stdioEnv, stdioIdentity, doAddServer, props]);\n\n // ---- Render ----\n\n return (\n <div className=\"flex flex-1 flex-col gap-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Add MCP Source</h1>\n <p className=\"mt-1 text-[13px] text-muted-foreground\">\n Connect to an MCP server to discover and use its tools.\n </p>\n </div>\n\n {/* Transport toggle — only shown when stdio is enabled server-side */}\n {allowStdio && (\n <div className=\"flex gap-1 rounded-lg border border-border bg-muted/30 p-1\">\n <Button\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setTransport(\"remote\")}\n className={`flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${\n transport === \"remote\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n Remote\n </Button>\n <Button\n variant=\"ghost\"\n type=\"button\"\n onClick={() => setTransport(\"stdio\")}\n className={`flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${\n transport === \"stdio\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n Stdio\n </Button>\n </div>\n )}\n\n {transport === \"remote\" ? (\n <>\n <McpRemoteSourceFields\n url={state.url}\n onUrlChange={(url) => dispatch({ type: \"set-url\", url })}\n identity={remoteIdentity}\n description={resolvedDescription}\n onDescriptionChange={setDescriptionDraft}\n preview={probe}\n probing={isProbing}\n error={probeError}\n onRetry={handleProbe}\n />\n\n {/* Authentication — declares the auth methods to register through the\n shared list editor. The credentials themselves (API key value /\n OAuth sign-in) are added from the integration's detail hub after\n adding. */}\n {probe && (\n <AuthMethodListEditor\n list={authMethodList}\n title=\"How does this server authenticate?\"\n oauthMetadata=\"discovered\"\n emptyHint=\"No methods declared. Add a method, or add the server without auth and connect from the integration page later.\"\n footerHint=\"Every method here is registered with the server. Connect an account from the integration page after adding.\"\n />\n )}\n\n {/* Error (add server). Probe errors show inline on the field. */}\n {otherError && (\n <div className=\"space-y-2\">\n <FormErrorAlert message={otherError} />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => dispatch({ type: \"retry\" })}\n className=\"text-xs\"\n >\n Try again\n </Button>\n </div>\n )}\n\n {remoteSlugExists && !isAdding && <SlugCollisionAlert slug={remoteSlug} />}\n\n <FloatActions>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => props.onCancel()}\n disabled={isAdding}\n >\n Cancel\n </Button>\n {(probe || isProbing) && (\n <Button type=\"button\" onClick={handleAddRemote} disabled={!canAdd}>\n {isAdding ? (\n <>\n <Spinner className=\"size-3.5\" /> Adding…\n </>\n ) : (\n \"Add source\"\n )}\n </Button>\n )}\n </FloatActions>\n </>\n ) : (\n <>\n {/* Stdio form */}\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntryField\n label=\"Command\"\n description=\"- The executable to run (e.g. npx, uvx, node).\"\n >\n <Input\n value={stdioCommand}\n onChange={(e) => setStdioCommand((e.target as HTMLInputElement).value)}\n placeholder=\"npx\"\n className=\"font-mono text-sm\"\n />\n </CardStackEntryField>\n\n <CardStackEntryField\n label=\"Arguments\"\n description=\"- Space-separated arguments passed to the command.\"\n >\n <Input\n value={stdioArgs}\n onChange={(e) => setStdioArgs((e.target as HTMLInputElement).value)}\n placeholder=\"-y chrome-devtools-mcp@latest\"\n className=\"font-mono text-sm\"\n />\n </CardStackEntryField>\n\n <CardStackEntryField\n label=\"Environment variables\"\n description=\"- One per line, KEY=value format.\"\n >\n <Textarea\n value={stdioEnv}\n onChange={(e) => setStdioEnv((e.target as HTMLTextAreaElement).value)}\n placeholder={\"KEY=value\\nANOTHER=value\"}\n rows={3}\n maxRows={10}\n className=\"font-mono text-sm\"\n />\n </CardStackEntryField>\n </CardStackContent>\n </CardStack>\n\n <IntegrationIdentityFields identity={stdioIdentity} namePlaceholder=\"My MCP Server\" />\n\n {/* Stdio error */}\n {stdioError && <FormErrorAlert message={stdioError} />}\n\n {stdioSlugExists && !stdioAdding && <SlugCollisionAlert slug={stdioSlug} />}\n\n <FloatActions>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => props.onCancel()}\n disabled={stdioAdding}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n onClick={handleAddStdio}\n disabled={!stdioCommand.trim() || stdioAdding || stdioSlugExists}\n >\n {stdioAdding ? (\n <>\n <Spinner className=\"size-3.5\" /> Adding…\n </>\n ) : (\n \"Add source\"\n )}\n </Button>\n </FloatActions>\n </>\n )}\n </div>\n );\n}\n","import { Badge } from \"@executor-js/react/components/badge\";\nimport {\n CardStack,\n CardStackContent,\n CardStackEntry,\n CardStackEntryActions,\n CardStackEntryContent,\n CardStackEntryDescription,\n CardStackEntryField,\n CardStackEntryMedia,\n CardStackEntryTitle,\n} from \"@executor-js/react/components/card-stack\";\nimport { FieldError } from \"@executor-js/react/components/field\";\nimport { Input } from \"@executor-js/react/components/input\";\nimport { Textarea } from \"@executor-js/react/components/textarea\";\nimport { Skeleton } from \"@executor-js/react/components/skeleton\";\nimport { IntegrationFavicon } from \"@executor-js/react/components/integration-favicon\";\nimport { IOSSpinner } from \"@executor-js/react/components/spinner\";\nimport { Button } from \"@executor-js/react/components/button\";\nimport {\n IntegrationIdentityFieldRows,\n type IntegrationIdentity,\n} from \"@executor-js/react/plugins/integration-identity\";\n\nexport type McpRemoteSourcePreview = {\n readonly name: string;\n readonly serverName: string | null;\n readonly connected: boolean;\n readonly requiresAuthentication: boolean;\n readonly requiresOAuth: boolean;\n readonly toolCount: number | null;\n};\n\nexport function McpRemoteSourceFields(props: {\n readonly url: string;\n readonly onUrlChange: (url: string) => void;\n readonly identity: IntegrationIdentity;\n /** The integration's agent-visible description (prefilled from the server's\n * `instructions` when the probe connected). */\n readonly description?: string;\n readonly onDescriptionChange?: (value: string) => void;\n readonly preview: McpRemoteSourcePreview | null;\n readonly probing?: boolean;\n readonly error?: string | null;\n readonly onRetry?: () => void;\n readonly namespaceReadOnly?: boolean;\n readonly urlDisabled?: boolean;\n}) {\n const previewDescription = props.preview\n ? props.preview.connected\n ? props.preview.toolCount === null\n ? null\n : `${props.preview.toolCount} tool${props.preview.toolCount !== 1 ? \"s\" : \"\"} available`\n : props.preview.requiresOAuth\n ? \"OAuth required to discover tools\"\n : props.preview.requiresAuthentication\n ? \"Authentication required to discover tools\"\n : \"Ready to add\"\n : null;\n\n if (props.preview) {\n return (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntry>\n <CardStackEntryMedia>\n <IntegrationFavicon url={props.url} size={32} />\n </CardStackEntryMedia>\n <CardStackEntryContent>\n <CardStackEntryTitle>\n {props.preview.serverName ?? props.preview.name}\n </CardStackEntryTitle>\n {previewDescription ? (\n <CardStackEntryDescription>{previewDescription}</CardStackEntryDescription>\n ) : null}\n </CardStackEntryContent>\n <CardStackEntryActions>\n {props.preview.connected ? (\n <Badge\n variant=\"outline\"\n className=\"border-emerald-500/20 bg-emerald-500/10 text-[10px] text-emerald-600 dark:text-emerald-400\"\n >\n Connected\n </Badge>\n ) : props.preview.requiresOAuth ? (\n <Badge\n variant=\"outline\"\n className=\"border-amber-500/20 bg-amber-500/10 text-[10px] text-amber-600 dark:text-amber-400\"\n >\n OAuth required\n </Badge>\n ) : (\n <Badge\n variant=\"outline\"\n className=\"border-amber-500/20 bg-amber-500/10 text-[10px] text-amber-600 dark:text-amber-400\"\n >\n Auth required\n </Badge>\n )}\n </CardStackEntryActions>\n </CardStackEntry>\n <IntegrationIdentityFieldRows\n identity={props.identity}\n namePlaceholder=\"e.g. Linear\"\n namespaceReadOnly={props.namespaceReadOnly}\n />\n {props.onDescriptionChange && (\n <CardStackEntryField label=\"Description\">\n <Textarea\n value={props.description ?? \"\"}\n onChange={(e) =>\n props.onDescriptionChange?.((e.target as HTMLTextAreaElement).value)\n }\n placeholder=\"What this server offers and when to reach for it\"\n rows={2}\n maxRows={6}\n className=\"text-sm\"\n />\n <p className=\"text-[11px] text-muted-foreground\">\n Agent-visible. Prefilled from the server's instructions when it sends any.\n </p>\n </CardStackEntryField>\n )}\n <CardStackEntryField label=\"Server URL\">\n <Input\n value={props.url}\n onChange={(e) => props.onUrlChange((e.target as HTMLInputElement).value)}\n placeholder=\"https://mcp.example.com\"\n className=\"w-full font-mono text-sm\"\n disabled={props.urlDisabled}\n />\n </CardStackEntryField>\n </CardStackContent>\n </CardStack>\n );\n }\n\n if (props.probing) {\n return (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntry>\n <CardStackEntryMedia>\n <Skeleton className=\"size-4 rounded\" />\n </CardStackEntryMedia>\n <CardStackEntryContent>\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"mt-1 h-3 w-32\" />\n </CardStackEntryContent>\n <CardStackEntryActions>\n <Skeleton className=\"h-4 w-20 rounded-full\" />\n </CardStackEntryActions>\n </CardStackEntry>\n </CardStackContent>\n </CardStack>\n );\n }\n\n return (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntryField label=\"Server URL\">\n <div className=\"relative\">\n <Input\n value={props.url}\n onChange={(e) => props.onUrlChange((e.target as HTMLInputElement).value)}\n placeholder=\"https://mcp.example.com\"\n className=\"w-full pr-9 font-mono text-sm\"\n aria-invalid={props.error ? true : undefined}\n disabled={props.urlDisabled}\n />\n {props.probing && (\n <div className=\"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2\">\n <IOSSpinner className=\"size-4\" />\n </div>\n )}\n </div>\n {props.error && (\n <div className=\"mt-2 space-y-2\">\n <FieldError>{props.error}</FieldError>\n {props.onRetry && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={props.onRetry}\n className=\"h-7 px-2 text-xs\"\n >\n Try again\n </Button>\n )}\n </div>\n )}\n </CardStackEntryField>\n </CardStackContent>\n </CardStack>\n );\n}\n"],"mappings":"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","names":["Button","CardStack","CardStackContent","CardStackEntryField","Input","Textarea","jsx","jsxs","value","Button","CardStack","CardStackContent","CardStackEntryField","Input","Textarea"]}
@@ -4,11 +4,11 @@ import {
4
4
  mcpAuthMethodInputFromEditorValue,
5
5
  mcpServerAtom,
6
6
  mcpWireAuthInput
7
- } from "./chunk-3AOD4VAW.js";
7
+ } from "./chunk-AL7N323J.js";
8
8
  import "./chunk-3H5Y7JCQ.js";
9
9
 
10
10
  // src/react/EditMcpSource.tsx
11
- import { useCallback, useMemo, useState } from "react";
11
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
12
12
  import { useAtomValue, useAtomSet } from "@effect/atom-react";
13
13
  import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
14
14
  import * as Exit from "effect/Exit";
@@ -19,15 +19,6 @@ import {
19
19
  AuthMethodListEditor,
20
20
  useAuthMethodList
21
21
  } from "@executor-js/react/components/auth-method-list-editor";
22
- import { Button } from "@executor-js/react/components/button";
23
- import {
24
- CardStack,
25
- CardStackContent,
26
- CardStackEntry,
27
- CardStackEntryContent,
28
- CardStackEntryDescription,
29
- CardStackEntryTitle
30
- } from "@executor-js/react/components/card-stack";
31
22
  import { Badge } from "@executor-js/react/components/badge";
32
23
  import { FormErrorAlert } from "@executor-js/react/lib/integration-add";
33
24
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -59,7 +50,6 @@ function RemoteEdit(props) {
59
50
  [server.config.authenticationTemplate]
60
51
  );
61
52
  const list = useAuthMethodList(seeds);
62
- const [saving, setSaving] = useState(false);
63
53
  const [error, setError] = useState(null);
64
54
  const editedMethods = useMemo(
65
55
  () => list.rows.map((row) => {
@@ -82,8 +72,7 @@ function RemoteEdit(props) {
82
72
  return false;
83
73
  });
84
74
  }, [editedMethods, server.config.authenticationTemplate]);
85
- const handleSave = useCallback(async () => {
86
- setSaving(true);
75
+ const applyStaged = useCallback(async () => {
87
76
  setError(null);
88
77
  const exit = await doConfigureAuth({
89
78
  params: { slug: server.slug },
@@ -95,84 +84,76 @@ function RemoteEdit(props) {
95
84
  });
96
85
  if (Exit.isFailure(exit)) {
97
86
  setError("Failed to update authentication methods");
98
- setSaving(false);
99
- return;
87
+ return { ok: false };
100
88
  }
101
- setSaving(false);
89
+ return { ok: true, summary: "Authentication methods updated." };
102
90
  }, [doConfigureAuth, editedMethods, server.slug]);
103
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
104
- /* @__PURE__ */ jsxs("div", { children: [
105
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit MCP Source" }),
106
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Manage how this MCP server authenticates. The endpoint is part of the server's identity \u2014 remove and re-add to change it. Accounts are added from the integration page." })
91
+ const onPendingChangeRef = useRef(props.onPendingChange);
92
+ onPendingChangeRef.current = props.onPendingChange;
93
+ useEffect(() => {
94
+ onPendingChangeRef.current?.(methodsChanged ? applyStaged : null);
95
+ return () => onPendingChangeRef.current?.(null);
96
+ }, [methodsChanged, applyStaged]);
97
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4 border-t border-border/60 pt-5", children: [
98
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
99
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Authentication methods" }),
100
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
101
+ "Changes apply when you save. The endpoint (",
102
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: server.config.endpoint }),
103
+ ") is part of the server's identity \u2014 remove and re-add to change it."
104
+ ] })
107
105
  ] }),
108
- /* @__PURE__ */ jsx(CardStack, { children: /* @__PURE__ */ jsx(CardStackContent, { className: "border-t-0", children: /* @__PURE__ */ jsxs(CardStackEntry, { children: [
109
- /* @__PURE__ */ jsxs(CardStackEntryContent, { children: [
110
- /* @__PURE__ */ jsx(CardStackEntryTitle, { children: server.description || String(server.slug) }),
111
- /* @__PURE__ */ jsx(CardStackEntryDescription, { className: "font-mono text-xs", children: server.config.endpoint })
112
- ] }),
113
- /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: "remote" })
114
- ] }) }) }),
115
106
  /* @__PURE__ */ jsx(
116
107
  AuthMethodListEditor,
117
108
  {
118
109
  list,
119
- title: "How does this server authenticate?",
120
110
  oauthMetadata: "discovered",
121
111
  emptyHint: "No methods declared. Add one, or save to mark this server as open (no authentication).",
122
112
  footerHint: "Connections pick one of these methods. Removing a method detaches connections created against it."
123
113
  }
124
114
  ),
125
- methodsChanged ? /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: () => void handleSave(), disabled: saving, children: saving ? "Saving\u2026" : "Save authentication methods" }) }) : null,
126
- error && /* @__PURE__ */ jsx(FormErrorAlert, { message: error }),
127
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end border-t border-border pt-4", children: /* @__PURE__ */ jsx(Button, { onClick: props.onSave, children: "Done" }) })
115
+ error && /* @__PURE__ */ jsx(FormErrorAlert, { message: error })
128
116
  ] });
129
117
  }
130
118
  function StdioReadOnly(props) {
131
119
  const { command, args } = props.server.config;
132
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
133
- /* @__PURE__ */ jsxs("div", { children: [
134
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit MCP Source" }),
135
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Stdio MCP sources cannot be edited in the UI. Remove and recreate the source with the updated command." })
120
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 border-t border-border/60 pt-5", children: [
121
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
122
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Server command" }),
123
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Stdio MCP sources cannot be edited. Remove and recreate the source with the updated command." })
136
124
  ] }),
137
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-card px-4 py-3", children: [
138
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
139
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-card-foreground", children: String(props.server.slug) }),
140
- /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground font-mono", children: [
141
- command,
142
- " ",
143
- (args ?? []).join(" ")
144
- ] })
125
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border/60 bg-muted/40 px-3 py-2", children: [
126
+ /* @__PURE__ */ jsxs("p", { className: "min-w-0 flex-1 truncate font-mono text-xs text-foreground", children: [
127
+ command,
128
+ " ",
129
+ (args ?? []).join(" ")
145
130
  ] }),
146
131
  /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: "stdio" })
147
- ] }),
148
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end border-t border-border pt-4", children: /* @__PURE__ */ jsx(Button, { onClick: props.onSave, children: "Done" }) })
132
+ ] })
149
133
  ] });
150
134
  }
151
- function EditMcpSource({
152
- sourceId,
153
- onSave
154
- }) {
135
+ function EditMcpSource({ sourceId, onPendingChange }) {
155
136
  const slug = IntegrationSlug.make(sourceId);
156
137
  const serverResult = useAtomValue(mcpServerAtom(slug));
157
138
  const server = AsyncResult.isSuccess(serverResult) ? serverResult.value : null;
158
- if (!AsyncResult.isSuccess(serverResult) || server === null) {
159
- return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { children: [
160
- /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Edit MCP Source" }),
161
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Loading configuration\u2026" })
162
- ] }) });
163
- }
139
+ if (!AsyncResult.isSuccess(serverResult) || server === null) return null;
164
140
  if (server.config.transport === "stdio") {
165
141
  return /* @__PURE__ */ jsx(
166
142
  StdioReadOnly,
167
143
  {
168
- server,
169
- onSave
144
+ server
170
145
  }
171
146
  );
172
147
  }
173
- return /* @__PURE__ */ jsx(RemoteEdit, { server, onSave });
148
+ return /* @__PURE__ */ jsx(
149
+ RemoteEdit,
150
+ {
151
+ server,
152
+ ...onPendingChange ? { onPendingChange } : {}
153
+ }
154
+ );
174
155
  }
175
156
  export {
176
157
  EditMcpSource as default
177
158
  };
178
- //# sourceMappingURL=EditMcpSource-75NJRWZR.js.map
159
+ //# sourceMappingURL=EditMcpSource-BV5ZEWEY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/EditMcpSource.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAtomValue, useAtomSet } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport * as Exit from \"effect/Exit\";\n\nimport { IntegrationSlug } from \"@executor-js/sdk/shared\";\nimport type { EditSheetApplyResult, EditSheetSectionProps } from \"@executor-js/sdk/client\";\nimport { apiKeyMethodLabel, type AuthPlacement } from \"@executor-js/sdk/http-auth\";\nimport { integrationWriteKeys } from \"@executor-js/react/api/reactivity-keys\";\nimport {\n AuthMethodListEditor,\n useAuthMethodList,\n type AuthMethodRow,\n type AuthMethodSeed,\n} from \"@executor-js/react/components/auth-method-list-editor\";\nimport { Badge } from \"@executor-js/react/components/badge\";\nimport { FormErrorAlert } from \"@executor-js/react/lib/integration-add\";\n\nimport { configureMcpAuth, mcpServerAtom } from \"./atoms\";\nimport type {\n McpAuthMethod,\n McpCanonicalAuthMethodInput,\n McpIntegrationConfig,\n} from \"../sdk/types\";\nimport {\n editorValueFromMcpAuthMethod,\n mcpAuthMethodInputFromEditorValue,\n mcpWireAuthInput,\n} from \"./auth-method-config\";\n\ntype McpServer = {\n readonly slug: IntegrationSlug;\n readonly description: string;\n readonly kind: string;\n readonly canRemove: boolean;\n readonly canRefresh: boolean;\n readonly config: McpIntegrationConfig;\n};\n\ntype McpRemoteConfig = Extract<McpIntegrationConfig, { transport: \"remote\" }>;\n\nconst methodSeedLabel = (method: McpAuthMethod): string => {\n if (method.kind === \"oauth2\") return \"OAuth\";\n if (method.kind === \"apikey\") return apiKeyMethodLabel(method);\n return \"No authentication\";\n};\n\nconst samePlacements = (\n a: readonly AuthPlacement[] | undefined,\n b: readonly AuthPlacement[] | undefined,\n): boolean => {\n const left = a ?? [];\n const right = b ?? [];\n if (left.length !== right.length) return false;\n return left.every((placement: AuthPlacement, index: number) => {\n const other = right[index];\n return (\n other !== undefined &&\n placement.carrier === other.carrier &&\n placement.name === other.name &&\n (placement.prefix ?? \"\") === (other.prefix ?? \"\") &&\n (placement.variable ?? \"\") === (other.variable ?? \"\") &&\n (placement.literal ?? null) === (other.literal ?? null)\n );\n });\n};\n\n// ---------------------------------------------------------------------------\n// Remote edit — v2: the integration's endpoint is part of its identity\n// (opaque-to-core config); the editable surface is the declared auth-method\n// LIST, through the same shared editor as the add flow. Accounts (credentials)\n// are managed from the integration page's accounts hub. Rendered inside the\n// integration Edit sheet (plugin `editSheet` slot).\n// ---------------------------------------------------------------------------\n\nfunction RemoteEdit(props: {\n server: McpServer & { config: McpRemoteConfig };\n onPendingChange?: EditSheetSectionProps[\"onPendingChange\"];\n}) {\n const { server } = props;\n const doConfigureAuth = useAtomSet(configureMcpAuth, { mode: \"promiseExit\" });\n\n const seeds = useMemo<readonly AuthMethodSeed[]>(\n () =>\n server.config.authenticationTemplate.map(\n (method: McpAuthMethod): AuthMethodSeed => ({\n value: editorValueFromMcpAuthMethod(method),\n slug: method.slug,\n label: methodSeedLabel(method),\n }),\n ),\n [server.config.authenticationTemplate],\n );\n const list = useAuthMethodList(seeds);\n\n const [error, setError] = useState<string | null>(null);\n\n // The edited methods, slugs preserved for seeded rows so existing\n // connections (bound by template slug) stay attached. New rows omit the\n // slug — the backend assigns kind-based ones.\n const editedMethods = useMemo<readonly McpCanonicalAuthMethodInput[]>(\n () =>\n list.rows.map((row: AuthMethodRow): McpCanonicalAuthMethodInput => {\n const input = mcpAuthMethodInputFromEditorValue(row.value);\n return row.seedSlug !== undefined ? { ...input, slug: row.seedSlug } : input;\n }),\n [list.rows],\n );\n\n const methodsChanged = useMemo(() => {\n const stored = server.config.authenticationTemplate;\n if (editedMethods.length !== stored.length) return true;\n return editedMethods.some((method: McpCanonicalAuthMethodInput, index: number) => {\n const current = stored[index];\n if (!current) return true;\n if ((method.slug ?? \"\") !== current.slug) return true;\n if (method.kind !== current.kind) return true;\n if (method.kind === \"apikey\" && current.kind === \"apikey\") {\n return !samePlacements(method.placements, current.placements);\n }\n return false;\n });\n }, [editedMethods, server.config.authenticationTemplate]);\n\n // Staged apply, run by the sheet's Save when the method list changed.\n const applyStaged = useCallback(async (): Promise<EditSheetApplyResult> => {\n setError(null);\n const exit = await doConfigureAuth({\n params: { slug: server.slug },\n payload: {\n authenticationTemplate:\n editedMethods.length > 0\n ? editedMethods.map(mcpWireAuthInput)\n : [{ kind: \"none\" as const }],\n mode: \"replace\",\n },\n reactivityKeys: integrationWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setError(\"Failed to update authentication methods\");\n return { ok: false };\n }\n return { ok: true, summary: \"Authentication methods updated.\" };\n }, [doConfigureAuth, editedMethods, server.slug]);\n\n const onPendingChangeRef = useRef(props.onPendingChange);\n onPendingChangeRef.current = props.onPendingChange;\n useEffect(() => {\n onPendingChangeRef.current?.(methodsChanged ? applyStaged : null);\n return () => onPendingChangeRef.current?.(null);\n }, [methodsChanged, applyStaged]);\n\n return (\n <div className=\"space-y-4 border-t border-border/60 pt-5\">\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-foreground\">Authentication methods</p>\n <p className=\"text-xs text-muted-foreground\">\n Changes apply when you save. The endpoint (\n <span className=\"font-mono\">{server.config.endpoint}</span>) is part of the server's\n identity — remove and re-add to change it.\n </p>\n </div>\n\n <AuthMethodListEditor\n list={list}\n oauthMetadata=\"discovered\"\n emptyHint=\"No methods declared. Add one, or save to mark this server as open (no authentication).\"\n footerHint=\"Connections pick one of these methods. Removing a method detaches connections created against it.\"\n />\n\n {error && <FormErrorAlert message={error} />}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Stdio read-only view\n// ---------------------------------------------------------------------------\n\nfunction StdioReadOnly(props: {\n server: McpServer & { config: Extract<McpIntegrationConfig, { transport: \"stdio\" }> };\n}) {\n const { command, args } = props.server.config;\n return (\n <div className=\"space-y-3 border-t border-border/60 pt-5\">\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-foreground\">Server command</p>\n <p className=\"text-xs text-muted-foreground\">\n Stdio MCP sources cannot be edited. Remove and recreate the source with the updated\n command.\n </p>\n </div>\n <div className=\"flex items-center gap-3 rounded-md border border-border/60 bg-muted/40 px-3 py-2\">\n <p className=\"min-w-0 flex-1 truncate font-mono text-xs text-foreground\">\n {command} {(args ?? []).join(\" \")}\n </p>\n <Badge variant=\"secondary\" className=\"text-xs\">\n stdio\n </Badge>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component — the mcp plugin's section of the integration Edit sheet.\n// `sourceId` is the integration slug (v2).\n// ---------------------------------------------------------------------------\n\nexport default function EditMcpSource({ sourceId, onPendingChange }: EditSheetSectionProps) {\n const slug = IntegrationSlug.make(sourceId);\n const serverResult = useAtomValue(mcpServerAtom(slug));\n const server = AsyncResult.isSuccess(serverResult) ? serverResult.value : null;\n\n if (!AsyncResult.isSuccess(serverResult) || server === null) return null;\n\n if (server.config.transport === \"stdio\") {\n return (\n <StdioReadOnly\n server={\n server as McpServer & { config: Extract<McpIntegrationConfig, { transport: \"stdio\" }> }\n }\n />\n );\n }\n\n return (\n <RemoteEdit\n server={server as McpServer & { config: McpRemoteConfig }}\n {...(onPendingChange ? { onPendingChange } : {})}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  mcpAuthMethodInputsFromPlacements,
5
5
  mcpServerAtom,
6
6
  mcpWireAuthInput
7
- } from "./chunk-3AOD4VAW.js";
7
+ } from "./chunk-AL7N323J.js";
8
8
  import "./chunk-3H5Y7JCQ.js";
9
9
 
10
10
  // src/react/McpAccountsPanel.tsx
@@ -80,4 +80,4 @@ function McpAccountsPanel(props) {
80
80
  export {
81
81
  McpAccountsPanel as default
82
82
  };
83
- //# sourceMappingURL=McpAccountsPanel-QBCSCJE7.js.map
83
+ //# sourceMappingURL=McpAccountsPanel-Y3D6HSPC.js.map
@@ -15,9 +15,13 @@ export declare const McpGroup: HttpApiGroup.HttpApiGroup<"mcp", HttpApiEndpoint.
15
15
  readonly slug: Schema.String;
16
16
  readonly toolCount: Schema.NullOr<Schema.Number>;
17
17
  readonly serverName: Schema.NullOr<Schema.String>;
18
+ /** Server `instructions` from initialize — prefills the description field. */
19
+ readonly instructions: Schema.NullOr<Schema.String>;
18
20
  }>>, HttpApiEndpoint.Json<typeof InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"addServer", "POST", "/mcp/servers", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Union<readonly [Schema.Struct<{
19
21
  readonly transport: Schema.optional<Schema.Literal<"remote">>;
20
22
  readonly name: Schema.String;
23
+ /** Agent-visible catalog description. Defaults to the display name. */
24
+ readonly description: Schema.optional<Schema.String>;
21
25
  readonly endpoint: Schema.String;
22
26
  readonly remoteTransport: Schema.optional<Schema.Literals<readonly ["streamable-http", "sse", "auto"]>>;
23
27
  readonly slug: Schema.optional<Schema.String>;
@@ -57,6 +61,7 @@ export declare const McpGroup: HttpApiGroup.HttpApiGroup<"mcp", HttpApiEndpoint.
57
61
  }>, Schema.Struct<{
58
62
  readonly transport: Schema.Literal<"stdio">;
59
63
  readonly name: Schema.String;
64
+ readonly description: Schema.optional<Schema.String>;
60
65
  readonly command: Schema.String;
61
66
  readonly args: Schema.optional<Schema.$Array<Schema.String>>;
62
67
  readonly env: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
@@ -12,6 +12,7 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
12
12
  slug: string;
13
13
  toolCount: number;
14
14
  serverName: string | null;
15
+ instructions: string | null;
15
16
  } | {
16
17
  connected: false;
17
18
  requiresAuthentication: true;
@@ -21,6 +22,7 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
21
22
  slug: string;
22
23
  toolCount: null;
23
24
  serverName: null;
25
+ instructions: null;
24
26
  } | {
25
27
  connected: false;
26
28
  requiresAuthentication: true;
@@ -30,6 +32,7 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
30
32
  slug: string;
31
33
  toolCount: null;
32
34
  serverName: null;
35
+ instructions: null;
33
36
  }, import("../sdk").McpConnectionError, never>;
34
37
  addServer: (input: import("../promise").McpServerInput) => import("effect/Effect").Effect<{
35
38
  slug: string;
@@ -68,9 +71,11 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
68
71
  readonly slug: import("effect/Schema").String;
69
72
  readonly toolCount: import("effect/Schema").NullOr<import("effect/Schema").Number>;
70
73
  readonly serverName: import("effect/Schema").NullOr<import("effect/Schema").String>;
74
+ readonly instructions: import("effect/Schema").NullOr<import("effect/Schema").String>;
71
75
  }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof import("../sdk").McpConnectionError | typeof import("../sdk").McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"addServer", "POST", "/mcp/servers", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
72
76
  readonly transport: import("effect/Schema").optional<import("effect/Schema").Literal<"remote">>;
73
77
  readonly name: import("effect/Schema").String;
78
+ readonly description: import("effect/Schema").optional<import("effect/Schema").String>;
74
79
  readonly endpoint: import("effect/Schema").String;
75
80
  readonly remoteTransport: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["streamable-http", "sse", "auto"]>>;
76
81
  readonly slug: import("effect/Schema").optional<import("effect/Schema").String>;
@@ -107,6 +112,7 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
107
112
  }>, import("effect/Schema").Struct<{
108
113
  readonly transport: import("effect/Schema").Literal<"stdio">;
109
114
  readonly name: import("effect/Schema").String;
115
+ readonly description: import("effect/Schema").optional<import("effect/Schema").String>;
110
116
  readonly command: import("effect/Schema").String;
111
117
  readonly args: import("effect/Schema").optional<import("effect/Schema").$Array<import("effect/Schema").String>>;
112
118
  readonly env: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").String>>;
@@ -30,6 +30,8 @@ var StringMap = Schema.Record(Schema.String, Schema.String);
30
30
  var AddRemoteServerPayload = Schema.Struct({
31
31
  transport: Schema.optional(Schema.Literal("remote")),
32
32
  name: Schema.String,
33
+ /** Agent-visible catalog description. Defaults to the display name. */
34
+ description: Schema.optional(Schema.String),
33
35
  endpoint: Schema.String,
34
36
  remoteTransport: Schema.optional(Schema.Literals(["streamable-http", "sse", "auto"])),
35
37
  slug: Schema.optional(Schema.String),
@@ -44,6 +46,7 @@ var AddRemoteServerPayload = Schema.Struct({
44
46
  var AddStdioServerPayload = Schema.Struct({
45
47
  transport: Schema.Literal("stdio"),
46
48
  name: Schema.String,
49
+ description: Schema.optional(Schema.String),
47
50
  command: Schema.String,
48
51
  args: Schema.optional(Schema.Array(Schema.String)),
49
52
  env: Schema.optional(StringMap),
@@ -64,7 +67,9 @@ var ProbeEndpointResponse = Schema.Struct({
64
67
  name: Schema.String,
65
68
  slug: Schema.String,
66
69
  toolCount: Schema.NullOr(Schema.Number),
67
- serverName: Schema.NullOr(Schema.String)
70
+ serverName: Schema.NullOr(Schema.String),
71
+ /** Server `instructions` from initialize — prefills the description field. */
72
+ instructions: Schema.NullOr(Schema.String)
68
73
  });
69
74
  var AddServerResponse = Schema.Struct({
70
75
  slug: Schema.String
@@ -212,4 +217,4 @@ export {
212
217
  authMethodsFromConfig,
213
218
  mcpAuthMethodInputsFromPlacements
214
219
  };
215
- //# sourceMappingURL=chunk-3AOD4VAW.js.map
220
+ //# sourceMappingURL=chunk-AL7N323J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/atoms.ts","../src/react/client.ts","../src/api/group.ts","../src/react/auth-method-config.ts"],"sourcesContent":["import type { IntegrationSlug } from \"@executor-js/sdk/shared\";\nimport { ReactivityKey } from \"@executor-js/react/api/reactivity-keys\";\nimport { McpClient } from \"./client\";\n\n// ---------------------------------------------------------------------------\n// Query atoms (v2)\n//\n// An MCP server is an integration. `getServer` reads the integration row's\n// opaque config (transport, endpoint, auth template). Credentials are separate\n// owner-scoped connections, created through the core connections / oauth surface\n// — there is no per-server credential binding to read here anymore.\n// ---------------------------------------------------------------------------\n\nexport const mcpServerAtom = (slug: IntegrationSlug) =>\n McpClient.query(\"mcp\", \"getServer\", {\n params: { slug },\n timeToLive: \"15 seconds\",\n reactivityKeys: [ReactivityKey.integrations, ReactivityKey.tools],\n });\n\n// ---------------------------------------------------------------------------\n// Mutation atoms\n// ---------------------------------------------------------------------------\n\nexport const probeMcpEndpoint = McpClient.mutation(\"mcp\", \"probeEndpoint\");\nexport const addMcpServer = McpClient.mutation(\"mcp\", \"addServer\");\nexport const removeMcpServer = McpClient.mutation(\"mcp\", \"removeServer\");\nexport const configureMcpServer = McpClient.mutation(\"mcp\", \"configureServer\");\n// Merge-append auth methods onto an integration's `authenticationTemplate`.\nexport const configureMcpAuth = McpClient.mutation(\"mcp\", \"configureAuth\");\n","import { createPluginAtomClient } from \"@executor-js/sdk/client\";\nimport {\n getExecutorApiBaseUrl,\n getExecutorServerAuthorizationHeader,\n} from \"@executor-js/react/api/server-connection\";\nimport { McpGroup } from \"../api/group\";\n\nexport const McpClient = createPluginAtomClient(McpGroup, {\n baseUrl: getExecutorApiBaseUrl,\n authorizationHeader: getExecutorServerAuthorizationHeader,\n});\n","import { HttpApiEndpoint, HttpApiGroup } from \"effect/unstable/httpapi\";\nimport { Schema } from \"effect\";\nimport {\n IntegrationSlug,\n InternalError,\n IntegrationAlreadyExistsError,\n} from \"@executor-js/sdk/shared\";\n\nimport { McpConnectionError, McpToolDiscoveryError } from \"../sdk/errors\";\nimport {\n McpAuthMethod,\n McpAuthMethodInput,\n McpAuthShorthand,\n McpIntegrationConfig,\n} from \"../sdk/types\";\n\n// ---------------------------------------------------------------------------\n// Params\n// ---------------------------------------------------------------------------\n\nconst SlugParams = { slug: IntegrationSlug };\n\nconst StringMap = Schema.Record(Schema.String, Schema.String);\n\n// ---------------------------------------------------------------------------\n// Add server — discriminated union on transport. An MCP server is registered\n// as an integration; connections (credentials) are created separately through\n// the core connections / oauth surface.\n// ---------------------------------------------------------------------------\n\nconst AddRemoteServerPayload = Schema.Struct({\n transport: Schema.optional(Schema.Literal(\"remote\")),\n name: Schema.String,\n /** Agent-visible catalog description. Defaults to the display name. */\n description: Schema.optional(Schema.String),\n endpoint: Schema.String,\n remoteTransport: Schema.optional(Schema.Literals([\"streamable-http\", \"sse\", \"auto\"])),\n slug: Schema.optional(Schema.String),\n queryParams: Schema.optional(StringMap),\n headers: Schema.optional(StringMap),\n /** Declared auth methods a connection can be applied through. */\n authenticationTemplate: Schema.optional(Schema.Array(McpAuthMethodInput)),\n /** Single-method shorthand (legacy callers); ignored when\n * `authenticationTemplate` is present. */\n auth: Schema.optional(McpAuthShorthand),\n});\n\nconst AddStdioServerPayload = Schema.Struct({\n transport: Schema.Literal(\"stdio\"),\n name: Schema.String,\n description: Schema.optional(Schema.String),\n command: Schema.String,\n args: Schema.optional(Schema.Array(Schema.String)),\n env: Schema.optional(StringMap),\n cwd: Schema.optional(Schema.String),\n slug: Schema.optional(Schema.String),\n});\n\nconst AddServerPayload = Schema.Union([AddRemoteServerPayload, AddStdioServerPayload]);\n\nconst ProbeEndpointPayload = Schema.Struct({\n endpoint: Schema.String,\n headers: Schema.optional(StringMap),\n queryParams: Schema.optional(StringMap),\n});\n\nconst ProbeEndpointResponse = Schema.Struct({\n connected: Schema.Boolean,\n requiresAuthentication: Schema.Boolean,\n requiresOAuth: Schema.Boolean,\n supportsDynamicRegistration: Schema.Boolean,\n name: Schema.String,\n slug: Schema.String,\n toolCount: Schema.NullOr(Schema.Number),\n serverName: Schema.NullOr(Schema.String),\n /** Server `instructions` from initialize — prefills the description field. */\n instructions: Schema.NullOr(Schema.String),\n});\n\n// ---------------------------------------------------------------------------\n// Responses\n// ---------------------------------------------------------------------------\n\nconst AddServerResponse = Schema.Struct({\n slug: Schema.String,\n});\n\nconst RemoveServerResponse = Schema.Struct({\n removed: Schema.Boolean,\n});\n\nconst ConfigureServerPayload = Schema.Struct({\n config: McpIntegrationConfig,\n});\n\nconst ConfigureServerResponse = Schema.Struct({\n config: McpIntegrationConfig,\n});\n\n// The configureAuth payload/response — custom auth methods to merge-append\n// onto the integration's `authenticationTemplate` (or `replace` the set).\n// Mirrors the GraphQL/OpenAPI configure endpoints.\nconst ConfigureAuthPayload = Schema.Struct({\n authenticationTemplate: Schema.Array(McpAuthMethodInput),\n mode: Schema.optional(Schema.Literals([\"merge\", \"replace\"])),\n});\n\nconst ConfigureAuthResponse = Schema.Struct({\n authenticationTemplate: Schema.Array(McpAuthMethod),\n});\n\nconst GetServerResponse = Schema.NullOr(\n Schema.Struct({\n slug: IntegrationSlug,\n description: Schema.String,\n kind: Schema.String,\n canRemove: Schema.Boolean,\n canRefresh: Schema.Boolean,\n config: McpIntegrationConfig,\n }),\n);\n\n// ---------------------------------------------------------------------------\n// Group\n//\n// Integrations are tenant-level (no scope segment); plugin domain errors carry\n// their own `HttpApiSchema` status (4xx). `InternalError` is the shared opaque\n// 500 translated at the HTTP edge.\n// ---------------------------------------------------------------------------\n\nexport const McpGroup = HttpApiGroup.make(\"mcp\")\n .add(\n HttpApiEndpoint.post(\"probeEndpoint\", \"/mcp/probe\", {\n payload: ProbeEndpointPayload,\n success: ProbeEndpointResponse,\n error: [InternalError, McpConnectionError, McpToolDiscoveryError],\n }),\n )\n .add(\n HttpApiEndpoint.post(\"addServer\", \"/mcp/servers\", {\n payload: AddServerPayload,\n success: AddServerResponse,\n error: [\n InternalError,\n McpConnectionError,\n McpToolDiscoveryError,\n IntegrationAlreadyExistsError,\n ],\n }),\n )\n .add(\n HttpApiEndpoint.delete(\"removeServer\", \"/mcp/servers/:slug\", {\n params: SlugParams,\n success: RemoveServerResponse,\n error: [InternalError, McpConnectionError, McpToolDiscoveryError],\n }),\n )\n .add(\n HttpApiEndpoint.get(\"getServer\", \"/mcp/servers/:slug\", {\n params: SlugParams,\n success: GetServerResponse,\n error: [InternalError, McpConnectionError, McpToolDiscoveryError],\n }),\n )\n .add(\n HttpApiEndpoint.post(\"configureServer\", \"/mcp/servers/:slug/config\", {\n params: SlugParams,\n payload: ConfigureServerPayload,\n success: ConfigureServerResponse,\n error: [InternalError, McpConnectionError, McpToolDiscoveryError],\n }),\n )\n .add(\n HttpApiEndpoint.post(\"configureAuth\", \"/mcp/servers/:slug/auth\", {\n params: SlugParams,\n payload: ConfigureAuthPayload,\n success: ConfigureAuthResponse,\n error: [InternalError, McpConnectionError, McpToolDiscoveryError],\n }),\n );\n","// ---------------------------------------------------------------------------\n// MCP ↔ generic auth-method converters — a thin oauth adapter over the shared\n// codec (`@executor-js/react/lib/shared-auth-method-codec`). The apikey/none\n// paths (multi-placement, multi-variable) live in the shared codec; MCP only\n// contributes its oauth flavor: endpoint-less methods whose metadata is\n// discovered at connect time (`discoveryUrl` = the MCP endpoint).\n// ---------------------------------------------------------------------------\n\nimport { AuthTemplateSlug } from \"@executor-js/sdk/shared\";\nimport type { AuthTemplateEditorValue } from \"@executor-js/react/components/auth-template-editor\";\nimport type { AuthMethod, Placement } from \"@executor-js/react/lib/auth-placements\";\nimport {\n authMethodFromSharedTemplate,\n editorValueFromSharedMethod,\n sharedMethodInputFromEditorValue,\n wirePlacementsFromEditor,\n} from \"@executor-js/react/lib/shared-auth-method-codec\";\n\nimport { wireAuthInputFromShared } from \"@executor-js/react/lib/shared-auth-method-codec\";\nimport type { McpAuthMethod, McpAuthMethodInput, McpCanonicalAuthMethodInput } from \"../sdk/types\";\n\n/** Serialize a canonical method into the wire input union (apikey → the\n * request-shaped dialect; none/oauth2 pass through). */\nexport const mcpWireAuthInput = (\n method: McpAuthMethod | McpCanonicalAuthMethodInput,\n): McpAuthMethodInput => wireAuthInputFromShared(method) as McpAuthMethodInput;\n\nconst oauthAuthMethod = (slug: string, endpoint: string): AuthMethod => ({\n id: slug,\n label: \"OAuth\",\n kind: \"oauth\",\n source: slug.startsWith(\"custom_\") ? \"custom\" : \"spec\",\n template: AuthTemplateSlug.make(slug),\n placements: [],\n oauth: { discoveryUrl: endpoint, supportsDynamicRegistration: true },\n});\n\n/** Convert a generic editor value into one MCP auth-method input (no slug —\n * the backend assigns carrier-derived slugs). An apikey value keeps every\n * named placement (headers and query params mix freely); one with no usable\n * placement falls back to `none`. */\nexport function mcpAuthMethodInputFromEditorValue(\n value: AuthTemplateEditorValue,\n): McpCanonicalAuthMethodInput {\n if (value.kind === \"oauth\") return { kind: \"oauth2\" };\n return (sharedMethodInputFromEditorValue(value) ?? {\n kind: \"none\",\n }) as McpCanonicalAuthMethodInput;\n}\n\n/** Convert one stored MCP method into the generic editor value. */\nexport function editorValueFromMcpAuthMethod(method: McpAuthMethod): AuthTemplateEditorValue {\n if (method.kind === \"oauth2\") {\n return { kind: \"oauth\", authorizationUrl: \"\", tokenUrl: \"\", scopes: [] };\n }\n return editorValueFromSharedMethod(method);\n}\n\n/** Project the stored methods into the generic `AuthMethod[]` the hub renders.\n * Mirrors the server's `describeMcpAuthMethods`; `custom_` slugs mark\n * user-created methods (removable from the hub). `endpoint` feeds the oauth\n * method's probe-at-connect `discoveryUrl`. */\nexport function authMethodsFromConfig(\n methods: readonly McpAuthMethod[],\n endpoint: string,\n): AuthMethod[] {\n return methods.map((method: McpAuthMethod): AuthMethod => {\n if (method.kind === \"oauth2\") return oauthAuthMethod(method.slug, endpoint);\n return authMethodFromSharedTemplate(method);\n });\n}\n\n/** Build the MCP method input for a custom method from generic placements —\n * ONE method carrying every named placement (header + query mix in a single\n * method; each placement renders from its own input variable, or shares one).\n * Empty when no placement is usable. */\nexport function mcpAuthMethodInputsFromPlacements(\n placements: readonly Placement[],\n): McpCanonicalAuthMethodInput[] {\n const wire = wirePlacementsFromEditor(placements);\n if (wire.length === 0) return [];\n return [{ kind: \"apikey\", placements: wire }];\n}\n"],"mappings":"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","names":[]}