@agent-native/core 0.72.2 → 0.72.4
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +16 -0
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/a2a/client.ts +7 -3
- package/corpus/core/src/client/AgentPanel.tsx +12 -1
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +263 -13
- package/corpus/core/src/client/api-path.ts +28 -0
- package/corpus/core/src/client/embed-auth.ts +26 -0
- package/corpus/core/src/client/mcp-app-host.ts +6 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +227 -33
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -1
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +16 -4
- package/corpus/core/src/client/use-chat-threads.ts +86 -5
- package/corpus/core/src/demo/fetch-interceptor.ts +1 -1
- package/corpus/core/src/embedding/agent.ts +6 -1
- package/corpus/core/src/embedding/bridge.ts +34 -1
- package/corpus/core/src/mcp/build-server.ts +38 -10
- package/corpus/core/src/mcp/embed-app.ts +120 -45
- package/corpus/core/src/mcp/index.ts +5 -0
- package/corpus/core/src/mcp/org-directory.ts +70 -11
- package/corpus/core/src/mcp/server.ts +14 -0
- package/corpus/core/src/mcp-client/config.ts +12 -0
- package/corpus/core/src/mcp-client/index.ts +2 -0
- package/corpus/core/src/mcp-client/manager.ts +268 -9
- package/corpus/core/src/mcp-client/remote-store.ts +154 -0
- package/corpus/core/src/mcp-client/routes.ts +2 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +8 -0
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/shared/mcp-embed-headers.ts +44 -3
- package/corpus/core/src/vite/client.ts +53 -0
- package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +17 -10
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +15 -6
- package/corpus/templates/assets/AGENTS.md +7 -5
- package/corpus/templates/assets/actions/generate-asset.ts +161 -0
- package/corpus/templates/assets/actions/list-assets.ts +4 -2
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/open-asset-picker.ts +84 -3
- package/corpus/templates/assets/app/components/layout/Layout.tsx +3 -2
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +27 -4
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +35 -5
- package/corpus/templates/assets/app/routes/_index.tsx +12 -0
- package/corpus/templates/assets/app/routes/chat.$threadId.tsx +1 -0
- package/corpus/templates/assets/app/routes/library.tsx +243 -40
- package/corpus/templates/chat/actions/navigate.ts +3 -0
- package/corpus/templates/chat/app/components/layout/Layout.tsx +7 -2
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +27 -4
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +38 -6
- package/corpus/templates/chat/app/routes/_index.tsx +13 -0
- package/corpus/templates/chat/app/routes/chat.$threadId.tsx +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +9 -0
- package/corpus/templates/design/AGENTS.md +10 -5
- package/corpus/templates/design/actions/connect-assets-mcp.ts +131 -0
- package/corpus/templates/design/actions/insert-asset.ts +219 -0
- package/corpus/templates/design/actions/view-screen.ts +3 -1
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +53 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -1
- package/corpus/templates/design/server/plugins/assets-mcp.ts +60 -0
- package/corpus/templates/dispatch/app/routes/chat.$threadId.tsx +26 -0
- package/dist/a2a/client.d.ts +1 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +5 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +6 -2
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +22 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +215 -13
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/api-path.d.ts.map +1 -1
- package/dist/client/api-path.js +27 -0
- package/dist/client/api-path.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +27 -0
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts.map +1 -1
- package/dist/client/mcp-app-host.js +5 -0
- package/dist/client/mcp-app-host.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +179 -33
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +3 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +7 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +9 -5
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts +6 -0
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +79 -5
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/demo/fetch-interceptor.js +1 -1
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/embedding/agent.d.ts +1 -1
- package/dist/embedding/agent.d.ts.map +1 -1
- package/dist/embedding/agent.js +1 -1
- package/dist/embedding/agent.js.map +1 -1
- package/dist/embedding/bridge.d.ts.map +1 -1
- package/dist/embedding/bridge.js +27 -1
- package/dist/embedding/bridge.js.map +1 -1
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +32 -9
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +120 -45
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/org-directory.d.ts +1 -0
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +59 -11
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp-client/config.d.ts +12 -0
- package/dist/mcp-client/config.d.ts.map +1 -1
- package/dist/mcp-client/config.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/manager.d.ts +2 -0
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +201 -9
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/remote-store.d.ts +27 -0
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +105 -0
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +1 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +2 -2
- package/dist/provider-api/actions/query-staged-dataset.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +8 -8
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +8 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +3 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +40 -3
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +44 -0
- package/dist/vite/client.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MCP_APP_CHAT_BRIDGE_QUERY_PARAM,
|
|
3
|
+
EMBED_MODE_QUERY_PARAM,
|
|
4
|
+
} from "../shared/embed-auth.js";
|
|
1
5
|
import {
|
|
2
6
|
AGENT_NATIVE_EMBED_MESSAGE_TYPES,
|
|
3
7
|
createAgentNativeEmbedEnvelope,
|
|
@@ -61,10 +65,38 @@ type PendingRequest = {
|
|
|
61
65
|
|
|
62
66
|
function resolveParentOrigin(win: Window, explicit?: string): string | null {
|
|
63
67
|
if (explicit) return explicit;
|
|
68
|
+
if (shouldUseOpaqueParentTarget(win)) return "*";
|
|
64
69
|
const referrerOrigin = embeddedAppOrigin(win.document?.referrer ?? "");
|
|
65
70
|
return referrerOrigin;
|
|
66
71
|
}
|
|
67
72
|
|
|
73
|
+
function shouldUseOpaqueParentTarget(win: Window): boolean {
|
|
74
|
+
try {
|
|
75
|
+
const url = new URL(win.location.href);
|
|
76
|
+
const chatBridge = url.searchParams.get(MCP_APP_CHAT_BRIDGE_QUERY_PARAM);
|
|
77
|
+
const embedMode = url.searchParams.get(EMBED_MODE_QUERY_PARAM);
|
|
78
|
+
return (
|
|
79
|
+
chatBridge === "1" ||
|
|
80
|
+
chatBridge === "true" ||
|
|
81
|
+
embedMode === "1" ||
|
|
82
|
+
embedMode === "true"
|
|
83
|
+
);
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function defaultAllowedOrigins(
|
|
90
|
+
parentOrigin: string | null,
|
|
91
|
+
referrerOrigin: string | null,
|
|
92
|
+
): string[] {
|
|
93
|
+
if (!parentOrigin) return [];
|
|
94
|
+
if (parentOrigin === "*") {
|
|
95
|
+
return ["null", ...(referrerOrigin ? [referrerOrigin] : [])];
|
|
96
|
+
}
|
|
97
|
+
return [parentOrigin];
|
|
98
|
+
}
|
|
99
|
+
|
|
68
100
|
function postToParent(
|
|
69
101
|
win: Window,
|
|
70
102
|
parent: Window | null,
|
|
@@ -83,9 +115,10 @@ export function createEmbeddedAppBridge(
|
|
|
83
115
|
): EmbeddedAppBridge {
|
|
84
116
|
const win = options.currentWindow ?? window;
|
|
85
117
|
const parentOrigin = resolveParentOrigin(win, options.parentOrigin);
|
|
118
|
+
const referrerOrigin = embeddedAppOrigin(win.document?.referrer ?? "");
|
|
86
119
|
const allowedOrigins =
|
|
87
120
|
options.allowedOrigins ??
|
|
88
|
-
(parentOrigin
|
|
121
|
+
defaultAllowedOrigins(parentOrigin, referrerOrigin);
|
|
89
122
|
const pending = new Map<string, PendingRequest>();
|
|
90
123
|
let destroyed = false;
|
|
91
124
|
|
|
@@ -152,6 +152,8 @@ export interface MCPCallerIdentity {
|
|
|
152
152
|
oauthScopes?: string[];
|
|
153
153
|
/** Present only for standard remote MCP OAuth access tokens. */
|
|
154
154
|
oauthClientId?: string;
|
|
155
|
+
/** Present only for framework-minted first-party MCP client tokens. */
|
|
156
|
+
firstPartyMcp?: boolean;
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
/** Per-request context used to turn an action's relative deep link into the
|
|
@@ -748,7 +750,7 @@ function safeUiSegment(value: string | undefined, fallback: string): string {
|
|
|
748
750
|
|
|
749
751
|
// ChatGPT and Claude cache MCP App resource HTML by `ui://` URI. Bump this
|
|
750
752
|
// when the shared shell changes in a way that must invalidate host caches.
|
|
751
|
-
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-
|
|
753
|
+
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-v51";
|
|
752
754
|
|
|
753
755
|
function legacyDefaultMcpAppUri(config: MCPConfig, actionName: string): string {
|
|
754
756
|
const app = safeUiSegment(config.appId ?? config.name, "agent-native");
|
|
@@ -1785,6 +1787,7 @@ function addSecretCandidate(
|
|
|
1785
1787
|
|
|
1786
1788
|
async function verifyA2AJwtForMcp(
|
|
1787
1789
|
token: string,
|
|
1790
|
+
resourceUrl?: string | string[],
|
|
1788
1791
|
): Promise<Record<string, unknown> | null> {
|
|
1789
1792
|
const jose = await import("jose");
|
|
1790
1793
|
let unverifiedPayload: Record<string, unknown> | null = null;
|
|
@@ -1813,21 +1816,43 @@ async function verifyA2AJwtForMcp(
|
|
|
1813
1816
|
}
|
|
1814
1817
|
}
|
|
1815
1818
|
|
|
1819
|
+
const firstPartyMcp = unverifiedPayload.agent_native_first_party_mcp === true;
|
|
1820
|
+
const audiences = firstPartyMcp ? mcpAudienceList(resourceUrl) : null;
|
|
1821
|
+
if (firstPartyMcp && !audiences?.length) return null;
|
|
1822
|
+
|
|
1816
1823
|
for (const secret of candidateSecrets) {
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1824
|
+
const encodedSecret = new TextEncoder().encode(secret);
|
|
1825
|
+
for (const audience of audiences ?? [undefined]) {
|
|
1826
|
+
try {
|
|
1827
|
+
const { payload } = await jose.jwtVerify(
|
|
1828
|
+
token,
|
|
1829
|
+
encodedSecret,
|
|
1830
|
+
audience ? { audience } : undefined,
|
|
1831
|
+
);
|
|
1832
|
+
return payload as Record<string, unknown>;
|
|
1833
|
+
} catch {
|
|
1834
|
+
// Try the next candidate without exposing which secret matched.
|
|
1835
|
+
}
|
|
1825
1836
|
}
|
|
1826
1837
|
}
|
|
1827
1838
|
|
|
1828
1839
|
return null;
|
|
1829
1840
|
}
|
|
1830
1841
|
|
|
1842
|
+
function mcpAudienceList(resource: string | string[] | undefined): string[] {
|
|
1843
|
+
const raw = Array.isArray(resource) ? resource : resource ? [resource] : [];
|
|
1844
|
+
const seen = new Set<string>();
|
|
1845
|
+
const out: string[] = [];
|
|
1846
|
+
for (const value of raw) {
|
|
1847
|
+
const normalized = value.replace(/\/+$/, "");
|
|
1848
|
+
if (normalized && !seen.has(normalized)) {
|
|
1849
|
+
seen.add(normalized);
|
|
1850
|
+
out.push(normalized);
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return out;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1831
1856
|
async function isConnectTokenAllowed(
|
|
1832
1857
|
jti: string | undefined,
|
|
1833
1858
|
): Promise<boolean> {
|
|
@@ -1941,7 +1966,7 @@ export async function verifyAuth(
|
|
|
1941
1966
|
|
|
1942
1967
|
// Try an A2A JWT via the shared A2A_SECRET first, then the caller org's
|
|
1943
1968
|
// synced A2A secret when the token carries org_domain.
|
|
1944
|
-
const payload = await verifyA2AJwtForMcp(token);
|
|
1969
|
+
const payload = await verifyA2AJwtForMcp(token, options.resourceUrl);
|
|
1945
1970
|
if (payload) {
|
|
1946
1971
|
const tokenScope =
|
|
1947
1972
|
typeof payload.scope === "string" ? payload.scope : undefined;
|
|
@@ -1976,6 +2001,9 @@ export async function verifyAuth(
|
|
|
1976
2001
|
typeof payload.org_domain === "string"
|
|
1977
2002
|
? (payload.org_domain as string)
|
|
1978
2003
|
: undefined,
|
|
2004
|
+
...(payload.agent_native_first_party_mcp === true
|
|
2005
|
+
? { firstPartyMcp: true }
|
|
2006
|
+
: {}),
|
|
1979
2007
|
},
|
|
1980
2008
|
// Verified JWT (connect-minted or A2A delegation) — a real caller.
|
|
1981
2009
|
fullSurface: true,
|
|
@@ -114,6 +114,7 @@ export function embedApp(
|
|
|
114
114
|
const frameReadyMessageDelays = [0, 200, 500, 1500, 3000, 7000, 15000, 30000];
|
|
115
115
|
const frameReadyTimeoutMs = 45000;
|
|
116
116
|
const frameLoadTimeoutMs = 45000;
|
|
117
|
+
const maxEmbedSessionRefreshAttempts = 2;
|
|
117
118
|
const defaultOpenAiBridgeWaitMs = 200;
|
|
118
119
|
const chatGptOpenAiBridgeWaitMs = 5000;
|
|
119
120
|
const openAiBridgePollMs = 50;
|
|
@@ -121,6 +122,7 @@ export function embedApp(
|
|
|
121
122
|
const nativeBridgeRequestTimeoutMs = 30000;
|
|
122
123
|
const wrapperRequestTimeoutMs = 5000;
|
|
123
124
|
let app = null;
|
|
125
|
+
let appConnectPromise = null;
|
|
124
126
|
let openAiBridge = null;
|
|
125
127
|
let wrapperRequestId = 0;
|
|
126
128
|
const wrapperRequests = new Map();
|
|
@@ -134,6 +136,7 @@ export function embedApp(
|
|
|
134
136
|
let appFrameReadyTimer = null;
|
|
135
137
|
let appFrameLoadTimer = null;
|
|
136
138
|
let lastFrameSrc = "";
|
|
139
|
+
let embedSessionRefreshAttempts = 0;
|
|
137
140
|
|
|
138
141
|
function esc(value) {
|
|
139
142
|
return String(value ?? "")
|
|
@@ -269,9 +272,9 @@ export function embedApp(
|
|
|
269
272
|
record.deepLinkUrl,
|
|
270
273
|
record.deepLink,
|
|
271
274
|
record.openUrl,
|
|
272
|
-
record.url,
|
|
273
275
|
structuredOpenLinkUrl,
|
|
274
|
-
metaUrl
|
|
276
|
+
metaUrl,
|
|
277
|
+
record.url
|
|
275
278
|
]);
|
|
276
279
|
}
|
|
277
280
|
|
|
@@ -324,6 +327,12 @@ export function embedApp(
|
|
|
324
327
|
try { appFrame.contentWindow.postMessage(message, "*"); } catch {}
|
|
325
328
|
}
|
|
326
329
|
|
|
330
|
+
function notifyOuterMcpAppReady() {
|
|
331
|
+
try {
|
|
332
|
+
window.parent.postMessage({ type: "agentNative.embeddedAppReady" }, "*");
|
|
333
|
+
} catch {}
|
|
334
|
+
}
|
|
335
|
+
|
|
327
336
|
function nextWrapperRequestId() {
|
|
328
337
|
wrapperRequestId += 1;
|
|
329
338
|
return "mcp-wrapper-" + Date.now() + "-" + wrapperRequestId;
|
|
@@ -640,6 +649,21 @@ export function embedApp(
|
|
|
640
649
|
);
|
|
641
650
|
}
|
|
642
651
|
|
|
652
|
+
function importHeadChildrenWithBase(source, baseHref) {
|
|
653
|
+
const base = document.createElement("base");
|
|
654
|
+
base.href = baseHref;
|
|
655
|
+
const nodes = Array.from(source.childNodes).filter((node) => {
|
|
656
|
+
return !(
|
|
657
|
+
node.nodeType === 1 &&
|
|
658
|
+
String(node.nodeName || "").toLowerCase() === "base"
|
|
659
|
+
);
|
|
660
|
+
});
|
|
661
|
+
document.head.replaceChildren(
|
|
662
|
+
base,
|
|
663
|
+
...nodes.map((node) => document.importNode(node, true))
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
643
667
|
function isModuleScript(script) {
|
|
644
668
|
return (script.getAttribute("type") || "").trim().toLowerCase() === "module";
|
|
645
669
|
}
|
|
@@ -835,10 +859,7 @@ export function embedApp(
|
|
|
835
859
|
);
|
|
836
860
|
const scripts = Array.from(parsed.querySelectorAll("script"));
|
|
837
861
|
copyDocumentElementAttributes(parsed.documentElement);
|
|
838
|
-
|
|
839
|
-
const base = document.createElement("base");
|
|
840
|
-
base.href = config.baseHref;
|
|
841
|
-
document.head.prepend(base);
|
|
862
|
+
importHeadChildrenWithBase(parsed.head, config.baseHref);
|
|
842
863
|
importChildren(parsed.body, document.body);
|
|
843
864
|
installExternalOpenControl(appUrl);
|
|
844
865
|
for (const script of scripts) {
|
|
@@ -920,6 +941,7 @@ export function embedApp(
|
|
|
920
941
|
window.history.replaceState(window.history.state, "", localPathFromUrl(appUrl, false));
|
|
921
942
|
} catch {}
|
|
922
943
|
await mountTransplantedHtml(html, appUrl);
|
|
944
|
+
embedSessionRefreshAttempts = 0;
|
|
923
945
|
notifyHostHeightRepeatedly();
|
|
924
946
|
}
|
|
925
947
|
|
|
@@ -1159,6 +1181,7 @@ export function embedApp(
|
|
|
1159
1181
|
frame.addEventListener("load", () => {
|
|
1160
1182
|
if (appFrame !== frame) return;
|
|
1161
1183
|
clearFrameLoadTimer();
|
|
1184
|
+
notifyOuterMcpAppReady();
|
|
1162
1185
|
sendFrameReadyMessages(frame);
|
|
1163
1186
|
startFrameReadyTimer(frame);
|
|
1164
1187
|
});
|
|
@@ -1177,6 +1200,13 @@ export function embedApp(
|
|
|
1177
1200
|
renderFrameFallback();
|
|
1178
1201
|
return;
|
|
1179
1202
|
}
|
|
1203
|
+
if (embedSessionRefreshAttempts >= maxEmbedSessionRefreshAttempts) {
|
|
1204
|
+
renderAppLaunchError(
|
|
1205
|
+
"Embedded app session expired. Reopen the app to mint a fresh session."
|
|
1206
|
+
);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
embedSessionRefreshAttempts += 1;
|
|
1180
1210
|
openStartUrl = "";
|
|
1181
1211
|
startedFor = "";
|
|
1182
1212
|
lastFrameSrc = "";
|
|
@@ -1193,19 +1223,6 @@ export function embedApp(
|
|
|
1193
1223
|
return true;
|
|
1194
1224
|
}
|
|
1195
1225
|
|
|
1196
|
-
// We have connected to a standards-track MCP Apps host (Codex, Cursor,
|
|
1197
|
-
// Claude over the SDK, our own renderer, …) through the postMessage
|
|
1198
|
-
// \`ui/*\` bridge rather than ChatGPT's \`window.openai\` global. These hosts
|
|
1199
|
-
// render the resource in a strict sandboxed iframe (typically
|
|
1200
|
-
// \`sandbox="allow-scripts"\`, opaque origin). Self-navigating that iframe to
|
|
1201
|
-
// the real app origin tears down the host bridge and loses the opaque-origin
|
|
1202
|
-
// auth context, which shows up as a permanent / flashing loading state.
|
|
1203
|
-
// Transplanting the app document into the shell keeps the bridge alive and
|
|
1204
|
-
// works under the opaque origin via embed-token auth, exactly like Claude.
|
|
1205
|
-
function isNativeMcpAppsBridgeHost() {
|
|
1206
|
-
return !!app && !openAiBridge;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
1226
|
function shouldTransplantAppDocument() {
|
|
1210
1227
|
const render = renderModeSource();
|
|
1211
1228
|
const mode = render.mode;
|
|
@@ -1215,7 +1232,6 @@ export function embedApp(
|
|
|
1215
1232
|
return (
|
|
1216
1233
|
isClaudeMcpContentHost() ||
|
|
1217
1234
|
isChatGptSandboxHost() ||
|
|
1218
|
-
isNativeMcpAppsBridgeHost() ||
|
|
1219
1235
|
mode === "transplant" ||
|
|
1220
1236
|
render.frame === "transplant"
|
|
1221
1237
|
);
|
|
@@ -1240,10 +1256,29 @@ export function embedApp(
|
|
|
1240
1256
|
}
|
|
1241
1257
|
|
|
1242
1258
|
function shouldRenderControlledAppFrame() {
|
|
1243
|
-
return !!openAiBridge || isChatGptSandboxHost();
|
|
1259
|
+
return !!openAiBridge || !!app || isChatGptSandboxHost();
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
function shouldDirectRenderKnownAppRoute(src) {
|
|
1263
|
+
return !!app && !openAiBridge && !isEmbedStartUrl(src) && !shouldTransplantAppDocument();
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function isCurrentFrameUrl(src) {
|
|
1267
|
+
try {
|
|
1268
|
+
return new URL(src, window.location.href).href === window.location.href;
|
|
1269
|
+
} catch {
|
|
1270
|
+
return false;
|
|
1271
|
+
}
|
|
1244
1272
|
}
|
|
1245
1273
|
|
|
1246
1274
|
function navigateToAppFrame(src) {
|
|
1275
|
+
if (isCurrentFrameUrl(src)) {
|
|
1276
|
+
clearFrameReadyTimer();
|
|
1277
|
+
clearFrameLoadTimer();
|
|
1278
|
+
setMessage("App opened");
|
|
1279
|
+
notifyHostHeightRepeatedly();
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1247
1282
|
clearFrameReadyTimer();
|
|
1248
1283
|
clearFrameLoadTimer();
|
|
1249
1284
|
appFrame = null;
|
|
@@ -1257,6 +1292,24 @@ export function embedApp(
|
|
|
1257
1292
|
}
|
|
1258
1293
|
}
|
|
1259
1294
|
|
|
1295
|
+
async function ensureHostAppConnected() {
|
|
1296
|
+
if (!app || typeof app.connect !== "function") return;
|
|
1297
|
+
if (!appConnectPromise) {
|
|
1298
|
+
appConnectPromise = Promise.resolve(app.connect())
|
|
1299
|
+
.then(async (value) => {
|
|
1300
|
+
// Let the host process ui/notifications/initialized before follow-up calls.
|
|
1301
|
+
await new Promise((resolve) => window.setTimeout(resolve, 0));
|
|
1302
|
+
await new Promise((resolve) => window.setTimeout(resolve, 0));
|
|
1303
|
+
return value;
|
|
1304
|
+
})
|
|
1305
|
+
.catch((err) => {
|
|
1306
|
+
appConnectPromise = null;
|
|
1307
|
+
throw err;
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
await appConnectPromise;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1260
1313
|
async function updateHostModelContext(data) {
|
|
1261
1314
|
const params = {};
|
|
1262
1315
|
if (Array.isArray(data && data.content)) params.content = data.content;
|
|
@@ -1271,6 +1324,7 @@ export function embedApp(
|
|
|
1271
1324
|
return { ok: true };
|
|
1272
1325
|
}
|
|
1273
1326
|
if (!app || typeof app.updateModelContext !== "function") return { ok: false };
|
|
1327
|
+
await ensureHostAppConnected();
|
|
1274
1328
|
await app.updateModelContext(params);
|
|
1275
1329
|
return { ok: true };
|
|
1276
1330
|
}
|
|
@@ -1356,6 +1410,7 @@ export function embedApp(
|
|
|
1356
1410
|
agentNativeModelContext: modelContext
|
|
1357
1411
|
});
|
|
1358
1412
|
} else if (app && typeof app.updateModelContext === "function") {
|
|
1413
|
+
await ensureHostAppConnected();
|
|
1359
1414
|
await app.updateModelContext(modelContext);
|
|
1360
1415
|
}
|
|
1361
1416
|
} catch (err) {
|
|
@@ -1372,6 +1427,7 @@ export function embedApp(
|
|
|
1372
1427
|
}
|
|
1373
1428
|
let result = null;
|
|
1374
1429
|
if (app && typeof app.sendMessage === "function") {
|
|
1430
|
+
await ensureHostAppConnected();
|
|
1375
1431
|
result = await app.sendMessage({
|
|
1376
1432
|
role: "user",
|
|
1377
1433
|
content
|
|
@@ -1412,8 +1468,10 @@ export function embedApp(
|
|
|
1412
1468
|
const data = event.data.data || {};
|
|
1413
1469
|
if (event.data.type === "agentNative.embeddedAppReady") {
|
|
1414
1470
|
appFrameReady = true;
|
|
1471
|
+
embedSessionRefreshAttempts = 0;
|
|
1415
1472
|
clearFrameLoadTimer();
|
|
1416
1473
|
clearFrameReadyTimer();
|
|
1474
|
+
notifyOuterMcpAppReady();
|
|
1417
1475
|
return;
|
|
1418
1476
|
}
|
|
1419
1477
|
if (event.data.type === "agentNative.embedSessionExpired") {
|
|
@@ -1454,7 +1512,7 @@ export function embedApp(
|
|
|
1454
1512
|
}
|
|
1455
1513
|
|
|
1456
1514
|
async function launchEmbed() {
|
|
1457
|
-
|
|
1515
|
+
let launchUrl = openStartUrl || openUrl;
|
|
1458
1516
|
if (!launchUrl) {
|
|
1459
1517
|
renderAppLaunchError("Open link was not available.");
|
|
1460
1518
|
return;
|
|
@@ -1463,11 +1521,11 @@ export function embedApp(
|
|
|
1463
1521
|
setMessage("Ready to open.");
|
|
1464
1522
|
return;
|
|
1465
1523
|
}
|
|
1466
|
-
if (startedFor === launchUrl) return;
|
|
1467
|
-
startedFor = launchUrl;
|
|
1468
1524
|
setMessage("Loading app");
|
|
1469
1525
|
try {
|
|
1470
1526
|
const selfNavigate = shouldSelfNavigateToApp();
|
|
1527
|
+
if (startedFor === launchUrl) return;
|
|
1528
|
+
startedFor = launchUrl;
|
|
1471
1529
|
const embedUrl = withChatBridgeParam(launchUrl);
|
|
1472
1530
|
if (selfNavigate && isEmbedStartUrl(embedUrl)) {
|
|
1473
1531
|
if (shouldTransplantAppDocument()) {
|
|
@@ -1483,6 +1541,10 @@ export function embedApp(
|
|
|
1483
1541
|
renderFrame(embedUrl);
|
|
1484
1542
|
return;
|
|
1485
1543
|
}
|
|
1544
|
+
if (shouldDirectRenderKnownAppRoute(embedUrl)) {
|
|
1545
|
+
renderFrame(embedUrl);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1486
1548
|
const result = await callEmbedSessionTool(embedSessionArgsFor(embedUrl));
|
|
1487
1549
|
const data = parseToolResult(result);
|
|
1488
1550
|
if (typeof data.startUrl !== "string" || !data.startUrl) {
|
|
@@ -1640,7 +1702,7 @@ export function embedApp(
|
|
|
1640
1702
|
|
|
1641
1703
|
function createNativeMcpAppsBridge() {
|
|
1642
1704
|
let rpcId = 0;
|
|
1643
|
-
let
|
|
1705
|
+
let connectPromise = null;
|
|
1644
1706
|
let hostContext = {};
|
|
1645
1707
|
const pendingRequests = new Map();
|
|
1646
1708
|
|
|
@@ -1708,26 +1770,32 @@ export function embedApp(
|
|
|
1708
1770
|
return hostContext.protocolVersion || "mcp-apps-postmessage";
|
|
1709
1771
|
},
|
|
1710
1772
|
async connect() {
|
|
1711
|
-
if (
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1773
|
+
if (connectPromise) return await connectPromise;
|
|
1774
|
+
connectPromise = (async () => {
|
|
1775
|
+
window.addEventListener("message", onMessage, { passive: true });
|
|
1776
|
+
const result = await rpcRequest(
|
|
1777
|
+
"ui/initialize",
|
|
1778
|
+
{
|
|
1779
|
+
appInfo: { name: "Agent Native Embed", version: "1.0.0" },
|
|
1780
|
+
appCapabilities: {},
|
|
1781
|
+
protocolVersion: "2026-01-26"
|
|
1782
|
+
},
|
|
1783
|
+
nativeBridgeInitializeTimeoutMs
|
|
1784
|
+
);
|
|
1785
|
+
hostContext = objectValue(result);
|
|
1786
|
+
rpcNotify("ui/notifications/initialized", {});
|
|
1787
|
+
if (typeof nativeApp.onhostcontextchanged === "function") {
|
|
1788
|
+
nativeApp.onhostcontextchanged(hostContext);
|
|
1789
|
+
}
|
|
1790
|
+
return hostContext;
|
|
1791
|
+
})().catch((err) => {
|
|
1792
|
+
connectPromise = null;
|
|
1793
|
+
throw err;
|
|
1794
|
+
});
|
|
1795
|
+
return await connectPromise;
|
|
1729
1796
|
},
|
|
1730
1797
|
async callServerTool(request) {
|
|
1798
|
+
await nativeApp.connect();
|
|
1731
1799
|
const record = objectValue(request);
|
|
1732
1800
|
return await rpcRequest("tools/call", {
|
|
1733
1801
|
name: record.name,
|
|
@@ -1735,6 +1803,7 @@ export function embedApp(
|
|
|
1735
1803
|
});
|
|
1736
1804
|
},
|
|
1737
1805
|
async updateModelContext(params) {
|
|
1806
|
+
await nativeApp.connect();
|
|
1738
1807
|
return await rpcRequest("ui/update-model-context", objectValue(params));
|
|
1739
1808
|
},
|
|
1740
1809
|
async openLink(params) {
|
|
@@ -1749,12 +1818,14 @@ export function embedApp(
|
|
|
1749
1818
|
return opened ? { ok: true } : { isError: true };
|
|
1750
1819
|
},
|
|
1751
1820
|
async requestDisplayMode(params) {
|
|
1821
|
+
await nativeApp.connect();
|
|
1752
1822
|
return await rpcRequest("ui/request-display-mode", objectValue(params));
|
|
1753
1823
|
},
|
|
1754
1824
|
sendSizeChanged(params) {
|
|
1755
1825
|
rpcNotify("ui/notifications/size-changed", objectValue(params));
|
|
1756
1826
|
},
|
|
1757
1827
|
async sendMessage(params) {
|
|
1828
|
+
await nativeApp.connect();
|
|
1758
1829
|
return await rpcRequest("ui/message", objectValue(params));
|
|
1759
1830
|
}
|
|
1760
1831
|
};
|
|
@@ -1798,6 +1869,7 @@ export function embedApp(
|
|
|
1798
1869
|
|
|
1799
1870
|
async function startNativeMcpAppsBridge() {
|
|
1800
1871
|
app = createNativeMcpAppsBridge();
|
|
1872
|
+
appConnectPromise = null;
|
|
1801
1873
|
app.ontoolinput = (params) => {
|
|
1802
1874
|
toolInput = params.arguments || {};
|
|
1803
1875
|
};
|
|
@@ -1815,7 +1887,8 @@ export function embedApp(
|
|
|
1815
1887
|
notifyHostHeight();
|
|
1816
1888
|
sendHostContext();
|
|
1817
1889
|
};
|
|
1818
|
-
await
|
|
1890
|
+
await ensureHostAppConnected();
|
|
1891
|
+
notifyOuterMcpAppReady();
|
|
1819
1892
|
updateDisplayButton();
|
|
1820
1893
|
notifyHostHeight();
|
|
1821
1894
|
sendHostContext();
|
|
@@ -1828,6 +1901,7 @@ export function embedApp(
|
|
|
1828
1901
|
{},
|
|
1829
1902
|
{ autoResize: false }
|
|
1830
1903
|
);
|
|
1904
|
+
appConnectPromise = null;
|
|
1831
1905
|
app.ontoolinput = (params) => {
|
|
1832
1906
|
toolInput = params.arguments || {};
|
|
1833
1907
|
};
|
|
@@ -1845,7 +1919,8 @@ export function embedApp(
|
|
|
1845
1919
|
notifyHostHeight();
|
|
1846
1920
|
sendHostContext();
|
|
1847
1921
|
};
|
|
1848
|
-
await
|
|
1922
|
+
await ensureHostAppConnected();
|
|
1923
|
+
notifyOuterMcpAppReady();
|
|
1849
1924
|
updateDisplayButton();
|
|
1850
1925
|
notifyHostHeight();
|
|
1851
1926
|
sendHostContext();
|
|
@@ -146,6 +146,10 @@ function scopedCacheKey(
|
|
|
146
146
|
].join("|");
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
function serviceScopedCacheKey(origin: string, orgId: string): string {
|
|
150
|
+
return [origin, `service-org:${orgId}`].join("|");
|
|
151
|
+
}
|
|
152
|
+
|
|
149
153
|
/**
|
|
150
154
|
* Fetch the org's first-party sibling apps from the org directory.
|
|
151
155
|
*
|
|
@@ -162,6 +166,7 @@ function scopedCacheKey(
|
|
|
162
166
|
export async function fetchOrgApps(opts?: {
|
|
163
167
|
selfId?: string;
|
|
164
168
|
selfOrigin?: string;
|
|
169
|
+
serviceOrgId?: string;
|
|
165
170
|
env?: NodeJS.ProcessEnv;
|
|
166
171
|
}): Promise<OrgApp[]> {
|
|
167
172
|
const env = opts?.env ?? process.env;
|
|
@@ -182,24 +187,32 @@ export async function fetchOrgApps(opts?: {
|
|
|
182
187
|
let cacheKey: string | null = null;
|
|
183
188
|
let apps: OrgApp[] = [];
|
|
184
189
|
let ttl = EMPTY_TTL_MS;
|
|
190
|
+
const serviceOrgId = opts?.serviceOrgId?.trim();
|
|
191
|
+
if (serviceOrgId) {
|
|
192
|
+
const serviceCacheKey = serviceScopedCacheKey(origin, serviceOrgId);
|
|
193
|
+
const cached = cache.get(serviceCacheKey);
|
|
194
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
195
|
+
return stripSelf(cached.apps);
|
|
196
|
+
}
|
|
197
|
+
cacheKey = serviceCacheKey;
|
|
198
|
+
}
|
|
185
199
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// peers already use. No new secret loading is invented here.
|
|
190
|
-
const { resolveA2ACallerAuth } = await import("../a2a/caller-auth.js");
|
|
191
|
-
const auth = await resolveA2ACallerAuth();
|
|
200
|
+
const auth = serviceOrgId
|
|
201
|
+
? await resolveOrgDirectoryServiceAuth(serviceOrgId)
|
|
202
|
+
: await resolveOrgDirectoryCallerAuth();
|
|
192
203
|
if (!auth.apiKey) {
|
|
193
204
|
// No signed token available (no A2A secret / no caller identity) — the
|
|
194
205
|
// directory requires the org bearer, so degrade silently to local-only.
|
|
195
206
|
return [];
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
if (!cacheKey) {
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
cacheKey = scopedCacheKey(origin, auth);
|
|
212
|
+
const cached = cache.get(cacheKey);
|
|
213
|
+
if (cached && cached.expiresAt > now) {
|
|
214
|
+
return stripSelf(cached.apps);
|
|
215
|
+
}
|
|
203
216
|
}
|
|
204
217
|
|
|
205
218
|
const res = await fetch(`${origin}/_agent-native/org/apps`, {
|
|
@@ -236,3 +249,49 @@ export async function fetchOrgApps(opts?: {
|
|
|
236
249
|
export function _resetOrgDirectoryCache(): void {
|
|
237
250
|
cache.clear();
|
|
238
251
|
}
|
|
252
|
+
|
|
253
|
+
async function resolveOrgDirectoryCallerAuth(): Promise<{
|
|
254
|
+
apiKey?: string;
|
|
255
|
+
userEmail?: string;
|
|
256
|
+
orgId?: string;
|
|
257
|
+
orgDomain?: string;
|
|
258
|
+
}> {
|
|
259
|
+
// Reuse the existing A2A caller-auth: it reads userEmail + orgId from the
|
|
260
|
+
// request context, loads the org A2A secret via getOrgA2ASecret (falling
|
|
261
|
+
// back to the global A2A_SECRET env), and signs the same bearer JWT A2A
|
|
262
|
+
// peers already use. No new secret loading is invented for normal callers.
|
|
263
|
+
const { resolveA2ACallerAuth } = await import("../a2a/caller-auth.js");
|
|
264
|
+
return resolveA2ACallerAuth();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function resolveOrgDirectoryServiceAuth(orgId: string): Promise<{
|
|
268
|
+
apiKey?: string;
|
|
269
|
+
userEmail?: string;
|
|
270
|
+
orgId?: string;
|
|
271
|
+
orgDomain?: string;
|
|
272
|
+
}> {
|
|
273
|
+
const trimmedOrgId = orgId.trim();
|
|
274
|
+
if (!trimmedOrgId) return {};
|
|
275
|
+
let orgDomain: string | undefined;
|
|
276
|
+
let orgSecret: string | undefined;
|
|
277
|
+
try {
|
|
278
|
+
const { getOrgDomain, getOrgA2ASecret } = await import("../org/context.js");
|
|
279
|
+
orgDomain = (await getOrgDomain(trimmedOrgId)) ?? undefined;
|
|
280
|
+
orgSecret = (await getOrgA2ASecret(trimmedOrgId)) ?? undefined;
|
|
281
|
+
} catch {}
|
|
282
|
+
try {
|
|
283
|
+
const [{ signA2AToken }, { serviceIdentityEmail }] = await Promise.all([
|
|
284
|
+
import("../a2a/client.js"),
|
|
285
|
+
import("./connect-store.js"),
|
|
286
|
+
]);
|
|
287
|
+
const userEmail = serviceIdentityEmail("mcp-client", trimmedOrgId);
|
|
288
|
+
const apiKey = await signA2AToken(userEmail, orgDomain, orgSecret, {
|
|
289
|
+
expiresIn: "5m",
|
|
290
|
+
preferGlobalSecret: !orgSecret,
|
|
291
|
+
extraClaims: { org_id: trimmedOrgId },
|
|
292
|
+
});
|
|
293
|
+
return { apiKey, userEmail, orgId: trimmedOrgId, orgDomain };
|
|
294
|
+
} catch {
|
|
295
|
+
return { orgId: trimmedOrgId, orgDomain };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -103,6 +103,14 @@ function deriveRequestMeta(event: H3Event): MCPRequestMeta {
|
|
|
103
103
|
fullCatalogHeader === "1" ||
|
|
104
104
|
fullCatalogHeader === "true" ||
|
|
105
105
|
fullCatalogHeader === "yes";
|
|
106
|
+
const inlineAppsHeader = getRequestHeader(
|
|
107
|
+
event,
|
|
108
|
+
"x-agent-native-mcp-inline-apps",
|
|
109
|
+
)?.toLowerCase();
|
|
110
|
+
const inlineAppsRequested =
|
|
111
|
+
inlineAppsHeader === "1" ||
|
|
112
|
+
inlineAppsHeader === "true" ||
|
|
113
|
+
inlineAppsHeader === "yes";
|
|
106
114
|
const basePath = getConfiguredAppBasePath();
|
|
107
115
|
return {
|
|
108
116
|
origin,
|
|
@@ -111,6 +119,7 @@ function deriveRequestMeta(event: H3Event): MCPRequestMeta {
|
|
|
111
119
|
clientName,
|
|
112
120
|
clientHint,
|
|
113
121
|
...(fullCatalog ? { fullCatalog } : {}),
|
|
122
|
+
...(inlineAppsRequested ? { inlineMcpApps: true } : {}),
|
|
114
123
|
};
|
|
115
124
|
}
|
|
116
125
|
|
|
@@ -357,6 +366,11 @@ export async function handleMcpRequest(
|
|
|
357
366
|
const server = await createMCPServerForRequest(config, authResult.identity, {
|
|
358
367
|
...requestMeta,
|
|
359
368
|
fullSurface: authResult.fullSurface === true,
|
|
369
|
+
inlineMcpApps:
|
|
370
|
+
requestMeta.inlineMcpApps === true &&
|
|
371
|
+
authResult.identity?.firstPartyMcp === true
|
|
372
|
+
? true
|
|
373
|
+
: undefined,
|
|
360
374
|
// When the caller minted their token with --full-catalog (catalog_scope:
|
|
361
375
|
// "full" JWT claim), bypass the connector-catalog tier filter.
|
|
362
376
|
...(authResult.fullCatalog === true ? { fullCatalog: true } : {}),
|