import { useEffect, useState, type ReactNode } from "react"; import { Link, useNavigate } from "@tanstack/react-router"; import { type CompleteSourceOAuthResult, type CreateSourcePayload, type InstanceConfig, type Loadable, type StartSourceOAuthPayload, type SecretListItem, type Source, type UpdateSourcePayload, useCreateSecret, useCreateSource, useInstanceConfig, useRefreshSecrets, useRemoveProviderAuthGrant, useRemoveSource, useSecrets, useSources, useStartSourceOAuth, useSource, useUpdateSource, } from "@executor/react"; import { Badge } from "../components/ui/badge"; import { Button } from "../components/ui/button"; import { LoadableBlock } from "../components/loadable"; import { SourceNotFoundState } from "../components/source-not-found-state"; import { SourceFavicon } from "../components/source-favicon"; import { IconArrowLeft, IconPencil, IconPlus, IconSpinner, IconTrash, } from "../components/icons"; import { cn } from "../lib/utils"; import { asMcpRemoteTransportValue, defaultMcpRemoteTransportFields, defaultMcpStdioTransportFields, setMcpTransportFieldsTransport, type McpRemoteTransportFields, type McpStdioTransportFields, type McpTransportFields, type McpTransportValue, } from "./mcp-transport-state"; import { parseJsonStringArray, parseJsonStringMap } from "./json-form"; import { sourceTemplates, type SourceTemplate } from "./source-templates"; import { getDomain } from "tldts"; type StatusBannerState = { tone: "info" | "success" | "error"; text: string; }; type SourceOAuthPopupMessage = | { type: "executor:oauth-result"; ok: true; sessionId: string; auth: CompleteSourceOAuthResult["auth"]; } | { type: "executor:oauth-result"; ok: false; sessionId: string | null; error: string; }; const SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS = 2 * 60_000; const SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX = "executor:oauth-result:"; const isSourceNotFoundLoadable = (loadable: Loadable): boolean => loadable.status === "error" && loadable.error.message.toLowerCase().includes("source not found"); type SourceFormBase = { name: string; kind: Source["kind"]; endpoint: string; namespace: string; enabled: boolean; specUrl: string; service: string; version: string; defaultHeadersText: string; authKind: Source["auth"]["kind"]; authHeaderName: string; authPrefix: string; bearerProviderId: string; bearerHandle: string; oauthAccessProviderId: string; oauthAccessHandle: string; oauthRefreshProviderId: string; oauthRefreshHandle: string; managedAuth: Extract< Source["auth"], { kind: "provider_grant_ref" | "mcp_oauth" } > | null; }; type SourceFormState = SourceFormBase & McpTransportFields; const kindOptions: ReadonlyArray = [ "mcp", "openapi", "graphql", "google_discovery", "internal", ]; const transportOptions: ReadonlyArray> = [ "auto", "streamable-http", "sse", "stdio", ]; const authOptions: ReadonlyArray = [ "none", "bearer", "oauth2", "provider_grant_ref", "mcp_oauth", ]; const trimToNull = (value: string): string | null => { const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; }; const namespaceFromUrl = (url: string): string => { try { const domain = getDomain(url); if (!domain) return ""; const dot = domain.indexOf("."); return dot > 0 ? domain.slice(0, dot) : domain; } catch { return ""; } }; const googleDiscoveryNamespace = (service: string): string => `google.${service .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, ".") .replace(/^\.+|\.+$/g, "")}`; const readStoredSourceOAuthPopupResult = ( sessionId: string, ): SourceOAuthPopupMessage | null => { if (typeof window === "undefined") { return null; } const raw = window.localStorage.getItem( `${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`, ); if (!raw) { return null; } try { return JSON.parse(raw) as SourceOAuthPopupMessage; } catch { return null; } }; const clearStoredSourceOAuthPopupResult = (sessionId: string): void => { if (typeof window === "undefined") { return; } window.localStorage.removeItem( `${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`, ); }; const startSourceOAuthPopup = async (input: { authorizationUrl: string; sessionId: string; }): Promise => { if (typeof window === "undefined") { throw new Error("OAuth popup is only available in a browser context"); } clearStoredSourceOAuthPopupResult(input.sessionId); const popup = window.open( input.authorizationUrl, "executor-source-oauth", "popup=yes,width=520,height=720", ); if (!popup) { throw new Error("Popup blocked. Allow popups and try again."); } popup.focus(); return await new Promise( (resolve, reject) => { let settled = false; let closedPoll = 0; let resultTimeout = 0; const cleanup = () => { window.removeEventListener("message", onMessage); if (closedPoll) { window.clearInterval(closedPoll); } if (resultTimeout) { window.clearTimeout(resultTimeout); } if (!popup.closed) { popup.close(); } clearStoredSourceOAuthPopupResult(input.sessionId); }; const settleWithError = (message: string) => { if (settled) { return; } settled = true; cleanup(); reject(new Error(message)); }; const settleFromPayload = (data: SourceOAuthPopupMessage) => { if (!data.ok) { settleWithError(data.error || "OAuth failed"); return; } if (settled) { return; } settled = true; cleanup(); resolve(data.auth); }; const onMessage = (event: MessageEvent) => { if (event.origin !== window.location.origin) { return; } const data = event.data as SourceOAuthPopupMessage | undefined; if (!data || data.type !== "executor:oauth-result") { return; } if (data.ok && data.sessionId !== input.sessionId) { return; } if ( !data.ok && data.sessionId !== null && data.sessionId !== input.sessionId ) { return; } settleFromPayload(data); }; window.addEventListener("message", onMessage); resultTimeout = window.setTimeout(() => { settleWithError( "OAuth popup timed out before completion. Please try again.", ); }, SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS); closedPoll = window.setInterval(() => { const stored = readStoredSourceOAuthPopupResult(input.sessionId); if (stored) { settleFromPayload(stored); return; } if (popup.closed) { // Stop polling — only run one final deferred check to give the // callback page time to write localStorage before we give up. window.clearInterval(closedPoll); closedPoll = 0; window.setTimeout(() => { const delayedStored = readStoredSourceOAuthPopupResult( input.sessionId, ); if (delayedStored) { settleFromPayload(delayedStored); return; } settleWithError("OAuth popup was closed before completion."); }, 1500); } }, 300); }, ); }; const stringMapToEditor = (value: Record | null): string => value === null ? "" : JSON.stringify(value, null, 2); const stringArrayToEditor = ( value: ReadonlyArray | null | undefined, ): string => !value || value.length === 0 ? "" : JSON.stringify(value, null, 2); const readBindingStringMap = ( source: Source, key: string, ): Record | null => { const candidate = source.binding[key]; if ( candidate === null || candidate === undefined || typeof candidate !== "object" || Array.isArray(candidate) ) { return null; } const entries = Object.entries(candidate as Record); return entries.every(([, value]) => typeof value === "string") ? Object.fromEntries(entries as ReadonlyArray) : null; }; const readBindingStringArray = ( source: Source, key: string, ): Array | null => { const candidate = source.binding[key]; return Array.isArray(candidate) && candidate.every((value) => typeof value === "string") ? [...candidate] : null; }; const readBindingString = (source: Source, key: string): string => typeof source.binding[key] === "string" ? String(source.binding[key]) : ""; const readBindingTransport = (source: Source): McpTransportValue => { const candidate = source.binding.transport; return typeof candidate === "string" && (candidate === "auto" || candidate === "streamable-http" || candidate === "sse" || candidate === "stdio") ? candidate : ""; }; const buildSyntheticMcpStdioEndpoint = (input: { name?: string | null; endpoint?: string | null; command?: string | null; }): string => { const label = input.name?.trim() || input.endpoint?.trim() || input.command?.trim() || "mcp"; const slug = label .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, ""); return `stdio://local/${slug || "mcp"}`; }; const defaultFormState = (template?: SourceTemplate): SourceFormState => ({ name: template?.name ?? "", kind: template?.kind ?? "openapi", endpoint: template?.endpoint ?? "", namespace: template ? (template.namespace ?? ("service" in template ? googleDiscoveryNamespace(template.service) : namespaceFromUrl(template.endpoint ?? ""))) : "", enabled: true, specUrl: template && "specUrl" in template ? template.specUrl : "", service: template && "service" in template ? template.service : "", version: template && "version" in template ? template.version : "", defaultHeadersText: "", authKind: template?.kind === "google_discovery" ? "oauth2" : "none", authHeaderName: "Authorization", authPrefix: "Bearer ", bearerProviderId: "", bearerHandle: "", oauthAccessProviderId: "", oauthAccessHandle: "", oauthRefreshProviderId: "", oauthRefreshHandle: "", managedAuth: null, ...(template?.kind === "mcp" && template.connectionType === "command" ? defaultMcpStdioTransportFields({ command: template.command ?? "", argsText: stringArrayToEditor(template.args), envText: stringMapToEditor(template.env ?? null), cwd: template.cwd ?? "", }) : defaultMcpRemoteTransportFields( template?.kind === "mcp" ? asMcpRemoteTransportValue(template.transport) : "", )), }); const formStateFromSource = (source: Source): SourceFormState => ({ name: source.name, kind: source.kind, endpoint: source.endpoint, namespace: source.namespace ?? "", enabled: source.enabled, specUrl: readBindingString(source, "specUrl"), service: readBindingString(source, "service"), version: readBindingString(source, "version"), defaultHeadersText: stringMapToEditor( readBindingStringMap(source, "defaultHeaders"), ), authKind: source.auth.kind, authHeaderName: source.auth.kind === "none" || source.auth.kind === "mcp_oauth" ? "Authorization" : source.auth.headerName, authPrefix: source.auth.kind === "none" || source.auth.kind === "mcp_oauth" ? "Bearer " : source.auth.prefix, bearerProviderId: source.auth.kind === "bearer" ? source.auth.token.providerId : "", bearerHandle: source.auth.kind === "bearer" ? source.auth.token.handle : "", oauthAccessProviderId: source.auth.kind === "oauth2" ? source.auth.accessToken.providerId : "", oauthAccessHandle: source.auth.kind === "oauth2" ? source.auth.accessToken.handle : "", oauthRefreshProviderId: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.providerId : "", oauthRefreshHandle: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.handle : "", managedAuth: source.auth.kind === "provider_grant_ref" || source.auth.kind === "mcp_oauth" ? source.auth : null, ...(source.kind === "mcp" && readBindingTransport(source) === "stdio" ? defaultMcpStdioTransportFields({ command: readBindingString(source, "command"), argsText: stringArrayToEditor(readBindingStringArray(source, "args")), envText: stringMapToEditor(readBindingStringMap(source, "env")), cwd: readBindingString(source, "cwd"), }) : defaultMcpRemoteTransportFields( source.kind === "mcp" ? asMcpRemoteTransportValue(readBindingTransport(source) || "auto") : "", )), ...(source.kind === "mcp" && readBindingTransport(source) !== "stdio" ? { queryParamsText: stringMapToEditor( readBindingStringMap(source, "queryParams"), ), headersText: stringMapToEditor(readBindingStringMap(source, "headers")), } : {}), }); const buildAuthPayload = ( state: SourceFormState, ): CreateSourcePayload["auth"] => { if (state.authKind === "none") { return { kind: "none" }; } if ( (state.authKind === "provider_grant_ref" || state.authKind === "mcp_oauth") && state.managedAuth !== null ) { return state.managedAuth; } const headerName = state.authHeaderName.trim() || "Authorization"; const prefix = state.authPrefix; if (state.authKind === "bearer") { const providerId = state.bearerProviderId.trim(); const handle = state.bearerHandle.trim(); if (!providerId || !handle) { throw new Error( "Bearer auth requires a token. Select or create a secret.", ); } return { kind: "bearer", headerName, prefix, token: { providerId, handle, }, }; } const accessProviderId = state.oauthAccessProviderId.trim(); const accessHandle = state.oauthAccessHandle.trim(); if (!accessProviderId || !accessHandle) { throw new Error( "OAuth2 auth requires an access token. Select or create a secret.", ); } const refreshProviderId = trimToNull(state.oauthRefreshProviderId); const refreshHandle = trimToNull(state.oauthRefreshHandle); if ((refreshProviderId === null) !== (refreshHandle === null)) { throw new Error( "OAuth2 refresh token provider ID and handle must be set together.", ); } return { kind: "oauth2", headerName, prefix, accessToken: { providerId: accessProviderId, handle: accessHandle, }, refreshToken: refreshProviderId === null || refreshHandle === null ? null : { providerId: refreshProviderId, handle: refreshHandle, }, }; }; const buildRequestedSourceStatus = ( state: SourceFormState, ): CreateSourcePayload["status"] => { if ( state.kind !== "mcp" && state.kind !== "openapi" && state.kind !== "graphql" ) { return undefined; } return state.enabled ? "connected" : "draft"; }; const buildSourcePayload = (state: SourceFormState): CreateSourcePayload => { const name = state.name.trim(); const isMcpStdio = state.kind === "mcp" && state.transport === "stdio"; const endpoint = state.kind === "mcp" && state.transport === "stdio" ? buildSyntheticMcpStdioEndpoint({ name: state.name, endpoint: state.endpoint, command: state.command, }) : state.endpoint.trim(); if (!name) { throw new Error("Source name is required."); } if (!endpoint) { throw new Error("Source endpoint is required."); } if (isMcpStdio && !state.command.trim()) { throw new Error("MCP stdio transport requires a command."); } const shared = { name, kind: state.kind, endpoint, status: buildRequestedSourceStatus(state), enabled: state.enabled, namespace: trimToNull(state.namespace), auth: isMcpStdio ? { kind: "none" as const } : buildAuthPayload(state), } satisfies Pick< CreateSourcePayload, "name" | "kind" | "endpoint" | "status" | "enabled" | "namespace" | "auth" >; if (state.kind === "mcp") { if (state.transport === "stdio") { return { ...shared, binding: { transport: "stdio", queryParams: null, headers: null, command: state.command.trim(), args: parseJsonStringArray("Args", state.argsText), env: parseJsonStringMap("Environment", state.envText), cwd: trimToNull(state.cwd), }, }; } return { ...shared, binding: { transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), command: null, args: null, env: null, cwd: null, }, }; } if (state.kind === "openapi") { const specUrl = state.specUrl.trim(); if (!specUrl) { throw new Error("OpenAPI sources require a spec URL."); } return { ...shared, binding: { specUrl, defaultHeaders: parseJsonStringMap( "Default headers", state.defaultHeadersText, ), }, }; } if (state.kind === "graphql") { return { ...shared, binding: { defaultHeaders: parseJsonStringMap( "Default headers", state.defaultHeadersText, ), }, }; } if (state.kind === "google_discovery") { const service = state.service.trim(); const version = state.version.trim(); if (!service) { throw new Error("Google Discovery sources require a service."); } if (!version) { throw new Error("Google Discovery sources require a version."); } return { ...shared, binding: { service, version, discoveryUrl: endpoint, defaultHeaders: parseJsonStringMap( "Default headers", state.defaultHeadersText, ), }, }; } return { ...shared, binding: {}, }; }; const buildUpdatePayload = (state: SourceFormState): UpdateSourcePayload => ({ ...buildSourcePayload(state), }); const buildStartSourceOAuthPayload = ( state: SourceFormState, ): StartSourceOAuthPayload => { if (state.kind !== "mcp") { throw new Error("OAuth sign-in is only available for MCP sources."); } if (state.transport === "stdio") { throw new Error("OAuth sign-in is not available for MCP stdio sources."); } const endpoint = state.endpoint.trim(); if (!endpoint) { throw new Error("Source endpoint is required before starting OAuth."); } return { provider: "mcp", name: trimToNull(state.name), endpoint, transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), }; }; export function NewSourcePage() { return ; } export function EditSourcePage(props: { sourceId: string }) { const sources = useSources(); const source = useSource(props.sourceId); const missingSource = (sources.status === "ready" && !sources.data.some((candidate) => candidate.id === props.sourceId)) || isSourceNotFoundLoadable(source); if (missingSource) { return ; } return ( {(loadedSource) => ( )} ); } function SourceEditor(props: { mode: "create" | "edit"; source?: Source }) { const navigate = useNavigate(); const createSource = useCreateSource(); const startSourceOAuth = useStartSourceOAuth(); const updateSource = useUpdateSource(); const removeSource = useRemoveSource(); const removeProviderAuthGrant = useRemoveProviderAuthGrant(); const instanceConfig = useInstanceConfig(); const secrets = useSecrets(); const refreshSecrets = useRefreshSecrets(); const [formState, setFormState] = useState(() => props.source ? formStateFromSource(props.source) : defaultFormState(), ); const [statusBanner, setStatusBanner] = useState( null, ); const [selectedTemplateId, setSelectedTemplateId] = useState( null, ); const [oauthPopupBusy, setOauthPopupBusy] = useState(false); const [expandedOauthSecretRefTarget, setExpandedOauthSecretRefTarget] = useState(null); const isSubmitting = createSource.status === "pending" || updateSource.status === "pending"; const isDeleting = removeSource.status === "pending"; const isRevokingGrant = removeProviderAuthGrant.status === "pending"; const isOAuthSubmitting = startSourceOAuth.status === "pending" || oauthPopupBusy; const oauthSecretRefTarget = formState.authKind === "oauth2" && formState.oauthAccessHandle.trim().length > 0 ? `${formState.oauthAccessProviderId}:${formState.oauthAccessHandle}:${formState.oauthRefreshProviderId}:${formState.oauthRefreshHandle}` : null; const showOauthSecretRefs = oauthSecretRefTarget !== null && expandedOauthSecretRefTarget === oauthSecretRefTarget; const setField = ( key: K, value: SourceFormBase[K], ) => { setFormState((current) => ({ ...current, [key]: value })); }; const setTransport = (transport: McpTransportValue) => { setFormState((current) => ({ ...current, ...setMcpTransportFieldsTransport(current, transport), })); }; const setRemoteTransportField = < K extends Exclude, >( key: K, value: McpRemoteTransportFields[K], ) => { setFormState((current) => current.transport === "stdio" ? current : { ...current, [key]: value }, ); }; const setStdioTransportField = < K extends Exclude, >( key: K, value: McpStdioTransportFields[K], ) => { setFormState((current) => current.transport === "stdio" ? { ...current, [key]: value } : current, ); }; const applyTemplate = (template: SourceTemplate) => { setSelectedTemplateId(template.id); setFormState((current) => ({ ...defaultFormState(template), name: current.name.trim().length > 0 ? current.name : template.name, enabled: current.enabled, })); setStatusBanner({ tone: "info", text: `${template.name} loaded. Add auth if needed, then save.`, }); }; const handleSubmit = async () => { setStatusBanner(null); try { if (props.mode === "create") { const createdSource = await createSource.mutateAsync( buildSourcePayload(formState), ); void navigate({ to: "/sources/$sourceId", params: { sourceId: createdSource.id }, search: { tab: "model" }, }); return; } if (!props.source) { throw new Error("Cannot update a source before it has loaded."); } const updatedSource = await updateSource.mutateAsync({ sourceId: props.source.id, payload: buildUpdatePayload(formState), }); void navigate({ to: "/sources/$sourceId", params: { sourceId: updatedSource.id }, search: { tab: "model" }, }); } catch (error) { setStatusBanner({ tone: "error", text: error instanceof Error ? error.message : "Failed saving source.", }); } }; const handleMcpOAuthConnect = async () => { setStatusBanner(null); try { const result = await startSourceOAuth.mutateAsync( buildStartSourceOAuthPayload(formState), ); setStatusBanner({ tone: "info", text: "Finish OAuth in the popup. Saving will create the source and connect its tools.", }); setOauthPopupBusy(true); const auth = await startSourceOAuthPopup({ authorizationUrl: result.authorizationUrl, sessionId: result.sessionId, }); setOauthPopupBusy(false); refreshSecrets(); setExpandedOauthSecretRefTarget(null); setFormState((current) => ({ ...current, authKind: "oauth2", authHeaderName: auth.headerName, authPrefix: auth.prefix, oauthAccessProviderId: auth.accessToken.providerId, oauthAccessHandle: auth.accessToken.handle, oauthRefreshProviderId: auth.refreshToken?.providerId ?? "", oauthRefreshHandle: auth.refreshToken?.handle ?? "", managedAuth: null, })); setStatusBanner({ tone: "success", text: "OAuth credentials are ready. Save the source to connect and index tools.", }); } catch (error) { setOauthPopupBusy(false); setStatusBanner({ tone: "error", text: error instanceof Error ? error.message : "Failed starting OAuth.", }); } }; const handleRemove = async () => { if (!props.source || isDeleting) { return; } const confirmed = window.confirm( `Remove "${props.source.name}" and its indexed tools?`, ); if (!confirmed) { return; } setStatusBanner(null); try { const result = await removeSource.mutateAsync(props.source.id); if (!result.removed) { throw new Error("Source was not removed."); } void navigate({ to: "/" }); } catch (error) { setStatusBanner({ tone: "error", text: error instanceof Error ? error.message : "Failed removing source.", }); } }; const handleRevokeProviderGrant = async () => { if ( !props.source || isRevokingGrant || formState.managedAuth?.kind !== "provider_grant_ref" ) { return; } const confirmed = window.confirm( `Revoke the shared Google auth for "${props.source.name}"? This disconnects every source using the same shared grant.`, ); if (!confirmed) { return; } setStatusBanner(null); try { const result = await removeProviderAuthGrant.mutateAsync( formState.managedAuth.grantId, ); if (!result.removed) { throw new Error("Shared provider grant was not removed."); } setStatusBanner({ tone: "success", text: "Shared provider grant revoked. Linked sources now require authentication again.", }); } catch (error) { setStatusBanner({ tone: "error", text: error instanceof Error ? error.message : "Failed revoking shared provider grant.", }); } }; const backLink = props.mode === "edit" && props.source ? { to: "/sources/$sourceId" as const, params: { sourceId: props.source.id }, search: { tab: "model" as const }, } : { to: "/" as const }; return (
{/* Back + title */} {props.mode === "edit" ? "Back to source" : "Back"}

{props.mode === "edit" ? "Edit source" : "New source"}

{formState.kind} {formState.enabled ? "enabled" : "disabled"}
{statusBanner && } {/* Templates (create mode) */} {props.mode === "create" && (
{sourceTemplates.map((template) => ( ))}
)} {/* Form */}
setField("name", value)} placeholder="GitHub REST" /> setField("kind", value as Source["kind"]) } options={kindOptions.map((value) => ({ value, label: value, }))} /> {!( formState.kind === "mcp" && formState.transport === "stdio" ) && ( setField("endpoint", value)} placeholder={ formState.kind === "openapi" ? "https://api.github.com" : formState.kind === "graphql" ? "https://api.linear.app/graphql" : formState.kind === "google_discovery" ? "https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest" : "https://mcp.deepwiki.com/mcp" } mono /> )} setField("namespace", value)} placeholder="github" /> setField("enabled", checked)} />
{formState.kind === "mcp" && (
setTransport(value as McpTransportValue)} options={transportOptions.map((value) => ({ value, label: value, }))} /> {formState.transport === "stdio" ? (
setStdioTransportField("command", value) } placeholder="npx" mono /> setStdioTransportField("cwd", value) } placeholder="/path/to/project" mono /> setStdioTransportField("argsText", value) } placeholder={ '[\n "-y",\n "chrome-devtools-mcp@latest"\n]' } /> setStdioTransportField("envText", value) } placeholder={ '{\n "CHROME_PATH": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"\n}' } />
) : (
setRemoteTransportField("queryParamsText", value) } placeholder={'{\n "workspace": "demo"\n}'} /> setRemoteTransportField("headersText", value) } placeholder={'{\n "x-api-key": "..."\n}'} />
)}
)} {formState.kind === "openapi" && (
setField("specUrl", value)} placeholder="https://raw.githubusercontent.com/.../openapi.yaml" mono /> setField("defaultHeadersText", value)} placeholder={'{\n "x-api-version": "2026-03-01"\n}'} />
)} {formState.kind === "graphql" && (
setField("defaultHeadersText", value)} placeholder={'{\n "x-api-version": "2026-03-01"\n}'} />
)} {formState.kind === "google_discovery" && (
setField("service", value)} placeholder="sheets" /> setField("version", value)} placeholder="v4" /> setField("defaultHeadersText", value)} placeholder={'{\n "x-goog-user-project": "my-project"\n}'} />
)}
{formState.kind === "mcp" && formState.transport !== "stdio" && (

MCP OAuth

Opens the server's built-in OAuth flow to authenticate this source.

{formState.authKind === "oauth2" && formState.oauthAccessHandle.trim().length > 0 && (

Token refs attached to this draft

)}
)} {formState.kind === "mcp" && formState.transport === "stdio" ? (
Local MCP stdio sources do not use executor-managed HTTP or OAuth credentials.
) : ( setField("authKind", value as Source["auth"]["kind"]) } disabled={formState.managedAuth !== null} options={authOptions.map((value) => ({ value, label: value, }))} /> )} {formState.managedAuth !== null && !( formState.kind === "mcp" && formState.transport === "stdio" ) && (
{formState.managedAuth.kind === "provider_grant_ref" ? ( ) : ( )}

{formState.managedAuth.kind === "provider_grant_ref" ? "Shared provider grant" : "Managed MCP OAuth"}

{formState.managedAuth.kind === "provider_grant_ref" ? "This source uses a shared Google auth grant. Reconnect from Add Source to change the linked account or scopes." : "Authenticated through a persisted MCP OAuth session. Reconnect the source to refresh or replace the binding."}

{formState.managedAuth.kind === "provider_grant_ref" && props.mode === "edit" && (
)}
)} {formState.authKind !== "none" && formState.managedAuth === null && !( formState.kind === "mcp" && formState.transport === "stdio" ) && ( <> setField("authHeaderName", value)} placeholder="Authorization" /> setField("authPrefix", value)} placeholder="Bearer " /> )} {formState.authKind === "bearer" && formState.managedAuth === null && !( formState.kind === "mcp" && formState.transport === "stdio" ) && ( { setField("bearerProviderId", providerId); setField("bearerHandle", handle); }} /> )} {formState.authKind === "oauth2" && formState.managedAuth === null && !( formState.kind === "mcp" && formState.transport === "stdio" ) && (formState.kind !== "mcp" || formState.oauthAccessHandle.trim().length === 0 || showOauthSecretRefs) && ( <> { setField("oauthAccessProviderId", providerId); setField("oauthAccessHandle", handle); }} /> { setField("oauthRefreshProviderId", providerId); setField("oauthRefreshHandle", handle); }} allowEmpty /> )}
{/* Danger zone (edit mode) */} {props.mode === "edit" && props.source && (
)} {/* Actions */}
); } // --------------------------------------------------------------------------- // Form building blocks // --------------------------------------------------------------------------- function Section(props: { title: string; children: ReactNode; className?: string; }) { return (

{props.title}

{props.children}
); } function Field(props: { label: string; className?: string; children: ReactNode; }) { return ( ); } function TextInput(props: { value: string; onChange: (value: string) => void; placeholder?: string; mono?: boolean; }) { return ( props.onChange(event.target.value)} placeholder={props.placeholder} className={cn( "h-9 w-full rounded-lg border border-input bg-background px-3 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground/35 focus:border-ring focus:ring-1 focus:ring-ring/25", props.mono && "font-mono text-[12px]", )} /> ); } function SelectInput(props: { value: string; onChange: (value: string) => void; options: ReadonlyArray<{ value: string; label: string }>; disabled?: boolean; }) { return ( ); } function CodeEditor(props: { value: string; onChange: (value: string) => void; placeholder?: string; }) { return (