@agent-native/core 0.146.5 → 0.146.7

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 (38) hide show
  1. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +13 -9
  2. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +69 -33
  3. package/corpus/templates/calendar/app/root.tsx +0 -1
  4. package/corpus/templates/clips/app/root.tsx +0 -1
  5. package/corpus/templates/content/app/root.tsx +0 -1
  6. package/dist/collab/routes.d.ts +1 -1
  7. package/dist/collab/struct-routes.d.ts +1 -1
  8. package/dist/deploy/build.d.ts +21 -0
  9. package/dist/deploy/build.js +185 -10
  10. package/dist/jobs/background-automation-runner.d.ts +1 -1
  11. package/dist/jobs/background-automation-runner.js +1 -1
  12. package/dist/jobs/scheduler-health.d.ts +4 -0
  13. package/dist/jobs/scheduler-health.js +33 -0
  14. package/dist/localization/server.d.ts +0 -1
  15. package/dist/localization/server.js +3 -1
  16. package/dist/mcp-client/index.d.ts +1 -1
  17. package/dist/mcp-client/index.js +1 -1
  18. package/dist/mcp-client/routes.d.ts +11 -0
  19. package/dist/mcp-client/routes.js +26 -1
  20. package/dist/notifications/routes.d.ts +1 -1
  21. package/dist/observability/routes.d.ts +5 -5
  22. package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
  23. package/dist/provider-api/actions/provider-api.d.ts +5 -5
  24. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  25. package/dist/resources/handlers.d.ts +1 -1
  26. package/dist/secrets/routes.d.ts +9 -9
  27. package/dist/server/agent-chat/mcp-glue.js +12 -3
  28. package/dist/server/agent-chat-plugin.js +73 -48
  29. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  30. package/dist/server/auth.js +7 -0
  31. package/dist/server/http-response-telemetry.js +112 -5
  32. package/dist/server/release-migrations.js +2 -0
  33. package/dist/server/ssr-handler.js +8 -0
  34. package/dist/server/transcribe-voice.d.ts +1 -1
  35. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +54 -3
  36. package/dist/vite/client.js +5 -1
  37. package/package.json +1 -1
  38. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +54 -3
@@ -22,6 +22,17 @@ import type { McpConfig } from "./config.js";
22
22
  import { type McpClientManager } from "./manager.js";
23
23
  import { type RemoteMcpScope } from "./remote-store.js";
24
24
  export { formatMcpConnectError } from "./errors.js";
25
+ /**
26
+ * The settings table backing remote/built-in MCP servers could not be read.
27
+ *
28
+ * Distinct from `buildMergedConfig()` returning `null`, which means the app is
29
+ * genuinely configured with zero MCP servers. Coercing an unreachable database
30
+ * into an empty settings map made every caller report "no MCP servers
31
+ * configured" while the real answer was "could not read the configuration".
32
+ */
33
+ export declare class McpConfigUnreadableError extends Error {
34
+ constructor(cause: unknown);
35
+ }
25
36
  export interface ClientServer {
26
37
  id: string;
27
38
  scope: RemoteMcpScope;
@@ -24,6 +24,7 @@ import { getSession } from "../server/auth.js";
24
24
  import { getH3App } from "../server/framework-request-handler.js";
25
25
  import { readBody } from "../server/h3-helpers.js";
26
26
  import { runWithRequestContext } from "../server/request-context.js";
27
+ import { shouldDisableInProcessSweeps } from "../server/sweep-runtime.js";
27
28
  import { getAllSettings, getSettingsEmitter } from "../settings/store.js";
28
29
  import { areBuiltinMcpCapabilitiesSupported, BUILTIN_MCP_CAPABILITIES, getBuiltinMcpCapability, isBuiltinMcpCapabilityAvailable, listSupportedBuiltinMcpCapabilities, normalizeBuiltinMcpCapabilityIds, toBuiltinMcpServerConfig, } from "./builtin-capabilities.js";
29
30
  import { builtinMcpCapabilitiesSettingsKey, listEnabledBuiltinMcpCapabilities, setBuiltinMcpCapabilityEnabled, setEnabledBuiltinMcpCapabilities, } from "./builtin-store.js";
@@ -36,6 +37,21 @@ import { addRemoteServer, listRemoteServers, mergedConfigKey, removeRemoteServer
36
37
  import { isMcpToolAllowedForRequest } from "./visibility.js";
37
38
  import { loadWorkspaceMcpServers } from "./workspace-servers.js";
38
39
  export { formatMcpConnectError } from "./errors.js";
40
+ /**
41
+ * The settings table backing remote/built-in MCP servers could not be read.
42
+ *
43
+ * Distinct from `buildMergedConfig()` returning `null`, which means the app is
44
+ * genuinely configured with zero MCP servers. Coercing an unreachable database
45
+ * into an empty settings map made every caller report "no MCP servers
46
+ * configured" while the real answer was "could not read the configuration".
47
+ */
48
+ export class McpConfigUnreadableError extends Error {
49
+ constructor(cause) {
50
+ super(`Could not read MCP configuration from settings: ${cause?.message ?? cause}`);
51
+ this.name = "McpConfigUnreadableError";
52
+ this.cause = cause;
53
+ }
54
+ }
39
55
  /** Redact obvious auth header values before sending to the client. */
40
56
  function redactHeaders(headers) {
41
57
  if (!headers)
@@ -114,7 +130,10 @@ export function builtinMergedConfigKey(scope, capability, ownerId) {
114
130
  export async function buildMergedConfig() {
115
131
  const base = loadMcpConfig() ?? autoDetectMcpConfig();
116
132
  const servers = { ...(base?.servers ?? {}) };
117
- const all = await getAllSettings().catch(() => ({}));
133
+ const all = await getAllSettings().catch((err) => {
134
+ console.warn(`[mcp-client] settings read failed: ${err?.message ?? err}`);
135
+ throw new McpConfigUnreadableError(err);
136
+ });
118
137
  for (const [fullKey, value] of Object.entries(all)) {
119
138
  const userMatch = /^u:([^:]+):mcp-servers-remote$/.exec(fullKey);
120
139
  const orgMatch = /^o:([^:]+):mcp-servers-remote$/.exec(fullKey);
@@ -222,6 +241,12 @@ export function startMcpConfigRefresh(manager) {
222
241
  const intervalMs = mcpConfigRefreshIntervalMs();
223
242
  if (intervalMs <= 0 || typeof setInterval !== "function")
224
243
  return null;
244
+ // Billed per warm container on serverless, and the first tick always runs a
245
+ // full settings scan because `settingsDirty` starts true. Request-driven
246
+ // reconfigures (`waitUntilReady` on the MCP routes, `refreshGlobalMcpManager`)
247
+ // already cover config changes there, and a fresh container re-reads config.
248
+ if (shouldDisableInProcessSweeps())
249
+ return null;
225
250
  let currentSignature = sortedConfigSignature(manager.getConfig());
226
251
  let refreshing = false;
227
252
  // `buildMergedConfig` reads the entire settings table just to diff a
@@ -28,6 +28,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- error?: undefined;
32
31
  ok: boolean;
32
+ error?: undefined;
33
33
  }>>;
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
45
+ ok?: undefined;
44
46
  summary: import("./types.js").TraceSummary;
45
47
  spans: import("./types.js").TraceSpan[];
46
48
  id?: undefined;
49
+ } | {
47
50
  error?: undefined;
48
51
  ok?: undefined;
49
- } | {
50
52
  summary?: undefined;
51
53
  spans?: undefined;
52
54
  id: string;
53
- error?: undefined;
54
- ok?: undefined;
55
55
  } | {
56
+ ok?: undefined;
56
57
  summary?: undefined;
57
58
  spans?: undefined;
58
59
  id?: undefined;
59
60
  error: any;
60
- ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
66
  ok: boolean;
66
- error?: undefined;
67
67
  }>>;
@@ -75,8 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
75
75
  user: "user";
76
76
  }>>;
77
77
  }, z.core.$strip>>, {
78
- id?: undefined;
79
78
  deleted?: undefined;
79
+ id?: undefined;
80
80
  providers: {
81
81
  id: string;
82
82
  label: string;
@@ -93,10 +93,10 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
93
93
  label?: undefined;
94
94
  message?: undefined;
95
95
  } | {
96
- id?: undefined;
97
96
  deleted?: undefined;
98
- providers?: undefined;
99
97
  count?: undefined;
98
+ id?: undefined;
99
+ providers?: undefined;
100
100
  found: boolean;
101
101
  provider: import("../custom-registry.js").CustomProviderConfig;
102
102
  registered?: undefined;
@@ -104,8 +104,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
104
104
  message?: undefined;
105
105
  } | {
106
106
  deleted?: undefined;
107
- providers?: undefined;
108
107
  count?: undefined;
108
+ providers?: undefined;
109
109
  provider?: undefined;
110
110
  found: boolean;
111
111
  id: string;
@@ -113,8 +113,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
113
113
  label?: undefined;
114
114
  message?: undefined;
115
115
  } | {
116
- providers?: undefined;
117
116
  count?: undefined;
117
+ providers?: undefined;
118
118
  provider?: undefined;
119
119
  found?: undefined;
120
120
  deleted: boolean;
@@ -124,8 +124,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
124
124
  message?: undefined;
125
125
  } | {
126
126
  deleted?: undefined;
127
- providers?: undefined;
128
127
  count?: undefined;
128
+ providers?: undefined;
129
129
  provider?: undefined;
130
130
  found?: undefined;
131
131
  registered: boolean;
@@ -311,10 +311,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
311
311
  notes?: string | undefined;
312
312
  scope?: "org" | "user" | undefined;
313
313
  }, {
314
+ message?: undefined;
314
315
  id?: undefined;
315
316
  provider?: undefined;
316
317
  deleted?: undefined;
317
- message?: undefined;
318
318
  providers: {
319
319
  id: string;
320
320
  label: string;
@@ -329,29 +329,29 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
329
329
  registered?: undefined;
330
330
  label?: undefined;
331
331
  } | {
332
- id?: undefined;
332
+ message?: undefined;
333
333
  count?: undefined;
334
+ id?: undefined;
334
335
  deleted?: undefined;
335
- message?: undefined;
336
336
  providers?: undefined;
337
337
  found: boolean;
338
338
  provider: import("../custom-registry.js").CustomProviderConfig;
339
339
  registered?: undefined;
340
340
  label?: undefined;
341
341
  } | {
342
+ message?: undefined;
342
343
  count?: undefined;
343
344
  provider?: undefined;
344
345
  deleted?: undefined;
345
- message?: undefined;
346
346
  providers?: undefined;
347
347
  found: boolean;
348
348
  id: string;
349
349
  registered?: undefined;
350
350
  label?: undefined;
351
351
  } | {
352
+ message?: undefined;
352
353
  count?: undefined;
353
354
  provider?: undefined;
354
- message?: undefined;
355
355
  providers?: undefined;
356
356
  found?: undefined;
357
357
  deleted: boolean;
@@ -73,6 +73,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
73
73
  offset?: unknown;
74
74
  limit?: unknown;
75
75
  }, {
76
+ deleted?: undefined;
76
77
  jobs: {
77
78
  id: string;
78
79
  name: string;
@@ -83,7 +84,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
83
84
  updatedAt: string;
84
85
  }[];
85
86
  total: number;
86
- deleted?: undefined;
87
87
  jobId?: undefined;
88
88
  } | {
89
89
  jobs?: undefined;
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
91
91
  deleted: boolean;
92
92
  jobId: string;
93
93
  } | {
94
+ deleted?: undefined;
94
95
  jobs?: undefined;
95
96
  total?: undefined;
96
- deleted?: undefined;
97
97
  jobId?: undefined;
98
98
  hits: Record<string, unknown>[];
99
99
  offset: number;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- ok?: undefined;
52
51
  error: string;
52
+ ok?: undefined;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- ok?: undefined;
38
37
  status?: undefined;
38
+ ok?: undefined;
39
39
  } | {
40
- error?: undefined;
41
40
  ok: boolean;
42
41
  status: string;
42
+ error?: undefined;
43
43
  } | {
44
- ok?: undefined;
45
44
  error: string;
46
45
  removed?: undefined;
46
+ ok?: undefined;
47
47
  } | {
48
- error?: undefined;
49
48
  ok: boolean;
50
49
  removed: boolean;
50
+ error?: undefined;
51
51
  }>>;
52
52
  /**
53
53
  * POST /_agent-native/secrets/:key/test — validate an optional candidate value
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
- ok?: undefined;
58
57
  error: string;
59
58
  note?: undefined;
59
+ ok?: undefined;
60
60
  } | {
61
- error?: undefined;
62
61
  ok: boolean;
63
62
  note?: undefined;
64
- } | {
65
63
  error?: undefined;
64
+ } | {
66
65
  ok: boolean;
67
66
  note: string;
67
+ error?: undefined;
68
68
  } | {
69
69
  note?: undefined;
70
70
  ok: boolean;
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
95
95
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
96
96
  error: string;
97
97
  } | {
98
- error?: undefined;
99
98
  ok: boolean;
100
99
  key: string;
101
- } | {
102
100
  error?: undefined;
101
+ } | {
103
102
  ok: boolean;
104
103
  removed: boolean;
104
+ error?: undefined;
105
105
  }>>;
@@ -1,5 +1,5 @@
1
1
  import { defineEventHandler, getMethod, setResponseHeader, setResponseStatus, } from "h3";
2
- import { buildMergedConfig, getHubStatus, } from "../../mcp-client/index.js";
2
+ import { buildMergedConfig, getHubStatus, McpConfigUnreadableError, } from "../../mcp-client/index.js";
3
3
  import { getH3App } from "../framework-request-handler.js";
4
4
  // ---------------------------------------------------------------------------
5
5
  // MCP client glue — a shared manager reference + a /_agent-native/mcp/status
@@ -18,8 +18,17 @@ export async function refreshGlobalMcpManager() {
18
18
  const manager = getGlobalMcpManager();
19
19
  if (!manager)
20
20
  return false;
21
- await manager.reconfigure(await buildMergedConfig());
22
- return true;
21
+ try {
22
+ await manager.reconfigure(await buildMergedConfig());
23
+ return true;
24
+ }
25
+ catch (err) {
26
+ if (err instanceof McpConfigUnreadableError) {
27
+ console.warn(`[mcp-client] global refresh skipped: ${err.message}`);
28
+ return false;
29
+ }
30
+ throw err;
31
+ }
23
32
  }
24
33
  export function mountMcpHubStatusRoute(nitroApp) {
25
34
  const mountedApps = (globalThis.__agentNativeMcpHubStatusMountedApps ??= new WeakSet());
@@ -24,11 +24,11 @@ import { runChatThreadDataMigrations } from "../chat-threads/migrations.js";
24
24
  import { adoptThreadScopeIfUnscoped, createThread, forkThread, getThread, registerChatThreadsShareable, resolveRunThreadScope, resolveThreadAccess, listThreads, searchThreads, renameThread, createThreadShareLink, getThreadByShareToken, getThreadShareState, revokeThreadShareLink, setThreadArchived, setThreadPinned, setThreadScope, updateThreadData, withThreadDataLock, deleteThread, setThreadQueuedMessages, setThreadSourceIfMissing, } from "../chat-threads/store.js";
25
25
  import { isCheckpointRestorePath } from "../checkpoints/route-match.js";
26
26
  import { createDbAdminAgentTools } from "../db-admin/agent-tools.js";
27
- import { isTransientDatabaseError } from "../db/client.js";
27
+ import { isProductionServerlessFunctionRuntime, isTransientDatabaseError, } from "../db/client.js";
28
28
  import { filterFrameworkToolGroups, resolveFrameworkTools, } from "../framework-tools.js";
29
29
  import { verifyInternalToken, extractBearerToken, } from "../integrations/internal-token.js";
30
30
  import { RECURRING_JOBS_SWEEP_PATH, RECURRING_JOBS_SWEEP_TOKEN_SUBJECT, } from "../jobs/scheduler-dispatch.js";
31
- import { McpClientManager, loadMcpConfig, autoDetectMcpConfig, mcpToolsToActionEntries, syncMcpActionEntries, mountMcpServersRoutes, mountMcpHubRoutes, buildMergedConfig, startMcpConfigRefresh, getHubStatus, isHubServeEnabled, } from "../mcp-client/index.js";
31
+ import { McpClientManager, mcpToolsToActionEntries, syncMcpActionEntries, mountMcpServersRoutes, mountMcpHubRoutes, buildMergedConfig, startMcpConfigRefresh, getHubStatus, isHubServeEnabled, } from "../mcp-client/index.js";
32
32
  import { setProgressPreListHook } from "../progress/store.js";
33
33
  import { getSkillNameFromPath } from "../resources/metadata.js";
34
34
  import { resourceList, resourceListAccessible, resourceGet, ensurePersonalDefaults, SHARED_OWNER, WORKSPACE_OWNER, } from "../resources/store.js";
@@ -309,36 +309,43 @@ export function createAgentChatPlugin(options) {
309
309
  const mcpActionEntries = {};
310
310
  let mcpInitializationPromise = null;
311
311
  const initializeMcpManager = async () => {
312
- let mcpConfig = await buildMergedConfig().catch((err) => {
313
- console.warn(`[mcp-client] buildMergedConfig failed: ${err?.message ?? err}`);
314
- return null;
315
- });
316
- if (!mcpConfig) {
317
- mcpConfig = loadMcpConfig() ?? autoDetectMcpConfig();
318
- if (mcpConfig?.source) {
319
- console.log(`[mcp-client] loaded config from ${mcpConfig.source} (${Object.keys(mcpConfig.servers).length} server(s))`);
320
- }
321
- else if (process.env.DEBUG) {
322
- console.log("[mcp-client] no configured MCP servers — skipping MCP tools");
323
- }
324
- }
325
- else if (mcpConfig.source) {
312
+ const mcpConfig = await buildMergedConfig();
313
+ if (mcpConfig?.source) {
326
314
  console.log(`[mcp-client] merged config (${Object.keys(mcpConfig.servers).length} server(s), source: ${mcpConfig.source})`);
327
315
  }
328
- try {
329
- await mcpManager.reconfigure(mcpConfig);
316
+ else if (process.env.DEBUG) {
317
+ console.log("[mcp-client] no configured MCP servers — skipping MCP tools");
330
318
  }
331
- catch (err) {
332
- console.warn(`[mcp-client] initialization failed: ${err?.message ?? err}. Continuing without MCP tools.`);
333
- }
334
- finally {
335
- startMcpConfigRefresh(mcpManager);
319
+ await mcpManager.reconfigure(mcpConfig);
320
+ startMcpConfigRefresh(mcpManager);
321
+ };
322
+ /**
323
+ * Start MCP initialization at most once, and return the run in flight.
324
+ *
325
+ * On a serverless function nothing kicks this off at boot (see the
326
+ * `isProductionServerlessFunctionRuntime` gate below), so every surface
327
+ * that actually consumes MCP tools must await this or the manager stays
328
+ * empty for the life of the container.
329
+ */
330
+ const ensureMcpInitialized = () => {
331
+ if (!mcpInitializationPromise) {
332
+ mcpInitializationPromise = initializeMcpManager().catch((err) => {
333
+ // Do not cache a settings outage as a successful empty manager;
334
+ // the next MCP-consuming request must retry the configuration read.
335
+ mcpInitializationPromise = null;
336
+ throw err;
337
+ });
336
338
  }
339
+ return mcpInitializationPromise;
337
340
  };
338
- const getJobMcpActionEntries = (job) => {
341
+ const getJobMcpActionEntries = async (job) => {
339
342
  const requested = job?.meta.mcpTools ?? [];
340
343
  if (requested.length === 0)
341
344
  return {};
345
+ // Background action suppliers may be async so event-triggered and
346
+ // scheduled runs can await lazy MCP hydration on serverless cold
347
+ // starts. Runs without requested MCP tools still skip this work.
348
+ await ensureMcpInitialized();
342
349
  const entries = mcpToolsToActionEntries(mcpManager, {
343
350
  toolNames: requested,
344
351
  });
@@ -354,7 +361,7 @@ export function createAgentChatPlugin(options) {
354
361
  mountMcpServersRoutes(nitroApp, mcpManager, {
355
362
  // Serialize an unusually early settings mutation behind the initial
356
363
  // config snapshot so stale startup data cannot overwrite the write.
357
- waitUntilReady: () => mcpInitializationPromise ?? Promise.resolve(),
364
+ waitUntilReady: ensureMcpInitialized,
358
365
  });
359
366
  // Hub-serve: expose org-scope servers to other agent-native apps in the
360
367
  // workspace when `AGENT_NATIVE_MCP_HUB_TOKEN` is set (dispatch, by
@@ -825,25 +832,28 @@ export function createAgentChatPlugin(options) {
825
832
  // background surface. Interactive-only tools stay out of it, while
826
833
  // shared capabilities such as call-agent and core-send-email cannot
827
834
  // drift independently between the two background entry points.
828
- const getBackgroundActionEntries = (automation) => ({
829
- ...templateScripts,
830
- ...resourceScripts,
831
- ...docsScripts,
832
- ...(lazyContext ? frameworkContextTool : {}),
833
- ...urlTools,
834
- ...chatScripts,
835
- ...callAgentScript,
836
- ...jobTools,
837
- ...automationTools,
838
- ...notificationTools,
839
- ...progressTools,
840
- ...fetchTool,
841
- ...webSearchTool,
842
- ...toolActions,
843
- ...backgroundCoreEmailTools,
844
- ...coreAttachmentTools,
845
- ...getJobMcpActionEntries(automation),
846
- });
835
+ const getBackgroundActionEntries = async (automation) => {
836
+ const mcpActions = await getJobMcpActionEntries(automation);
837
+ return {
838
+ ...templateScripts,
839
+ ...resourceScripts,
840
+ ...docsScripts,
841
+ ...(lazyContext ? frameworkContextTool : {}),
842
+ ...urlTools,
843
+ ...chatScripts,
844
+ ...callAgentScript,
845
+ ...jobTools,
846
+ ...automationTools,
847
+ ...notificationTools,
848
+ ...progressTools,
849
+ ...fetchTool,
850
+ ...webSearchTool,
851
+ ...toolActions,
852
+ ...backgroundCoreEmailTools,
853
+ ...coreAttachmentTools,
854
+ ...mcpActions,
855
+ };
856
+ };
847
857
  // -----------------------------------------------------------------------
848
858
  // Production code-execution mode resolution.
849
859
  //
@@ -4514,6 +4524,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
4514
4524
  // the background worker), so both go through identical context + handler
4515
4525
  // selection.
4516
4526
  const invokeAgentChatHandler = async (event) => {
4527
+ // Chat is the main MCP consumer, and on serverless nothing hydrated the
4528
+ // manager at boot. Awaiting here trades first-chat latency for tools
4529
+ // that are actually present instead of a silently MCP-less run.
4530
+ await ensureMcpInitialized();
4517
4531
  // Resolve per-request auth context.
4518
4532
  const ownerContext = await resolveOwnerContext(event);
4519
4533
  return runWithAgentRunContext({
@@ -4851,6 +4865,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
4851
4865
  };
4852
4866
  }
4853
4867
  try {
4868
+ // Jobs may request MCP tools, and `getActions` is synchronous —
4869
+ // hydrate before the sweep so a serverless container that never
4870
+ // eagerly initialized still resolves them.
4871
+ await ensureMcpInitialized();
4854
4872
  await processRecurringJobs(schedulerDeps);
4855
4873
  return { ok: true };
4856
4874
  }
@@ -4913,10 +4931,17 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
4913
4931
  setInterval(() => void sweep(), 30_000);
4914
4932
  })();
4915
4933
  }
4916
- mcpInitializationPromise = initializeMcpManager().catch((err) => {
4917
- console.warn(`[mcp-client] deferred initialization failed: ${err?.message ?? err}`);
4918
- });
4919
- void mcpInitializationPromise;
4934
+ // Long-lived runtimes hydrate MCP once at boot. Serverless functions must
4935
+ // not: nothing awaits this, so a settings scan plus third-party MCP
4936
+ // handshakes run on EVERY cold start of every app — including requests
4937
+ // that never touch MCP — and outlive the response on a runtime that
4938
+ // freezes after responding. There, `ensureMcpInitialized()` is driven by
4939
+ // the surfaces that consume MCP tools instead.
4940
+ if (!isProductionServerlessFunctionRuntime()) {
4941
+ void ensureMcpInitialized().catch((err) => {
4942
+ console.warn(`[mcp-client] eager initialization failed: ${err?.message ?? err}`);
4943
+ });
4944
+ }
4920
4945
  // ─── Agent Teams orphan sweep ─────────────────────────────────────
4921
4946
  // Re-fires stuck/queued dispatches when the browser is closed and the
4922
4947
  // RunsTray's per-user reconciliation never triggers. Runs every 2 minutes
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
- error?: undefined;
31
30
  ok: boolean;
32
31
  key: string;
33
32
  baseUrlKey?: string;
34
33
  scope: AgentEngineApiKeyScope;
34
+ error?: undefined;
35
35
  }>>;
36
36
  export {};
@@ -1317,6 +1317,13 @@ function createAuthGuardFn() {
1317
1317
  if (p === "/_agent-native/integrations/process-a2a-continuation") {
1318
1318
  return;
1319
1319
  }
1320
+ // Scheduled recurring-job sweeps are self-fired by the platform scheduler
1321
+ // through the durable background function and authenticate with the same
1322
+ // short-lived HMAC token as the other internal processors. They do not
1323
+ // carry a browser session, so let the route perform its own token check.
1324
+ if (p === "/_agent-native/jobs/_process-sweep") {
1325
+ return;
1326
+ }
1320
1327
  // Agent Teams durable sub-agent processor. Self-fired by `spawnTask` to run
1321
1328
  // a queued sub-agent in a fresh function invocation; authenticity is
1322
1329
  // verified by the same HMAC internal-token scheme plus an atomic SQL claim,