@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.
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +13 -9
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +69 -33
- package/corpus/templates/calendar/app/root.tsx +0 -1
- package/corpus/templates/clips/app/root.tsx +0 -1
- package/corpus/templates/content/app/root.tsx +0 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +21 -0
- package/dist/deploy/build.js +185 -10
- package/dist/jobs/background-automation-runner.d.ts +1 -1
- package/dist/jobs/background-automation-runner.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +4 -0
- package/dist/jobs/scheduler-health.js +33 -0
- package/dist/localization/server.d.ts +0 -1
- package/dist/localization/server.js +3 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/routes.d.ts +11 -0
- package/dist/mcp-client/routes.js +26 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/mcp-glue.js +12 -3
- package/dist/server/agent-chat-plugin.js +73 -48
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/http-response-telemetry.js +112 -5
- package/dist/server/release-migrations.js +2 -0
- package/dist/server/ssr-handler.js +8 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +54 -3
- package/dist/vite/client.js +5 -1
- package/package.json +1 -1
- 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
|
|
@@ -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
|
-
|
|
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;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -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
|
-
|
|
22
|
-
|
|
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,
|
|
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
|
-
|
|
313
|
-
|
|
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
|
-
|
|
329
|
-
|
|
316
|
+
else if (process.env.DEBUG) {
|
|
317
|
+
console.log("[mcp-client] no configured MCP servers — skipping MCP tools");
|
|
330
318
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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:
|
|
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
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
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
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
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 {};
|
package/dist/server/auth.js
CHANGED
|
@@ -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,
|