@agent-native/core 0.206.0-nightly-20261009153146 → 0.206.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/action.d.ts +7 -1
  2. package/dist/client/agent-chat/index.d.ts +1 -1
  3. package/dist/client/agent-chat/index.js +1 -1
  4. package/dist/client/embed-auth.d.ts +2 -0
  5. package/dist/client/embed-auth.js +160 -12
  6. package/dist/client/host/index.d.ts +1 -1
  7. package/dist/client/host/index.js +1 -1
  8. package/dist/client/mcp-app-host.d.ts +1 -0
  9. package/dist/client/mcp-app-host.js +4 -1
  10. package/dist/collab/routes.d.ts +1 -1
  11. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  12. package/dist/mcp/build-server.d.ts +15 -0
  13. package/dist/mcp/build-server.js +307 -91
  14. package/dist/mcp/connect-route.js +1 -0
  15. package/dist/mcp/embed-app.js +291 -31
  16. package/dist/mcp/oauth-route.js +3 -0
  17. package/dist/mcp/oauth-store.d.ts +2 -1
  18. package/dist/mcp/oauth-store.js +5 -6
  19. package/dist/mcp/oauth-token.d.ts +5 -0
  20. package/dist/mcp/oauth-token.js +17 -0
  21. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  22. package/dist/mcp/server.d.ts +2 -2
  23. package/dist/mcp/server.js +2 -2
  24. package/dist/observability/routes.d.ts +5 -5
  25. package/dist/org/handlers.d.ts +1 -1
  26. package/dist/org/workspace-app-access-request.d.ts +8 -0
  27. package/dist/org/workspace-app-access-request.js +20 -0
  28. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  29. package/dist/resources/handlers.d.ts +1 -1
  30. package/dist/secrets/routes.d.ts +11 -11
  31. package/dist/server/action-routes.d.ts +2 -0
  32. package/dist/server/action-routes.js +187 -31
  33. package/dist/server/agent-chat/mcp-options.d.ts +3 -1
  34. package/dist/server/agent-chat-plugin.js +26 -1
  35. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  36. package/dist/server/auth.js +11 -20
  37. package/dist/server/embed-route.js +5 -3
  38. package/dist/server/embed-session.d.ts +30 -1
  39. package/dist/server/embed-session.js +376 -30
  40. package/dist/server/realtime-token.d.ts +1 -1
  41. package/dist/server/request-context.d.ts +2 -0
  42. package/dist/server/request-context.js +25 -1
  43. package/dist/shared/embed-auth.d.ts +74 -0
  44. package/dist/shared/embed-auth.js +379 -10
  45. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  46. package/dist/triggers/actions/manage-automation.d.ts +3 -3
  47. package/package.json +4 -4
package/dist/action.d.ts CHANGED
@@ -3,7 +3,7 @@ import { type ActionChatUIConfig } from "./action-ui.js";
3
3
  import type { ActionTool, AgentChatAttachment, AgentChatEvent } from "./agent/types.js";
4
4
  import type { ActionAuditConfig } from "./audit/types.js";
5
5
  import { type ActionAccessConfig } from "./authorization/action-access-runtime.js";
6
- export type ActionCaller = "tool" | "http" | "frontend" | "mcp-widget" | "cli" | "mcp" | "webmcp" | "a2a" | "automation";
6
+ export type ActionCaller = "tool" | "http" | "frontend" | "mcp-widget" | "mcp-widget-write" | "cli" | "mcp" | "webmcp" | "a2a" | "automation";
7
7
  export interface ActionAutomationContext {
8
8
  triggerId: string;
9
9
  triggerName: string;
@@ -38,6 +38,12 @@ export interface ActionRunContext {
38
38
  actionName?: string;
39
39
  /** Present only on frontend GETs authorized by a scoped directory-widget read capability. */
40
40
  mcpDirectoryWidgetReadOnly?: true;
41
+ /** Present only on frontend mutations authorized by a scoped directory-widget write capability. */
42
+ mcpDirectoryWidgetWrite?: {
43
+ appId: string;
44
+ resourceIds: Record<string, string>;
45
+ actionNames: readonly string[];
46
+ };
41
47
  threadId?: string;
42
48
  runId?: string;
43
49
  turnId?: string;
@@ -13,7 +13,7 @@ export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
13
13
  export { DEFAULT_MODEL, CHAT_MODEL_SELECTION_CHANGED_EVENT, chatModelSelectionStorageKey, loadChatModelCatalog, useChatModels, type UseChatModelsResult, type UseChatModelsOptions, type PersistedModelSelection, type EngineModelGroup, } from "../use-chat-models.js";
14
14
  export { fetchAgentEngineConfiguredState, useAgentEngineConfigured, type AgentEngineConfiguredState, type FetchAgentEngineConfiguredStateOptions, type UseAgentEngineConfiguredResult, } from "../use-agent-engine-configured.js";
15
15
  export { AGENT_CHAT_AI_SETUP_REQUIRED_CODE, AgentChatAiSetupRequiredError, ensureAgentEngineReadiness, getAgentEngineReadiness, invalidateAgentEngineReadiness, isAgentChatAiSetupRequiredError, isLocalRuntimeEngine, requireAgentEngineConfiguredForDispatch, subscribeAgentEngineReadiness, LOCAL_RUNTIME_ENGINE_IDS, agentEngineStatusUrlForChatApi, type AgentEngineReadinessSource, } from "../agent-engine-readiness.js";
16
- export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
16
+ export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useIsMcpDirectoryWidgetReadOnlyEmbed, useIsMcpDirectoryWidgetWriteEmbed, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
17
17
  export { buildDynamicAgentSuggestions, dedupeSuggestions, mergeAgentSuggestions, normalizeAgentDynamicSuggestionsConfig, useAgentDynamicSuggestions, useAgentDynamicSuggestionsResult, type AgentDynamicSuggestionContext, type AgentDynamicSuggestionsConfig, type AgentDynamicSuggestionsOption, } from "../dynamic-suggestions.js";
18
18
  export { clearChatStorage } from "../chat/storage.js";
19
19
  export { isAssistantChatHistoryVersion, coerceAssistantChatHistoryDate, type AssistantChatHistoryDate, type AssistantChatHistoryVersion, } from "../chat/assistant-chat-history-version.js";
@@ -13,7 +13,7 @@ export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
13
13
  export { DEFAULT_MODEL, CHAT_MODEL_SELECTION_CHANGED_EVENT, chatModelSelectionStorageKey, loadChatModelCatalog, useChatModels, } from "../use-chat-models.js";
14
14
  export { fetchAgentEngineConfiguredState, useAgentEngineConfigured, } from "../use-agent-engine-configured.js";
15
15
  export { AGENT_CHAT_AI_SETUP_REQUIRED_CODE, AgentChatAiSetupRequiredError, ensureAgentEngineReadiness, getAgentEngineReadiness, invalidateAgentEngineReadiness, isAgentChatAiSetupRequiredError, isLocalRuntimeEngine, requireAgentEngineConfiguredForDispatch, subscribeAgentEngineReadiness, LOCAL_RUNTIME_ENGINE_IDS, agentEngineStatusUrlForChatApi, } from "../agent-engine-readiness.js";
16
- export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useMcpAppHostContext, } from "../mcp-app-host.js";
16
+ export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useIsMcpDirectoryWidgetReadOnlyEmbed, useIsMcpDirectoryWidgetWriteEmbed, useMcpAppHostContext, } from "../mcp-app-host.js";
17
17
  export { buildDynamicAgentSuggestions, dedupeSuggestions, mergeAgentSuggestions, normalizeAgentDynamicSuggestionsConfig, useAgentDynamicSuggestions, useAgentDynamicSuggestionsResult, } from "../dynamic-suggestions.js";
18
18
  export { clearChatStorage } from "../chat/storage.js";
19
19
  export { isAssistantChatHistoryVersion, coerceAssistantChatHistoryDate, } from "../chat/assistant-chat-history-version.js";
@@ -11,12 +11,14 @@ export declare function getEmbedAuthToken(): string | null;
11
11
  * allowed.
12
12
  */
13
13
  export declare function hasMcpDirectoryWidgetCapabilityToken(): boolean;
14
+ export declare function hasMcpDirectoryWidgetWriteCapabilityToken(): boolean;
14
15
  /**
15
16
  * True when this document is the app nested in an MCP App widget shell (the
16
17
  * chat bridge is active) on a directory-widget read capability, which the
17
18
  * server limits to the widget's own resource reads.
18
19
  */
19
20
  export declare function isMcpDirectoryWidgetReadOnlyEmbed(): boolean;
21
+ export declare function isMcpDirectoryWidgetWriteEmbed(): boolean;
20
22
  export declare function isEmbedAuthActive(): boolean;
21
23
  export declare function _resetEmbedAuthForTests(): void;
22
24
  /**
@@ -1,5 +1,5 @@
1
- import { EMBED_MODE_QUERY_PARAM, EMBED_START_PATH, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, } from "../shared/embed-auth.js";
2
- import { isMcpDirectoryWidgetReadCapabilityScope } from "../shared/embed-auth.js";
1
+ import { EMBED_MODE_QUERY_PARAM, EMBED_START_PATH, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, MCP_DIRECTORY_WIDGET_SESSION_EXPIRED_HEADER, } from "../shared/embed-auth.js";
2
+ import { isMcpDirectoryWidgetReadCapabilityScope, isMcpDirectoryWidgetWriteCapabilityScope, } from "../shared/embed-auth.js";
3
3
  import { FRAMEWORK_INTERNAL_ROUTE_PREFIX } from "../shared/framework-route-prefix.js";
4
4
  import { MCP_APP_HOST_FILL_ATTRIBUTE } from "../shared/mcp-app-display.js";
5
5
  import { EMBED_TOKEN_STORAGE_KEY, MCP_CHAT_BRIDGE_STORAGE_KEY, } from "../shared/mcp-app-widget-embed.js";
@@ -7,11 +7,16 @@ import { SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, } from "../shared/sign-i
7
7
  import { frameworkRoutePrefix } from "./api-path.js";
8
8
  let installed = false;
9
9
  let memoryToken = null;
10
+ let renewedFromUrlToken = null;
11
+ let pendingWidgetSessionRenewal = null;
12
+ let widgetSessionRenewalRequestId = 0;
10
13
  let mcpChatBridgeActive = false;
11
14
  let mcpChatBridgeScope = null;
12
15
  const AUTH_FAILURE_COOLDOWN_MS = 60_000;
13
16
  const GUARDED_METHODS = new Set(["GET", "HEAD"]);
14
17
  const AUTH_FAILURE_HEADER = "x-agent-native-auth-circuit-breaker";
18
+ const EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY = `${EMBED_TOKEN_STORAGE_KEY}:renewed-from`;
19
+ const EMBED_SESSION_RENEWAL_TIMEOUT_MS = 15_000;
15
20
  const MCP_CHAT_BRIDGE_VIEWPORT_STYLE_ID = "agent-native-mcp-chat-bridge-viewport";
16
21
  const MCP_CHAT_BRIDGE_VIEWPORT_HEIGHT = 560;
17
22
  let pendingMcpChatBridgeViewportNotification = null;
@@ -43,7 +48,7 @@ export function readEmbedMcpChatBridgeFlagFromUrl() {
43
48
  return value === "1" || value === "true";
44
49
  }
45
50
  function currentMcpChatBridgeScope(win) {
46
- return readTokenFromUrl(win) ?? memoryToken ?? storedToken(win);
51
+ return getEmbedAuthToken() ?? memoryToken ?? storedToken(win);
47
52
  }
48
53
  function clearMcpChatBridge(win) {
49
54
  mcpChatBridgeActive = false;
@@ -142,6 +147,31 @@ export function getEmbedAuthToken() {
142
147
  return null;
143
148
  const fromUrl = readTokenFromUrl(win);
144
149
  if (fromUrl) {
150
+ let renewedFrom = renewedFromUrlToken;
151
+ if (!renewedFrom) {
152
+ try {
153
+ renewedFrom =
154
+ win.sessionStorage?.getItem(EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY) ??
155
+ null;
156
+ }
157
+ catch {
158
+ renewedFrom = null;
159
+ }
160
+ }
161
+ if (renewedFrom === fromUrl) {
162
+ const refreshed = memoryToken ?? storedToken(win);
163
+ if (refreshed && refreshed !== fromUrl)
164
+ return refreshed;
165
+ }
166
+ if (renewedFrom && renewedFrom !== fromUrl) {
167
+ renewedFromUrlToken = null;
168
+ try {
169
+ win.sessionStorage?.removeItem(EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY);
170
+ }
171
+ catch {
172
+ // coercion-ok: cleanup is best-effort; the refreshed URL token still supersedes this marker.
173
+ }
174
+ }
145
175
  storeToken(fromUrl, win);
146
176
  return fromUrl;
147
177
  }
@@ -160,7 +190,7 @@ function readEmbedTokenScope(token) {
160
190
  return undefined;
161
191
  }
162
192
  }
163
- let readOnlyScopeCache = null;
193
+ let widgetScopeCache = null;
164
194
  /**
165
195
  * True when the embed credential is a directory-widget read capability, which
166
196
  * only the MCP App widget flows mint. It stays readable after a client
@@ -173,13 +203,29 @@ export function hasMcpDirectoryWidgetCapabilityToken() {
173
203
  const token = getEmbedAuthToken();
174
204
  if (!token)
175
205
  return false;
176
- if (readOnlyScopeCache?.token !== token) {
177
- readOnlyScopeCache = {
206
+ if (widgetScopeCache?.token !== token) {
207
+ const scope = readEmbedTokenScope(token);
208
+ widgetScopeCache = {
178
209
  token,
179
- readOnly: isMcpDirectoryWidgetReadCapabilityScope(readEmbedTokenScope(token)),
210
+ readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
211
+ writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
180
212
  };
181
213
  }
182
- return readOnlyScopeCache.readOnly;
214
+ return widgetScopeCache.readOnly || widgetScopeCache.writable;
215
+ }
216
+ export function hasMcpDirectoryWidgetWriteCapabilityToken() {
217
+ const token = getEmbedAuthToken();
218
+ if (!token)
219
+ return false;
220
+ if (widgetScopeCache?.token !== token) {
221
+ const scope = readEmbedTokenScope(token);
222
+ widgetScopeCache = {
223
+ token,
224
+ readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
225
+ writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
226
+ };
227
+ }
228
+ return widgetScopeCache.writable;
183
229
  }
184
230
  /**
185
231
  * True when this document is the app nested in an MCP App widget shell (the
@@ -187,7 +233,21 @@ export function hasMcpDirectoryWidgetCapabilityToken() {
187
233
  * server limits to the widget's own resource reads.
188
234
  */
189
235
  export function isMcpDirectoryWidgetReadOnlyEmbed() {
190
- return hasMcpDirectoryWidgetCapabilityToken() && isEmbedMcpChatBridgeActive();
236
+ const token = getEmbedAuthToken();
237
+ if (!token)
238
+ return false;
239
+ if (widgetScopeCache?.token !== token) {
240
+ const scope = readEmbedTokenScope(token);
241
+ widgetScopeCache = {
242
+ token,
243
+ readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
244
+ writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
245
+ };
246
+ }
247
+ return widgetScopeCache.readOnly && isEmbedMcpChatBridgeActive();
248
+ }
249
+ export function isMcpDirectoryWidgetWriteEmbed() {
250
+ return (hasMcpDirectoryWidgetWriteCapabilityToken() && isEmbedMcpChatBridgeActive());
191
251
  }
192
252
  export function isEmbedAuthActive() {
193
253
  const win = browserWindow();
@@ -303,7 +363,10 @@ export function _resetEmbedAuthForTests() {
303
363
  }
304
364
  installed = false;
305
365
  memoryToken = null;
306
- readOnlyScopeCache = null;
366
+ renewedFromUrlToken = null;
367
+ pendingWidgetSessionRenewal = null;
368
+ widgetSessionRenewalRequestId = 0;
369
+ widgetScopeCache = null;
307
370
  mcpChatBridgeActive = false;
308
371
  mcpChatBridgeScope = null;
309
372
  authFailureCache.clear();
@@ -526,6 +589,63 @@ function requestUrlAndKey(input, init, win) {
526
589
  shouldGuard: shouldGuardAuthFailure(method, url),
527
590
  };
528
591
  }
592
+ function requestWidgetSessionRenewal(win) {
593
+ if (pendingWidgetSessionRenewal)
594
+ return pendingWidgetSessionRenewal;
595
+ if (!win.parent || win.parent === win)
596
+ return Promise.resolve(false);
597
+ widgetSessionRenewalRequestId += 1;
598
+ const requestId = `embed-renewal-${Date.now()}-${widgetSessionRenewalRequestId}`;
599
+ const renewal = new Promise((resolve) => {
600
+ let settled = false;
601
+ let timeoutId = null;
602
+ const finish = (succeeded) => {
603
+ if (settled)
604
+ return;
605
+ settled = true;
606
+ if (timeoutId !== null)
607
+ win.clearTimeout(timeoutId);
608
+ win.removeEventListener("message", onMessage);
609
+ resolve(succeeded);
610
+ };
611
+ const onMessage = (event) => {
612
+ if (event.source !== win.parent)
613
+ return;
614
+ const message = event.data;
615
+ const data = message && typeof message === "object" ? message.data : null;
616
+ if (message?.type !== "agentNative.embedSessionRenewed" ||
617
+ data?.requestId !== requestId) {
618
+ return;
619
+ }
620
+ if (data.ok !== true) {
621
+ finish(false);
622
+ return;
623
+ }
624
+ try {
625
+ win.parent.postMessage({ type: "agentNative.embedSessionRenewalApplied", requestId }, "*");
626
+ }
627
+ catch (error) {
628
+ console.warn("[agent-native] could not acknowledge embedded session renewal", error);
629
+ }
630
+ finish(true);
631
+ };
632
+ win.addEventListener("message", onMessage);
633
+ timeoutId = win.setTimeout(() => finish(false), EMBED_SESSION_RENEWAL_TIMEOUT_MS);
634
+ try {
635
+ win.parent.postMessage({
636
+ type: "agentNative.embedSessionExpired",
637
+ data: { requestId },
638
+ }, "*");
639
+ }
640
+ catch {
641
+ finish(false);
642
+ }
643
+ }).finally(() => {
644
+ pendingWidgetSessionRenewal = null;
645
+ });
646
+ pendingWidgetSessionRenewal = renewal;
647
+ return renewal;
648
+ }
529
649
  export function ensureEmbedAuthFetchInterceptor() {
530
650
  const win = browserWindow();
531
651
  if (!win)
@@ -534,7 +654,7 @@ export function ensureEmbedAuthFetchInterceptor() {
534
654
  markEmbedMcpChatBridgeActive();
535
655
  const urlToken = readTokenFromUrl(win);
536
656
  if (urlToken) {
537
- storeToken(urlToken, win);
657
+ getEmbedAuthToken();
538
658
  stripTokenFromUrl(win);
539
659
  }
540
660
  ensureMcpChatBridgeViewportClamp(win);
@@ -562,7 +682,35 @@ export function ensureEmbedAuthFetchInterceptor() {
562
682
  if (token && sameOrigin(input, win)) {
563
683
  [fetchInput, fetchInit] = withEmbedAuthHeaders(input, init, token, win);
564
684
  }
565
- const response = await originalFetch(fetchInput, fetchInit);
685
+ const canRenewWidgetSession = Boolean(token) &&
686
+ isMcpDirectoryWidgetWriteEmbed() &&
687
+ request &&
688
+ sameOrigin(input, win);
689
+ let replayRequest = null;
690
+ let firstRequest = null;
691
+ if (canRenewWidgetSession) {
692
+ try {
693
+ firstRequest = new Request(fetchInput, fetchInit);
694
+ replayRequest = firstRequest.clone();
695
+ }
696
+ catch {
697
+ // coercion-ok: non-cloneable streamed writes retain their original response and are not replayed.
698
+ }
699
+ }
700
+ let response = firstRequest
701
+ ? await originalFetch(firstRequest)
702
+ : await originalFetch(fetchInput, fetchInit);
703
+ if (response.status === 401 && canRenewWidgetSession) {
704
+ const sessionExpired = response.headers.get(MCP_DIRECTORY_WIDGET_SESSION_EXPIRED_HEADER) ===
705
+ "1";
706
+ if (sessionExpired && replayRequest && token) {
707
+ const renewed = await requestWidgetSessionRenewal(win);
708
+ if (renewed) {
709
+ const [retryInput, retryInit] = withEmbedAuthHeaders(replayRequest, undefined, token, win);
710
+ response = await originalFetch(retryInput, retryInit);
711
+ }
712
+ }
713
+ }
566
714
  if (request?.shouldGuard && isAuthFailureStatus(response.status)) {
567
715
  await recordAuthFailure(request.key, response);
568
716
  }
@@ -1,6 +1,6 @@
1
1
  export { initializeAgentNativeClient } from "../client-bootstrap.js";
2
2
  export { agentNativeApiDisabledReason, AgentNativeApiDisabledError, setAgentNativeApiDisabled, } from "../api-surface.js";
3
- export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, } from "../embed-auth.js";
3
+ export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, } from "../embed-auth.js";
4
4
  export { sendToFrame, onFrameMessage, requestUserInfo, getFrameOrigin, getFramePostMessageTargetOrigin, getCallbackOrigin, oauthRedirectUri, isInFrame, isTrustedFrameMessage, enterStyleEditing, enterTextEditing, exitSelectionMode, type UserInfo, } from "../frame.js";
5
5
  export { getBuilderParentOrigin, isInBuilderFrame, sendToBuilderChat, shouldParentFrameOwnAgentPanel, isTrustedBuilderMessage, tryDelegateBuildRequestToBuilder, type BuilderChatMessage, } from "../builder-frame.js";
6
6
  export { getClientSurface, type ClientSurface } from "../client-surface.js";
@@ -1,6 +1,6 @@
1
1
  export { initializeAgentNativeClient } from "../client-bootstrap.js";
2
2
  export { agentNativeApiDisabledReason, AgentNativeApiDisabledError, setAgentNativeApiDisabled, } from "../api-surface.js";
3
- export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, } from "../embed-auth.js";
3
+ export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, } from "../embed-auth.js";
4
4
  export { sendToFrame, onFrameMessage, requestUserInfo, getFrameOrigin, getFramePostMessageTargetOrigin, getCallbackOrigin, oauthRedirectUri, isInFrame, isTrustedFrameMessage, enterStyleEditing, enterTextEditing, exitSelectionMode, } from "../frame.js";
5
5
  export { getBuilderParentOrigin, isInBuilderFrame, sendToBuilderChat, shouldParentFrameOwnAgentPanel, isTrustedBuilderMessage, tryDelegateBuildRequestToBuilder, } from "../builder-frame.js";
6
6
  export { getClientSurface } from "../client-surface.js";
@@ -64,6 +64,7 @@ export declare function useIsMcpAppWidgetEmbed(): boolean;
64
64
  * instead of showing errors for requests that can never land.
65
65
  */
66
66
  export declare function useIsMcpDirectoryWidgetReadOnlyEmbed(): boolean;
67
+ export declare function useIsMcpDirectoryWidgetWriteEmbed(): boolean;
67
68
  export declare function isOpenAiMcpAppHost(): boolean;
68
69
  export declare function initializeMcpAppHost(): Promise<boolean>;
69
70
  export declare function sendMcpAppHostMessage(chat: McpAppHostChatMessage): Promise<boolean | null> | false;
@@ -2,7 +2,7 @@ import { useSyncExternalStore } from "react";
2
2
  import { EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, } from "../shared/embed-auth.js";
3
3
  import { MCP_APP_HOST_FILL_ATTRIBUTE, mcpAppHostFillsContainer, } from "../shared/mcp-app-display.js";
4
4
  import { MCP_APP_WIDGET_EMBED_ATTRIBUTE } from "../shared/mcp-app-widget-embed.js";
5
- import { getEmbedAuthToken, hasMcpDirectoryWidgetCapabilityToken, isEmbedAuthActive, markEmbedMcpChatBridgeActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, readEmbedMcpChatBridgeFlagFromUrl, } from "./embed-auth.js";
5
+ import { getEmbedAuthToken, hasMcpDirectoryWidgetCapabilityToken, isEmbedAuthActive, markEmbedMcpChatBridgeActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, readEmbedMcpChatBridgeFlagFromUrl, } from "./embed-auth.js";
6
6
  import { getFrameOrigin } from "./frame.js";
7
7
  export const AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES = {
8
8
  HOST_CONTEXT: "agentNative.mcpHostContext",
@@ -410,6 +410,9 @@ export function useIsMcpAppWidgetEmbed() {
410
410
  export function useIsMcpDirectoryWidgetReadOnlyEmbed() {
411
411
  return useSyncExternalStore(() => () => { }, isMcpDirectoryWidgetReadOnlyEmbed, () => false);
412
412
  }
413
+ export function useIsMcpDirectoryWidgetWriteEmbed() {
414
+ return useSyncExternalStore(() => () => { }, isMcpDirectoryWidgetWriteEmbed, () => false);
415
+ }
413
416
  export function isOpenAiMcpAppHost() {
414
417
  return (isInChildFrame() && isMcpAppBridgeEnabled() && readOpenAiBridge() !== null);
415
418
  }
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
13
13
  };
14
14
  }>>;
15
15
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
33
33
  idempotencyKey: string;
34
34
  deleted: boolean;
35
35
  } | {
36
+ id?: undefined;
36
37
  error: string;
37
38
  url?: undefined;
38
- id?: undefined;
39
39
  provider?: undefined;
40
40
  configured?: undefined;
41
41
  } | {
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
45
45
  configured?: undefined;
46
46
  error?: undefined;
47
47
  } | {
48
- url?: undefined;
49
48
  id?: undefined;
49
+ url?: undefined;
50
50
  provider?: undefined;
51
51
  error: string;
52
52
  configured: boolean;
@@ -34,6 +34,8 @@ export interface MCPConfig {
34
34
  productionActions?: Record<string, ActionEntry>;
35
35
  /** Unlisted from this MCP surface; used only when minting scoped widget tickets. */
36
36
  widgetReadActions?: Record<string, ActionEntry>;
37
+ /** Unlisted from this MCP surface; editor mutations callable only by scoped widget grants. */
38
+ widgetWriteActions?: Record<string, ActionEntry>;
37
39
  askAgent?: (message: string) => Promise<string>;
38
40
  builtinCrossAppTools?: boolean;
39
41
  /**
@@ -55,7 +57,15 @@ export interface MCPConfig {
55
57
  widgets?: boolean;
56
58
  widgetDomain?: string;
57
59
  widgetTargets?: Record<string, (args: Record<string, unknown>, result: unknown) => McpDirectoryWidgetTarget | null>;
60
+ authorizeWidgetWrite?: (input: {
61
+ toolName: string;
62
+ args: Record<string, unknown>;
63
+ result: unknown;
64
+ target: McpDirectoryWidgetTarget;
65
+ identity: MCPCallerIdentity;
66
+ }) => boolean | Promise<boolean>;
58
67
  widgetReadActionArguments?: Record<string, Record<string, McpDirectoryWidgetReadArgument>>;
68
+ widgetWriteActionArguments?: Record<string, Record<string, McpDirectoryWidgetReadArgument>>;
59
69
  /** Actions whose capability-backed `mcp-widget` execution is strictly read-only. */
60
70
  widgetReadOnlyActions?: readonly string[];
61
71
  /** Unlisted public reads that are available only through a scoped widget ticket. */
@@ -79,10 +89,14 @@ export interface MCPConfig {
79
89
  export interface McpDirectoryWidgetTarget {
80
90
  targetPath: string;
81
91
  resourceIds: Record<string, string>;
92
+ /** Mutations available to this artifact's editor, selected from the profile allowlist. */
93
+ writeActions?: readonly string[];
82
94
  }
83
95
  export interface MCPCallerIdentity {
84
96
  userEmail: string | undefined;
85
97
  identityAssurance?: "user" | "organization" | "service";
98
+ /** Issue time, in milliseconds, from a verified app-issued MCP credential. */
99
+ mcpCredentialIssuedAtMs?: number;
86
100
  orgId?: string | null;
87
101
  orgDomain: string | undefined;
88
102
  oauthScopes?: string[];
@@ -108,6 +122,7 @@ export declare class McpDirectoryProfileValidationError extends Error {
108
122
  }
109
123
  export declare function selectMcpActionSurface(config: MCPConfig, requestMeta?: MCPRequestMeta): Record<string, ActionEntry>;
110
124
  export declare function selectMcpDirectoryWidgetReadActions(profile: MCPConfig["directoryProfile"] | undefined, actions: Record<string, ActionEntry>): Record<string, ActionEntry> | undefined;
125
+ export declare function selectMcpDirectoryWidgetWriteActions(profile: MCPConfig["directoryProfile"] | undefined, actions: Record<string, ActionEntry>): Record<string, ActionEntry> | undefined;
111
126
  export declare function getConfiguredMcpOwnerEmail(): string | undefined;
112
127
  export declare function validateMcpDirectoryProfile(config: MCPConfig, sourceActions?: Record<string, ActionEntry>): void;
113
128
  export declare function validateMcpDirectoryWidgetDomain(domain: string | undefined): void;