93 lines · 4.1 KB · TypeScript
RawDownload
import { useAtomSet, useAtomValue } from "@effect/atom-react";import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; import { ScopeId } from "@executor-js/sdk/core";import { useScope, useUserScope } from "@executor-js/react/api/scope-context";import { connectionWriteKeys, sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";import { connectionsAtom } from "@executor-js/react/api/atoms";import { SourceOAuthSignInButton } from "@executor-js/react/plugins/oauth-sign-in";import { slugifyNamespace } from "@executor-js/react/plugins/source-identity";import { secretBackedValuesFromConfiguredCredentialBindings } from "@executor-js/react/plugins/credential-bindings"; import { mcpSourceAtom, mcpSourceBindingsAtom, setMcpSourceBinding } from "./atoms";import type { McpStoredSourceSchemaType } from "../sdk/stored-source";import { McpSourceBindingInput } from "../sdk/types"; // ---------------------------------------------------------------------------// McpSignInButton — top-bar action on the source detail page.//// Reads the source's stored endpoint + oauth2 slot, re-runs the DCR /// authorization-code flow against a stable `mcp-oauth2-${namespace}`// connection id, and on success writes the user's credential binding.// --------------------------------------------------------------------------- export default function McpSignInButton(props: { sourceId: string }) {  const scopeId = useScope();  const userScopeId = useUserScope();  const sourceResult = useAtomValue(    mcpSourceAtom(scopeId, props.sourceId),  ) as AsyncResult.AsyncResult<McpStoredSourceSchemaType | null, unknown>;  const source =    AsyncResult.isSuccess(sourceResult) && sourceResult.value ? sourceResult.value : null;  const sourceScope = source ? ScopeId.make(source.scope) : scopeId;  const bindingsResult = useAtomValue(    mcpSourceBindingsAtom(userScopeId, props.sourceId, sourceScope),  );  const connectionsResult = useAtomValue(connectionsAtom(userScopeId));  const setBinding = useAtomSet(setMcpSourceBinding, { mode: "promise" });   const remote = source && source.config.transport === "remote" ? source.config : null;  const oauth2 = remote && remote.auth.kind === "oauth2" ? remote.auth : null;  const connections = AsyncResult.isSuccess(connectionsResult)    ? (connectionsResult.value as readonly { readonly id: string }[])    : null;  const bindings = AsyncResult.isSuccess(bindingsResult) ? bindingsResult.value : null;  const connectionBinding = bindings?.find(    (binding) => binding.slot === oauth2?.connectionSlot && binding.value.kind === "connection",  );  const connectionId =    connectionBinding?.value.kind === "connection" ? connectionBinding.value.connectionId : null;  const isConnected =    oauth2 !== null &&    connections !== null &&    connectionId !== null &&    connections.some((c) => c.id === connectionId);   if (!remote || !oauth2 || !source) return null;  const namespaceSlug = slugifyNamespace(source.namespace) || "mcp";   return (    <SourceOAuthSignInButton      popupName="mcp-oauth"      pluginId="mcp"      namespace={namespaceSlug}      fallbackNamespace="mcp"      endpoint={remote.endpoint}      tokenScope={userScopeId}      connectionId={connectionId}      sourceLabel={`${source.name.trim() || source.namespace || "MCP"} OAuth`}      headers={secretBackedValuesFromConfiguredCredentialBindings(remote.headers, bindings ?? [])}      queryParams={secretBackedValuesFromConfiguredCredentialBindings(        remote.queryParams,        bindings ?? [],      )}      isConnected={isConnected}      detectPopupClosed={false}      onConnected={async (nextConnectionId) => {        await setBinding({          params: { scopeId: userScopeId },          payload: McpSourceBindingInput.make({            sourceId: props.sourceId,            sourceScope,            scope: userScopeId,            slot: oauth2.connectionSlot,            value: { kind: "connection", connectionId: nextConnectionId },          }),          reactivityKeys: [...sourceWriteKeys, ...connectionWriteKeys],        });      }}      reconnectingLabel="Reconnecting…"      signingInLabel="Signing in…"    />  );}