@stigmer/react 0.0.80 → 0.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/environment/index.d.ts +1 -1
- package/environment/index.d.ts.map +1 -1
- package/environment/index.js +1 -1
- package/environment/index.js.map +1 -1
- package/environment/systemEnvVars.d.ts +16 -0
- package/environment/systemEnvVars.d.ts.map +1 -1
- package/environment/systemEnvVars.js +32 -0
- package/environment/systemEnvVars.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/mcp-server/McpServerConfigPanel.d.ts +23 -1
- package/mcp-server/McpServerConfigPanel.d.ts.map +1 -1
- package/mcp-server/McpServerConfigPanel.js +14 -5
- package/mcp-server/McpServerConfigPanel.js.map +1 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +36 -14
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/McpServerPicker.d.ts.map +1 -1
- package/mcp-server/McpServerPicker.js +27 -3
- package/mcp-server/McpServerPicker.js.map +1 -1
- package/mcp-server/OAuthCallbackHandler.d.ts.map +1 -1
- package/mcp-server/OAuthCallbackHandler.js +33 -9
- package/mcp-server/OAuthCallbackHandler.js.map +1 -1
- package/mcp-server/useMcpServerConnect.d.ts +22 -12
- package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerConnect.js +17 -10
- package/mcp-server/useMcpServerConnect.js.map +1 -1
- package/mcp-server/useMcpServerCredentials.d.ts +53 -2
- package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
- package/mcp-server/useMcpServerCredentials.js +37 -6
- package/mcp-server/useMcpServerCredentials.js.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.d.ts +10 -1
- package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.js +60 -11
- package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
- package/package.json +4 -4
- package/src/environment/index.ts +1 -0
- package/src/environment/systemEnvVars.ts +39 -0
- package/src/index.ts +1 -0
- package/src/mcp-server/McpServerConfigPanel.tsx +82 -4
- package/src/mcp-server/McpServerDetailView.tsx +104 -16
- package/src/mcp-server/McpServerPicker.tsx +56 -18
- package/src/mcp-server/OAuthCallbackHandler.tsx +39 -12
- package/src/mcp-server/useMcpServerConnect.ts +33 -14
- package/src/mcp-server/useMcpServerCredentials.ts +68 -6
- package/src/mcp-server/useMcpServerOAuthConnect.ts +63 -15
- package/styles.css +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback, useMemo } from "react";
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
|
|
3
4
|
import { usePersonalEnvironment } from "../environment/usePersonalEnvironment";
|
|
4
5
|
import { diffEnv } from "../environment/diffEnv";
|
|
5
6
|
import { SYSTEM_ENV_VAR_KEYS } from "../environment/systemEnvVars";
|
|
@@ -32,9 +33,31 @@ import { useOAuthGrantStatus } from "./useOAuthGrantStatus";
|
|
|
32
33
|
* ```tsx
|
|
33
34
|
* const creds = useMcpServerCredentials("acme", mcpServer);
|
|
34
35
|
*
|
|
35
|
-
* // OAuth server — sign-in button +
|
|
36
|
+
* // OAuth server — sign-in button + manual override escape hatch
|
|
36
37
|
* if (creds.authMode === "oauth" && !creds.isOAuthConnected) {
|
|
37
|
-
*
|
|
38
|
+
* if (creds.manualOverride) {
|
|
39
|
+
* // User opted to enter the token manually
|
|
40
|
+
* return (
|
|
41
|
+
* <>
|
|
42
|
+
* <EnvVarForm
|
|
43
|
+
* variables={creds.missingVariables}
|
|
44
|
+
* onSubmit={(values) => creds.saveCredentials(values)}
|
|
45
|
+
* isSubmitting={creds.isSaving}
|
|
46
|
+
* />
|
|
47
|
+
* <button onClick={() => creds.setManualOverride(false)}>
|
|
48
|
+
* Sign in with OAuth instead
|
|
49
|
+
* </button>
|
|
50
|
+
* </>
|
|
51
|
+
* );
|
|
52
|
+
* }
|
|
53
|
+
* return (
|
|
54
|
+
* <>
|
|
55
|
+
* <button onClick={startOAuth}>Sign in</button>
|
|
56
|
+
* <button onClick={() => creds.setManualOverride(true)}>
|
|
57
|
+
* Enter token manually
|
|
58
|
+
* </button>
|
|
59
|
+
* </>
|
|
60
|
+
* );
|
|
38
61
|
* }
|
|
39
62
|
*
|
|
40
63
|
* // Manual vars still needed (mixed mode or manual-only)
|
|
@@ -52,10 +75,14 @@ import { useOAuthGrantStatus } from "./useOAuthGrantStatus";
|
|
|
52
75
|
*/
|
|
53
76
|
export function useMcpServerCredentials(org, mcpServer) {
|
|
54
77
|
const personalEnv = usePersonalEnvironment(org);
|
|
78
|
+
const [manualOverride, setManualOverride] = useState(false);
|
|
55
79
|
const auth = mcpServer?.spec?.auth;
|
|
56
80
|
const authMode = auth ? "oauth" : "manual";
|
|
57
81
|
const oauthTargetEnvVar = auth?.targetEnvVar || null;
|
|
58
82
|
const tokenLifetimeHint = auth?.tokenLifetimeHint || null;
|
|
83
|
+
const isVendorApprovalPending = authMode === "oauth" &&
|
|
84
|
+
auth?.vendorApprovalStatus === VendorApprovalStatus.PENDING;
|
|
85
|
+
const vendorApprovalDocsUrl = auth?.vendorApprovalDocsUrl || null;
|
|
59
86
|
const grantStatus = useOAuthGrantStatus(authMode === "oauth" ? (mcpServer?.metadata?.id ?? null) : null, authMode === "oauth" ? org : null);
|
|
60
87
|
const isOAuthConnected = authMode === "oauth" && grantStatus.connected;
|
|
61
88
|
const existingKeys = useMemo(() => new Set(Object.keys(personalEnv.environment?.spec?.data ?? {})), [personalEnv.environment]);
|
|
@@ -69,14 +96,14 @@ export function useMcpServerCredentials(org, mcpServer) {
|
|
|
69
96
|
}, [mcpServer, existingKeys]);
|
|
70
97
|
const requiredMissing = useMemo(() => allMissingVariables.filter((v) => !v.optional), [allMissingVariables]);
|
|
71
98
|
const missingVariables = useMemo(() => {
|
|
72
|
-
if (!oauthTargetEnvVar)
|
|
99
|
+
if (!oauthTargetEnvVar || manualOverride)
|
|
73
100
|
return requiredMissing;
|
|
74
101
|
return requiredMissing.filter((v) => v.key !== oauthTargetEnvVar);
|
|
75
|
-
}, [requiredMissing, oauthTargetEnvVar]);
|
|
102
|
+
}, [requiredMissing, oauthTargetEnvVar, manualOverride]);
|
|
76
103
|
const isReady = !personalEnv.isLoading &&
|
|
77
104
|
!grantStatus.isLoading &&
|
|
78
105
|
missingVariables.length === 0 &&
|
|
79
|
-
(authMode === "manual" || isOAuthConnected);
|
|
106
|
+
(authMode === "manual" || manualOverride || isOAuthConnected);
|
|
80
107
|
const saveCredentials = useCallback(async (values) => {
|
|
81
108
|
await personalEnv.getOrCreate();
|
|
82
109
|
await personalEnv.addVariables(values);
|
|
@@ -91,6 +118,8 @@ export function useMcpServerCredentials(org, mcpServer) {
|
|
|
91
118
|
isOAuthConnected,
|
|
92
119
|
accessTokenExpiresAt: grantStatus.accessTokenExpiresAt,
|
|
93
120
|
tokenLifetimeHint,
|
|
121
|
+
isVendorApprovalPending,
|
|
122
|
+
vendorApprovalDocsUrl,
|
|
94
123
|
missingVariables,
|
|
95
124
|
isReady,
|
|
96
125
|
isLoading: personalEnv.isLoading || grantStatus.isLoading,
|
|
@@ -98,6 +127,8 @@ export function useMcpServerCredentials(org, mcpServer) {
|
|
|
98
127
|
saveCredentials,
|
|
99
128
|
isSaving: personalEnv.isMutating,
|
|
100
129
|
refetch,
|
|
130
|
+
manualOverride,
|
|
131
|
+
setManualOverride,
|
|
101
132
|
};
|
|
102
133
|
}
|
|
103
134
|
//# sourceMappingURL=useMcpServerCredentials.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMcpServerCredentials.js","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerCredentials.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useMcpServerCredentials.js","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerCredentials.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oDAAoD,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAmH5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAkB,EAClB,SAA2B;IAE3B,MAAM,WAAW,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5D,MAAM,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC;IACnC,MAAM,QAAQ,GAAsB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9D,MAAM,iBAAiB,GAAG,IAAI,EAAE,YAAY,IAAI,IAAI,CAAC;IACrD,MAAM,iBAAiB,GAAG,IAAI,EAAE,iBAAiB,IAAI,IAAI,CAAC;IAE1D,MAAM,uBAAuB,GAC3B,QAAQ,KAAK,OAAO;QACpB,IAAI,EAAE,oBAAoB,KAAK,oBAAoB,CAAC,OAAO,CAAC;IAC9D,MAAM,qBAAqB,GAAG,IAAI,EAAE,qBAAqB,IAAI,IAAI,CAAC;IAElE,MAAM,WAAW,GAAG,mBAAmB,CACrC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAC/D,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAClC,CAAC;IAEF,MAAM,gBAAgB,GAAG,QAAQ,KAAK,OAAO,IAAI,WAAW,CAAC,SAAS,CAAC;IAEvE,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,EACrE,CAAC,WAAW,CAAC,WAAW,CAAC,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,EAAE;QACvC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAC1B,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;QAC5C,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAE7E,OAAO,OAAO,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC,MAAM,CAClD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CACvC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACpD,CAAC,mBAAmB,CAAC,CACtB,CAAC;IAEF,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,EAAE;QACpC,IAAI,CAAC,iBAAiB,IAAI,cAAc;YAAE,OAAO,eAAe,CAAC;QACjE,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,iBAAiB,CAAC,CAAC;IACpE,CAAC,EAAE,CAAC,eAAe,EAAE,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC;IAEzD,MAAM,OAAO,GACX,CAAC,WAAW,CAAC,SAAS;QACtB,CAAC,WAAW,CAAC,SAAS;QACtB,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAC7B,CAAC,QAAQ,KAAK,QAAQ,IAAI,cAAc,IAAI,gBAAgB,CAAC,CAAC;IAEhE,MAAM,eAAe,GAAG,WAAW,CACjC,KAAK,EAAE,MAAmC,EAAiB,EAAE;QAC3D,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,WAAW,CAAC,OAAO,EAAE,CAAC;QACtB,WAAW,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/B,OAAO;QACL,QAAQ;QACR,iBAAiB;QACjB,gBAAgB;QAChB,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;QACtD,iBAAiB;QACjB,uBAAuB;QACvB,qBAAqB;QACrB,gBAAgB;QAChB,OAAO;QACP,SAAS,EAAE,WAAW,CAAC,SAAS,IAAI,WAAW,CAAC,SAAS;QACzD,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,KAAK;QAC7C,eAAe;QACf,QAAQ,EAAE,WAAW,CAAC,UAAU;QAChC,OAAO;QACP,cAAc;QACd,iBAAiB;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -5,6 +5,13 @@ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/
|
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
7
|
export declare const OAUTH_CALLBACK_MESSAGE_TYPE = "stigmer:oauth:callback";
|
|
8
|
+
/**
|
|
9
|
+
* BroadcastChannel name used as a fallback when `window.opener` is severed
|
|
10
|
+
* by `Cross-Origin-Opener-Policy` headers on the OAuth provider.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare const OAUTH_BROADCAST_CHANNEL = "stigmer:oauth:broadcast";
|
|
8
15
|
/**
|
|
9
16
|
* Shape of the `postMessage` payload sent from the OAuth callback popup.
|
|
10
17
|
*
|
|
@@ -33,9 +40,11 @@ export interface UseMcpServerOAuthConnectReturn {
|
|
|
33
40
|
*
|
|
34
41
|
* @param mcpServerId - System-generated ID (metadata.id) of the MCP server.
|
|
35
42
|
* @param org - Organization context for token storage (caller's active org).
|
|
43
|
+
* @param declaredEnvKeys - Keys from the server's `spec.env` declaration.
|
|
44
|
+
* System vars are only injected when declared here.
|
|
36
45
|
* @returns The updated McpServer after tool discovery completes.
|
|
37
46
|
*/
|
|
38
|
-
readonly startOAuth: (mcpServerId: string, org: string) => Promise<McpServer>;
|
|
47
|
+
readonly startOAuth: (mcpServerId: string, org: string, declaredEnvKeys?: readonly string[]) => Promise<McpServer>;
|
|
39
48
|
/** `true` while any phase of the OAuth flow is in progress. */
|
|
40
49
|
readonly isInProgress: boolean;
|
|
41
50
|
/** Current phase of the OAuth flow. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMcpServerOAuthConnect.d.ts","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerOAuthConnect.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wDAAwD,CAAC;AAUxF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,OAAO,2BAA2B,CAAC;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,YAAY,GACZ,mBAAmB,GACnB,YAAY,GACZ,YAAY,GACZ,MAAM,CAAC;AAEX,wDAAwD;AACxD,MAAM,WAAW,8BAA8B;IAC7C
|
|
1
|
+
{"version":3,"file":"useMcpServerOAuthConnect.d.ts","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerOAuthConnect.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wDAAwD,CAAC;AAUxF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,OAAO,2BAA2B,CAAC;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,YAAY,GACZ,mBAAmB,GACnB,YAAY,GACZ,YAAY,GACZ,MAAM,CAAC;AAEX,wDAAwD;AACxD,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACnH,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;CACjC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,wBAAwB,IAAI,8BAA8B,CAsHzE"}
|
|
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { create } from "@bufbuild/protobuf";
|
|
4
4
|
import { InitiateOAuthConnectInputSchema, CompleteOAuthConnectInputSchema, ConnectInputSchema, } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
5
5
|
import { useStigmer } from "../hooks";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveDeclaredSystemEnvVars } from "../environment/systemEnvVars";
|
|
7
7
|
import { toError } from "../internal/toError";
|
|
8
8
|
/**
|
|
9
9
|
* Message type posted by {@link OAuthCallbackHandler} to the opener window.
|
|
@@ -11,6 +11,13 @@ import { toError } from "../internal/toError";
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
export const OAUTH_CALLBACK_MESSAGE_TYPE = "stigmer:oauth:callback";
|
|
14
|
+
/**
|
|
15
|
+
* BroadcastChannel name used as a fallback when `window.opener` is severed
|
|
16
|
+
* by `Cross-Origin-Opener-Policy` headers on the OAuth provider.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export const OAUTH_BROADCAST_CHANNEL = "stigmer:oauth:broadcast";
|
|
14
21
|
const POPUP_WIDTH = 600;
|
|
15
22
|
const POPUP_HEIGHT = 700;
|
|
16
23
|
const POPUP_CALLBACK_TIMEOUT_MS = 120_000;
|
|
@@ -62,7 +69,7 @@ export function useMcpServerOAuthConnect() {
|
|
|
62
69
|
setPhase("idle");
|
|
63
70
|
setError(null);
|
|
64
71
|
}, []);
|
|
65
|
-
const startOAuth = useCallback(async (mcpServerId, org) => {
|
|
72
|
+
const startOAuth = useCallback(async (mcpServerId, org, declaredEnvKeys) => {
|
|
66
73
|
setPhase("initiating");
|
|
67
74
|
setError(null);
|
|
68
75
|
cleanupRef.current?.();
|
|
@@ -91,7 +98,9 @@ export function useMcpServerOAuthConnect() {
|
|
|
91
98
|
state,
|
|
92
99
|
}));
|
|
93
100
|
setPhase("connecting");
|
|
94
|
-
const systemEnv =
|
|
101
|
+
const systemEnv = declaredEnvKeys
|
|
102
|
+
? await resolveDeclaredSystemEnvVars(stigmer, declaredEnvKeys)
|
|
103
|
+
: {};
|
|
95
104
|
const runtimeEnvMap = {};
|
|
96
105
|
for (const [key, envInput] of Object.entries(systemEnv)) {
|
|
97
106
|
runtimeEnvMap[key] = {
|
|
@@ -99,10 +108,14 @@ export function useMcpServerOAuthConnect() {
|
|
|
99
108
|
isSecret: envInput.isSecret ?? false,
|
|
100
109
|
};
|
|
101
110
|
}
|
|
102
|
-
const
|
|
111
|
+
const input = create(ConnectInputSchema, {
|
|
103
112
|
mcpServerId,
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
org,
|
|
114
|
+
...(Object.keys(runtimeEnvMap).length > 0
|
|
115
|
+
? { runtimeEnv: runtimeEnvMap }
|
|
116
|
+
: {}),
|
|
117
|
+
});
|
|
118
|
+
const server = await stigmer.mcpServer.connect(input);
|
|
106
119
|
setPhase("done");
|
|
107
120
|
return server;
|
|
108
121
|
}
|
|
@@ -129,17 +142,29 @@ export function useMcpServerOAuthConnect() {
|
|
|
129
142
|
// ---------------------------------------------------------------------------
|
|
130
143
|
// Popup callback listener
|
|
131
144
|
// ---------------------------------------------------------------------------
|
|
145
|
+
/**
|
|
146
|
+
* Grace period (ms) after `popup.closed` is first detected before treating
|
|
147
|
+
* it as a user-initiated close. COOP providers sever the opener reference
|
|
148
|
+
* immediately, making `popup.closed` appear `true` while the popup is still
|
|
149
|
+
* active. The grace period lets the BroadcastChannel callback arrive.
|
|
150
|
+
*/
|
|
151
|
+
const POPUP_CLOSED_GRACE_MS = 5_000;
|
|
132
152
|
function waitForOAuthCallback(popup, expectedState, onDispose) {
|
|
133
153
|
return new Promise((resolve, reject) => {
|
|
134
154
|
let settled = false;
|
|
135
155
|
let timeoutId;
|
|
136
156
|
let pollId;
|
|
157
|
+
let bc = null;
|
|
137
158
|
function cleanup() {
|
|
138
159
|
if (timeoutId)
|
|
139
160
|
clearTimeout(timeoutId);
|
|
140
161
|
if (pollId)
|
|
141
162
|
clearInterval(pollId);
|
|
142
163
|
window.removeEventListener("message", onMessage);
|
|
164
|
+
try {
|
|
165
|
+
bc?.close();
|
|
166
|
+
}
|
|
167
|
+
catch { /* ignore */ }
|
|
143
168
|
}
|
|
144
169
|
function settle(outcome) {
|
|
145
170
|
if (settled)
|
|
@@ -157,10 +182,7 @@ function waitForOAuthCallback(popup, expectedState, onDispose) {
|
|
|
157
182
|
settle(new Error("OAuth flow was cancelled."));
|
|
158
183
|
closePopup(popup);
|
|
159
184
|
});
|
|
160
|
-
function
|
|
161
|
-
if (event.origin !== window.location.origin)
|
|
162
|
-
return;
|
|
163
|
-
const data = event.data;
|
|
185
|
+
function validateAndSettle(data) {
|
|
164
186
|
if (data?.type !== OAUTH_CALLBACK_MESSAGE_TYPE)
|
|
165
187
|
return;
|
|
166
188
|
if (data.state !== expectedState) {
|
|
@@ -174,16 +196,43 @@ function waitForOAuthCallback(popup, expectedState, onDispose) {
|
|
|
174
196
|
}
|
|
175
197
|
settle({ code: data.code, state: data.state });
|
|
176
198
|
}
|
|
199
|
+
function onMessage(event) {
|
|
200
|
+
if (event.origin !== window.location.origin)
|
|
201
|
+
return;
|
|
202
|
+
validateAndSettle(event.data);
|
|
203
|
+
}
|
|
177
204
|
window.addEventListener("message", onMessage);
|
|
205
|
+
// BroadcastChannel — works even when COOP severs window.opener.
|
|
206
|
+
try {
|
|
207
|
+
bc = new BroadcastChannel(OAUTH_BROADCAST_CHANNEL);
|
|
208
|
+
bc.onmessage = (event) => {
|
|
209
|
+
validateAndSettle(event.data);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// BroadcastChannel unsupported — rely on postMessage only.
|
|
214
|
+
}
|
|
178
215
|
timeoutId = setTimeout(() => {
|
|
179
216
|
settle(new Error("OAuth authentication timed out. Ensure your callback page " +
|
|
180
217
|
"renders <OAuthCallbackHandler /> from @stigmer/react at " +
|
|
181
218
|
"the URL configured as your OAuth redirect URI."));
|
|
182
219
|
closePopup(popup);
|
|
183
220
|
}, POPUP_CALLBACK_TIMEOUT_MS);
|
|
221
|
+
// COOP providers make popup.closed appear true immediately after
|
|
222
|
+
// cross-origin navigation. Wait a grace period before treating it
|
|
223
|
+
// as a real user-initiated close.
|
|
224
|
+
let popupClosedAt = null;
|
|
184
225
|
pollId = setInterval(() => {
|
|
185
226
|
if (popup.closed) {
|
|
186
|
-
|
|
227
|
+
if (popupClosedAt === null) {
|
|
228
|
+
popupClosedAt = Date.now();
|
|
229
|
+
}
|
|
230
|
+
else if (Date.now() - popupClosedAt > POPUP_CLOSED_GRACE_MS) {
|
|
231
|
+
settle(new Error("The authentication window was closed before completing sign-in."));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
popupClosedAt = null;
|
|
187
236
|
}
|
|
188
237
|
}, 500);
|
|
189
238
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMcpServerOAuthConnect.js","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerOAuthConnect.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,EAC/B,kBAAkB,GACnB,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useMcpServerOAuthConnect.js","sourceRoot":"","sources":["../../src/mcp-server/useMcpServerOAuthConnect.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.82",
|
|
4
4
|
"description": "React provider and client hook for the Stigmer platform SDK",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@stigmer/theme": "0.0.
|
|
38
|
+
"@stigmer/theme": "0.0.82",
|
|
39
39
|
"react-markdown": "^10.1.0",
|
|
40
40
|
"remark-gfm": "^4.0.1",
|
|
41
41
|
"yaml": "^2.8.2"
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@base-ui/react": "^1.0.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.0.0",
|
|
46
|
-
"@stigmer/protos": "0.0.
|
|
47
|
-
"@stigmer/sdk": "0.0.
|
|
46
|
+
"@stigmer/protos": "0.0.82",
|
|
47
|
+
"@stigmer/sdk": "0.0.82",
|
|
48
48
|
"react": "^19.0.0",
|
|
49
49
|
"react-dom": "^19.0.0"
|
|
50
50
|
}
|
package/src/environment/index.ts
CHANGED
|
@@ -102,3 +102,42 @@ export async function resolveSystemEnvVarValues(
|
|
|
102
102
|
const credential = await stigmer.getAuthCredential();
|
|
103
103
|
return buildSystemEnvVars(stigmer.baseUrl, credential);
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve only the system env vars that the target resource actually
|
|
108
|
+
* declares in its environment specification.
|
|
109
|
+
*
|
|
110
|
+
* System vars (`STIGMER_SERVER_ADDRESS`, `STIGMER_API_KEY`) should
|
|
111
|
+
* only be injected when the resource needs them — blindly injecting
|
|
112
|
+
* them causes `runtime_env` to be non-empty on the wire, which
|
|
113
|
+
* changes the backend's missing-credential tolerance semantics.
|
|
114
|
+
*
|
|
115
|
+
* @param stigmer - Live Stigmer client for credential resolution.
|
|
116
|
+
* @param declaredEnvKeys - The set of env var keys the target
|
|
117
|
+
* resource declares (e.g., `Object.keys(mcpServer.spec.env)`).
|
|
118
|
+
* Only system vars whose keys appear here are included.
|
|
119
|
+
* @returns Filtered system env vars (may be empty).
|
|
120
|
+
*/
|
|
121
|
+
export async function resolveDeclaredSystemEnvVars(
|
|
122
|
+
stigmer: Stigmer,
|
|
123
|
+
declaredEnvKeys: ReadonlySet<string> | readonly string[],
|
|
124
|
+
): Promise<Record<string, EnvVarInput>> {
|
|
125
|
+
const keys =
|
|
126
|
+
declaredEnvKeys instanceof Set
|
|
127
|
+
? declaredEnvKeys
|
|
128
|
+
: new Set(declaredEnvKeys);
|
|
129
|
+
|
|
130
|
+
const hasDeclared = [...SYSTEM_ENV_VAR_KEYS].some((k) => keys.has(k));
|
|
131
|
+
if (!hasDeclared) {
|
|
132
|
+
return {};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const all = await resolveSystemEnvVarValues(stigmer);
|
|
136
|
+
const filtered: Record<string, EnvVarInput> = {};
|
|
137
|
+
for (const [key, value] of Object.entries(all)) {
|
|
138
|
+
if (keys.has(key)) {
|
|
139
|
+
filtered[key] = value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return filtered;
|
|
143
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -76,6 +76,16 @@ export interface McpServerOAuthSignInProps {
|
|
|
76
76
|
readonly error: Error | null;
|
|
77
77
|
/** Clear the OAuth error state. */
|
|
78
78
|
readonly onClearError: () => void;
|
|
79
|
+
/**
|
|
80
|
+
* `true` when the platform's OAuth app is pending vendor approval.
|
|
81
|
+
* Disables the sign-in button and shows an informational message.
|
|
82
|
+
*/
|
|
83
|
+
readonly isVendorApprovalPending?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Documentation URL for bringing your own OAuth token.
|
|
86
|
+
* Shown as a help link when `isVendorApprovalPending` is `true`.
|
|
87
|
+
*/
|
|
88
|
+
readonly vendorApprovalDocsUrl?: string | null;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
// ---------------------------------------------------------------------------
|
|
@@ -113,6 +123,18 @@ export interface McpServerConfigPanelProps {
|
|
|
113
123
|
readonly onEnabledToolsChange: (enabledTools: string[]) => void;
|
|
114
124
|
/** Called when the user clicks "Back" to return to the picker list. */
|
|
115
125
|
readonly onBack: () => void;
|
|
126
|
+
/**
|
|
127
|
+
* When provided, a "Enter token manually" link is shown below the
|
|
128
|
+
* OAuth sign-in section. Clicking it switches the panel to manual
|
|
129
|
+
* token entry mode — the caller is responsible for updating the
|
|
130
|
+
* `credentials` and `oauthSignIn` props accordingly.
|
|
131
|
+
*/
|
|
132
|
+
readonly onSwitchToManual?: () => void;
|
|
133
|
+
/**
|
|
134
|
+
* When provided, a "Sign in with OAuth instead" link is shown near
|
|
135
|
+
* the credentials form. Clicking it reverts to the OAuth flow.
|
|
136
|
+
*/
|
|
137
|
+
readonly onSwitchToOAuth?: () => void;
|
|
116
138
|
/** Error to display inline (e.g., from credential submission failure). */
|
|
117
139
|
readonly error?: Error | null;
|
|
118
140
|
/** Disables all interaction. */
|
|
@@ -179,6 +201,8 @@ export function McpServerConfigPanel({
|
|
|
179
201
|
enabledTools,
|
|
180
202
|
onEnabledToolsChange,
|
|
181
203
|
onBack,
|
|
204
|
+
onSwitchToManual,
|
|
205
|
+
onSwitchToOAuth,
|
|
182
206
|
error,
|
|
183
207
|
disabled,
|
|
184
208
|
className,
|
|
@@ -257,9 +281,23 @@ export function McpServerConfigPanel({
|
|
|
257
281
|
onSignIn={oauthSignIn.onSignIn}
|
|
258
282
|
error={oauthSignIn.error}
|
|
259
283
|
onClearError={oauthSignIn.onClearError}
|
|
284
|
+
isVendorApprovalPending={oauthSignIn.isVendorApprovalPending}
|
|
285
|
+
vendorApprovalDocsUrl={oauthSignIn.vendorApprovalDocsUrl}
|
|
286
|
+
onSwitchToManual={onSwitchToManual}
|
|
260
287
|
/>
|
|
261
288
|
)}
|
|
262
289
|
|
|
290
|
+
{/* Switch back to OAuth — shown in manual override mode */}
|
|
291
|
+
{!oauthSignIn && onSwitchToOAuth && (
|
|
292
|
+
<button
|
|
293
|
+
type="button"
|
|
294
|
+
onClick={onSwitchToOAuth}
|
|
295
|
+
className="text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground"
|
|
296
|
+
>
|
|
297
|
+
Sign in with OAuth instead
|
|
298
|
+
</button>
|
|
299
|
+
)}
|
|
300
|
+
|
|
263
301
|
{/* Credentials form — only when credentials prop is provided */}
|
|
264
302
|
{credentials && (
|
|
265
303
|
<EnvVarForm
|
|
@@ -308,6 +346,9 @@ function InlineOAuthSignIn({
|
|
|
308
346
|
onSignIn,
|
|
309
347
|
error,
|
|
310
348
|
onClearError,
|
|
349
|
+
isVendorApprovalPending,
|
|
350
|
+
vendorApprovalDocsUrl,
|
|
351
|
+
onSwitchToManual,
|
|
311
352
|
}: {
|
|
312
353
|
readonly serverName: string;
|
|
313
354
|
readonly isConnected: boolean;
|
|
@@ -315,6 +356,9 @@ function InlineOAuthSignIn({
|
|
|
315
356
|
readonly onSignIn: () => void;
|
|
316
357
|
readonly error: Error | null;
|
|
317
358
|
readonly onClearError: () => void;
|
|
359
|
+
readonly isVendorApprovalPending?: boolean;
|
|
360
|
+
readonly vendorApprovalDocsUrl?: string | null;
|
|
361
|
+
readonly onSwitchToManual?: () => void;
|
|
318
362
|
}) {
|
|
319
363
|
const isBusy =
|
|
320
364
|
phase === "initiating" ||
|
|
@@ -322,28 +366,38 @@ function InlineOAuthSignIn({
|
|
|
322
366
|
phase === "completing" ||
|
|
323
367
|
phase === "connecting";
|
|
324
368
|
|
|
369
|
+
const signInDisabled = isBusy || !!isVendorApprovalPending;
|
|
370
|
+
|
|
325
371
|
return (
|
|
326
372
|
<div className="space-y-1.5">
|
|
327
373
|
<div className="flex items-center justify-between">
|
|
328
374
|
<span
|
|
329
375
|
className={cn(
|
|
330
376
|
"inline-flex items-center gap-1 text-[0.65rem] font-medium",
|
|
331
|
-
isConnected
|
|
377
|
+
isConnected
|
|
378
|
+
? "text-success"
|
|
379
|
+
: isVendorApprovalPending
|
|
380
|
+
? "text-amber-600 dark:text-amber-400"
|
|
381
|
+
: "text-muted-foreground",
|
|
332
382
|
)}
|
|
333
383
|
>
|
|
334
384
|
<span
|
|
335
385
|
className={cn(
|
|
336
386
|
"size-1.5 rounded-full",
|
|
337
|
-
isConnected
|
|
387
|
+
isConnected
|
|
388
|
+
? "bg-success"
|
|
389
|
+
: isVendorApprovalPending
|
|
390
|
+
? "bg-amber-500"
|
|
391
|
+
: "bg-muted-foreground",
|
|
338
392
|
)}
|
|
339
393
|
aria-hidden="true"
|
|
340
394
|
/>
|
|
341
|
-
{isConnected ? "Signed in" : "Sign-in required"}
|
|
395
|
+
{isConnected ? "Signed in" : isVendorApprovalPending ? "Pending approval" : "Sign-in required"}
|
|
342
396
|
</span>
|
|
343
397
|
<button
|
|
344
398
|
type="button"
|
|
345
399
|
onClick={onSignIn}
|
|
346
|
-
disabled={
|
|
400
|
+
disabled={signInDisabled}
|
|
347
401
|
className={cn(
|
|
348
402
|
"inline-flex items-center gap-1 rounded px-2 py-0.5 text-[0.65rem] font-medium",
|
|
349
403
|
isConnected
|
|
@@ -361,6 +415,21 @@ function InlineOAuthSignIn({
|
|
|
361
415
|
)}
|
|
362
416
|
</button>
|
|
363
417
|
</div>
|
|
418
|
+
{isVendorApprovalPending && !isConnected && (
|
|
419
|
+
<div className="text-[0.65rem] text-amber-700 dark:text-amber-300">
|
|
420
|
+
<p>OAuth sign-in is pending vendor approval.</p>
|
|
421
|
+
{vendorApprovalDocsUrl && (
|
|
422
|
+
<a
|
|
423
|
+
href={vendorApprovalDocsUrl}
|
|
424
|
+
target="_blank"
|
|
425
|
+
rel="noopener noreferrer"
|
|
426
|
+
className="underline decoration-amber-600/40 underline-offset-2 hover:decoration-amber-600 dark:decoration-amber-400/40 dark:hover:decoration-amber-400"
|
|
427
|
+
>
|
|
428
|
+
Learn how to bring your own token
|
|
429
|
+
</a>
|
|
430
|
+
)}
|
|
431
|
+
</div>
|
|
432
|
+
)}
|
|
364
433
|
{error && (
|
|
365
434
|
<div className="flex items-start gap-1.5 text-[0.65rem] text-destructive">
|
|
366
435
|
<span className="flex-1">{error.message}</span>
|
|
@@ -373,6 +442,15 @@ function InlineOAuthSignIn({
|
|
|
373
442
|
</button>
|
|
374
443
|
</div>
|
|
375
444
|
)}
|
|
445
|
+
{onSwitchToManual && !isConnected && !isBusy && (
|
|
446
|
+
<button
|
|
447
|
+
type="button"
|
|
448
|
+
onClick={onSwitchToManual}
|
|
449
|
+
className="text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground"
|
|
450
|
+
>
|
|
451
|
+
Enter token manually
|
|
452
|
+
</button>
|
|
453
|
+
)}
|
|
376
454
|
</div>
|
|
377
455
|
);
|
|
378
456
|
}
|