@agent-vm/openclaw-mcp-portal-plugin 0.0.80 → 0.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +32 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpPortalCallPolicyDecision, McpPortalConfig, ResolvedMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
2
|
+
import { ApprovalTokenCallDigest } from "@agent-vm/mcp-portal/portal-auth/hmac-token";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
4
5
|
|
|
@@ -49,6 +50,7 @@ type OpenClawApprovalResolution = 'allow-always' | 'allow-once' | 'cancelled' |
|
|
|
49
50
|
interface OpenClawBeforeToolCallResult {
|
|
50
51
|
readonly block?: boolean;
|
|
51
52
|
readonly blockReason?: string;
|
|
53
|
+
readonly params?: Record<string, unknown>;
|
|
52
54
|
readonly requireApproval?: {
|
|
53
55
|
readonly description: string;
|
|
54
56
|
readonly onResolution?: (decision: OpenClawApprovalResolution) => Promise<void> | void;
|
|
@@ -147,7 +149,14 @@ declare const pluginEntry: {
|
|
|
147
149
|
//#endregion
|
|
148
150
|
//#region src/portal-plugin-runtime-state.d.ts
|
|
149
151
|
interface PortalPluginRuntimeState {
|
|
152
|
+
readonly consumeApprovalTokenId: (agentId: string, jti: string, expiresAtMs: number) => {
|
|
153
|
+
readonly ok: true;
|
|
154
|
+
} | {
|
|
155
|
+
readonly ok: false;
|
|
156
|
+
readonly reason: 'replay-cache-full' | 'replayed';
|
|
157
|
+
};
|
|
150
158
|
readonly configDir: string;
|
|
159
|
+
readonly getApprovalHmacKey: () => Buffer;
|
|
151
160
|
readonly getLoadedPortalConfig: () => McpPortalConfig | null;
|
|
152
161
|
readonly getPortalUnavailableReason: () => string | null;
|
|
153
162
|
readonly loadPortalConfig: () => Promise<McpPortalConfig>;
|
|
@@ -165,22 +174,6 @@ interface CreateBeforePromptBuildHandlerProps {
|
|
|
165
174
|
}
|
|
166
175
|
declare function createBeforePromptBuildHandler(props: CreateBeforePromptBuildHandlerProps): (event: OpenClawBeforePromptBuildEvent, context: OpenClawPluginHookContext) => Promise<OpenClawPromptHookResult | undefined>;
|
|
167
176
|
//#endregion
|
|
168
|
-
//#region src/before-tool-call-handler.d.ts
|
|
169
|
-
interface CreateBeforeToolCallHandlerProps {
|
|
170
|
-
readonly logger?: {
|
|
171
|
-
readonly warn?: (message: string) => void;
|
|
172
|
-
};
|
|
173
|
-
readonly runtimeState: PortalPluginRuntimeState;
|
|
174
|
-
}
|
|
175
|
-
declare function createBeforeToolCallHandler(props: CreateBeforeToolCallHandlerProps): (event: OpenClawBeforeToolCallEvent, context: OpenClawPluginHookContext) => Promise<OpenClawBeforeToolCallResult | undefined>;
|
|
176
|
-
//#endregion
|
|
177
|
-
//#region src/portal-config.d.ts
|
|
178
|
-
declare const portalPluginConfigSchema: z.ZodObject<{
|
|
179
|
-
configDir: z.ZodString;
|
|
180
|
-
}, z.core.$strict>;
|
|
181
|
-
type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;
|
|
182
|
-
declare function parsePortalConfig(value: unknown): PortalPluginConfig;
|
|
183
|
-
//#endregion
|
|
184
177
|
//#region src/portal-tool-policy.d.ts
|
|
185
178
|
interface PortalCallRequest {
|
|
186
179
|
readonly arguments: Record<string, unknown>;
|
|
@@ -197,6 +190,29 @@ declare function profilePortalCallDecision(profile: ResolvedMcpPortalProfile, ca
|
|
|
197
190
|
readonly toolName: string;
|
|
198
191
|
}): McpPortalCallPolicyDecision;
|
|
199
192
|
//#endregion
|
|
193
|
+
//#region src/before-tool-call-handler.d.ts
|
|
194
|
+
interface CreateBeforeToolCallHandlerProps {
|
|
195
|
+
readonly logger?: {
|
|
196
|
+
readonly error?: (message: string) => void;
|
|
197
|
+
readonly warn?: (message: string) => void;
|
|
198
|
+
};
|
|
199
|
+
readonly resolveApprovalTokenCallDigests?: (props: {
|
|
200
|
+
readonly agentId: string;
|
|
201
|
+
readonly approvalCalls: readonly PortalCallRequest[];
|
|
202
|
+
readonly context: OpenClawPluginHookContext;
|
|
203
|
+
readonly params: Record<string, unknown>;
|
|
204
|
+
}) => Promise<readonly ApprovalTokenCallDigest[]>;
|
|
205
|
+
readonly runtimeState: PortalPluginRuntimeState;
|
|
206
|
+
}
|
|
207
|
+
declare function createBeforeToolCallHandler(props: CreateBeforeToolCallHandlerProps): (event: OpenClawBeforeToolCallEvent, context: OpenClawPluginHookContext) => Promise<OpenClawBeforeToolCallResult | undefined>;
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/portal-config.d.ts
|
|
210
|
+
declare const portalPluginConfigSchema: z.ZodObject<{
|
|
211
|
+
configDir: z.ZodString;
|
|
212
|
+
}, z.core.$strict>;
|
|
213
|
+
type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;
|
|
214
|
+
declare function parsePortalConfig(value: unknown): PortalPluginConfig;
|
|
215
|
+
//#endregion
|
|
200
216
|
//#region src/portal-prompt-context.d.ts
|
|
201
217
|
interface PortalPromptNamespaceSummary {
|
|
202
218
|
readonly namespace: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-plugin-api.ts","../src/plugin-registration.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-plugin-api.ts","../src/plugin-registration.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/portal-config.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { loadMcpConfig, loadMcpPortalConfig, mcpPortalCallPolicyDecision, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
2
|
-
import { createPortalCore, createUpstreamMcpClientRuntime, listPortalCoreToolDescriptors, redactCredentialText, resolveUpstreamServers } from "@agent-vm/mcp-portal/core";
|
|
2
|
+
import { createPortalCore, createPortalPolicyApprovalEvaluator, createUpstreamMcpClientRuntime, listPortalCoreToolDescriptors, redactCredentialText, resolveUpstreamServers } from "@agent-vm/mcp-portal/core";
|
|
3
|
+
import { hashCallArguments, signApprovalToken } from "@agent-vm/mcp-portal/portal-auth/hmac-token";
|
|
3
4
|
import { readFile } from "node:fs/promises";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { z } from "zod";
|
|
7
|
+
import { randomBytes } from "node:crypto";
|
|
6
8
|
//#region src/before-prompt-build-handler.ts
|
|
7
9
|
function createBeforePromptBuildHandler(props) {
|
|
8
10
|
return async (_event, context) => {
|
|
@@ -34,6 +36,8 @@ function profilePortalCallDecision(profile, call) {
|
|
|
34
36
|
}
|
|
35
37
|
//#endregion
|
|
36
38
|
//#region src/before-tool-call-handler.ts
|
|
39
|
+
const approvalPromptTimeoutMs = 6e4;
|
|
40
|
+
const approvalTokenLifetimeMs = 5 * 6e4;
|
|
37
41
|
function isObjectRecord$2(value) {
|
|
38
42
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
43
|
}
|
|
@@ -62,6 +66,35 @@ function parseCallRequests(params) {
|
|
|
62
66
|
}
|
|
63
67
|
return parsedCalls;
|
|
64
68
|
}
|
|
69
|
+
function fallbackApprovalTokenCallDigests(calls) {
|
|
70
|
+
return calls.map((call) => ({
|
|
71
|
+
argumentsHash: hashCallArguments(call.arguments),
|
|
72
|
+
namespace: call.namespace,
|
|
73
|
+
toolName: call.toolName
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
function approvalTokenForCallDigests(props) {
|
|
77
|
+
const nowMs = props.nowMs ?? Date.now();
|
|
78
|
+
return signApprovalToken({
|
|
79
|
+
agentId: props.agentId,
|
|
80
|
+
calls: props.callDigests,
|
|
81
|
+
expiresAtMs: nowMs + approvalTokenLifetimeMs,
|
|
82
|
+
issuedAtMs: nowMs,
|
|
83
|
+
key: props.key
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function redactApprovalPreviewValue(key, value) {
|
|
87
|
+
if (/token|secret|password|credential|api[-_]?key/iu.test(key)) return "[redacted]";
|
|
88
|
+
if (Array.isArray(value)) return value.map((entry) => redactApprovalPreviewValue(key, entry));
|
|
89
|
+
if (typeof value === "object" && value !== null) return Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, redactApprovalPreviewValue(entryKey, entryValue)]));
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
function approvalCallPreview(call) {
|
|
93
|
+
const redactedArguments = redactApprovalPreviewValue("arguments", call.arguments);
|
|
94
|
+
const serializedArguments = JSON.stringify(redactedArguments);
|
|
95
|
+
const preview = serializedArguments.length > 500 ? `${serializedArguments.slice(0, 497)}...` : serializedArguments;
|
|
96
|
+
return `${call.id}: ${call.namespace}.${call.toolName} args=${preview}`;
|
|
97
|
+
}
|
|
65
98
|
function createBeforeToolCallHandler(props) {
|
|
66
99
|
return async (event, context) => {
|
|
67
100
|
if (event.toolName !== "mcp_portal_call") return;
|
|
@@ -82,29 +115,59 @@ function createBeforeToolCallHandler(props) {
|
|
|
82
115
|
block: true,
|
|
83
116
|
blockReason: "mcp-portal: malformed portal call batch."
|
|
84
117
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
const disabledCalls = calls.filter((call) => !profileAllowsPortalCall(profile, call));
|
|
119
|
+
if (disabledCalls.length > 0) {
|
|
120
|
+
if (disabledCalls.length === calls.length) {
|
|
121
|
+
const call = disabledCalls[0];
|
|
122
|
+
return {
|
|
123
|
+
block: true,
|
|
124
|
+
blockReason: call === void 0 ? `policy: ${agentId} has no enabled MCP Portal calls in this batch` : `policy: ${agentId}/${call.namespace}/${call.toolName} not enabled`
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
89
129
|
const approvalCalls = [];
|
|
90
|
-
for (const call of calls)
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
for (const call of calls) if (profilePortalCallDecision(profile, call).kind === "requires_approval") approvalCalls.push(call);
|
|
131
|
+
if (approvalCalls.length === 0) return;
|
|
132
|
+
if (approvalCalls.length !== calls.length) return;
|
|
133
|
+
const toolNames = approvalCalls.map((call) => `${call.namespace}.${call.toolName}`).toSorted().join(", ");
|
|
134
|
+
let portalApprovalToken;
|
|
135
|
+
try {
|
|
136
|
+
const callDigests = await props.resolveApprovalTokenCallDigests?.({
|
|
137
|
+
agentId,
|
|
138
|
+
approvalCalls,
|
|
139
|
+
context,
|
|
140
|
+
params: event.params
|
|
141
|
+
}) ?? fallbackApprovalTokenCallDigests(approvalCalls);
|
|
142
|
+
if (callDigests.length !== approvalCalls.length) throw new Error(`prepared ${callDigests.length} approval token digests for ${approvalCalls.length} approval call(s)`);
|
|
143
|
+
portalApprovalToken = approvalTokenForCallDigests({
|
|
144
|
+
agentId,
|
|
145
|
+
callDigests,
|
|
146
|
+
key: props.runtimeState.getApprovalHmacKey()
|
|
147
|
+
});
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const message = `mcp-portal: failed to prepare approval token: ${error instanceof Error ? error.message : String(error)}`;
|
|
150
|
+
props.logger?.error?.(message);
|
|
151
|
+
return {
|
|
93
152
|
block: true,
|
|
94
|
-
blockReason:
|
|
153
|
+
blockReason: message
|
|
95
154
|
};
|
|
96
|
-
if (decision.kind === "requires_approval") approvalCalls.push(call);
|
|
97
155
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
156
|
+
const approvalPreview = approvalCalls.map(approvalCallPreview).join("\n");
|
|
157
|
+
return {
|
|
158
|
+
params: {
|
|
159
|
+
...event.params,
|
|
160
|
+
portalApprovalToken
|
|
161
|
+
},
|
|
162
|
+
requireApproval: {
|
|
163
|
+
description: `Allow MCP Portal batch for agent ${agentId}:\n${approvalPreview}`,
|
|
164
|
+
pluginId: "mcp-portal",
|
|
165
|
+
severity: "warning",
|
|
166
|
+
timeoutBehavior: "deny",
|
|
167
|
+
timeoutMs: approvalPromptTimeoutMs,
|
|
168
|
+
title: `MCP Portal batch: ${toolNames}`
|
|
169
|
+
}
|
|
170
|
+
};
|
|
108
171
|
};
|
|
109
172
|
}
|
|
110
173
|
//#endregion
|
|
@@ -159,6 +222,10 @@ function createPortalPluginRuntimeState(props) {
|
|
|
159
222
|
let loadedPortalConfig = null;
|
|
160
223
|
let portalConfigPromise = null;
|
|
161
224
|
let portalUnavailableReason = null;
|
|
225
|
+
const approvalHmacKey = randomBytes(32);
|
|
226
|
+
const consumedApprovalTokenIds = /* @__PURE__ */ new Map();
|
|
227
|
+
const replayCacheLimit = 4096;
|
|
228
|
+
const replayCacheCleanupThreshold = replayCacheLimit / 2;
|
|
162
229
|
const loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;
|
|
163
230
|
function loadPortalConfig() {
|
|
164
231
|
if (portalConfigPromise !== null) return portalConfigPromise;
|
|
@@ -172,8 +239,27 @@ function createPortalPluginRuntimeState(props) {
|
|
|
172
239
|
portalConfigPromise = nextPromise;
|
|
173
240
|
return portalConfigPromise;
|
|
174
241
|
}
|
|
242
|
+
function sweepExpiredApprovalTokenIds(nowMs) {
|
|
243
|
+
if (consumedApprovalTokenIds.size < replayCacheCleanupThreshold) return;
|
|
244
|
+
for (const [tokenKey, tokenExpiresAtMs] of consumedApprovalTokenIds) if (tokenExpiresAtMs <= nowMs) consumedApprovalTokenIds.delete(tokenKey);
|
|
245
|
+
}
|
|
175
246
|
return {
|
|
247
|
+
consumeApprovalTokenId: (agentId, jti, expiresAtMs) => {
|
|
248
|
+
sweepExpiredApprovalTokenIds(Date.now());
|
|
249
|
+
const tokenKey = `${agentId}\n${jti}`;
|
|
250
|
+
if (consumedApprovalTokenIds.has(tokenKey)) return {
|
|
251
|
+
ok: false,
|
|
252
|
+
reason: "replayed"
|
|
253
|
+
};
|
|
254
|
+
if (consumedApprovalTokenIds.size >= replayCacheLimit) return {
|
|
255
|
+
ok: false,
|
|
256
|
+
reason: "replay-cache-full"
|
|
257
|
+
};
|
|
258
|
+
consumedApprovalTokenIds.set(tokenKey, expiresAtMs);
|
|
259
|
+
return { ok: true };
|
|
260
|
+
},
|
|
176
261
|
configDir: props.configDir,
|
|
262
|
+
getApprovalHmacKey: () => approvalHmacKey,
|
|
177
263
|
getLoadedPortalConfig: () => loadedPortalConfig,
|
|
178
264
|
getPortalUnavailableReason: () => portalUnavailableReason,
|
|
179
265
|
loadPortalConfig,
|
|
@@ -279,7 +365,7 @@ async function resolveManagedPortalSecret(secret) {
|
|
|
279
365
|
if (value === void 0 || value.length === 0) throw new Error(`Missing environment secret ${secret.name} for MCP Portal native plugin.`);
|
|
280
366
|
return value;
|
|
281
367
|
}
|
|
282
|
-
async function createManagedPortalCore(configDir) {
|
|
368
|
+
async function createManagedPortalCore(configDir, runtimeState) {
|
|
283
369
|
const effectiveConfigPaths = await resolveEffectiveConfigPaths(configDir);
|
|
284
370
|
const [mcpConfig, portalConfig] = await Promise.all([loadMcpConfig(effectiveConfigPaths.mcpConfigPath), loadMcpPortalConfig(effectiveConfigPaths.portalConfigPath)]);
|
|
285
371
|
const upstreamServers = await resolveUpstreamServers({
|
|
@@ -288,6 +374,21 @@ async function createManagedPortalCore(configDir) {
|
|
|
288
374
|
});
|
|
289
375
|
const upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });
|
|
290
376
|
const profilePolicyMaps = buildProfilePolicyMaps(portalConfig);
|
|
377
|
+
const approval = createPortalPolicyApprovalEvaluator({
|
|
378
|
+
consumeTokenId: (agentId, jti, expiresAtMs) => runtimeState.consumeApprovalTokenId(agentId, jti, expiresAtMs),
|
|
379
|
+
missingApprovalTokenDecision: {
|
|
380
|
+
kind: "approval_required",
|
|
381
|
+
level: "standard"
|
|
382
|
+
},
|
|
383
|
+
resolveRecord: (agentId) => {
|
|
384
|
+
const agent = portalConfig.agents[agentId];
|
|
385
|
+
if (agent === void 0) return;
|
|
386
|
+
return {
|
|
387
|
+
hmacKey: runtimeState.getApprovalHmacKey(),
|
|
388
|
+
profile: resolveMcpPortalProfile(portalConfig, agent.profile)
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
});
|
|
291
392
|
return createPortalCore({
|
|
292
393
|
accessPolicy: {
|
|
293
394
|
defaultPolicy: "deny-all",
|
|
@@ -295,7 +396,7 @@ async function createManagedPortalCore(configDir) {
|
|
|
295
396
|
enabledToolsByNamespaceByAgent: profilePolicyMaps.enabledToolsByNamespaceByAgent,
|
|
296
397
|
hiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent
|
|
297
398
|
},
|
|
298
|
-
|
|
399
|
+
approval,
|
|
299
400
|
catalogTtlMs: profilePolicyMaps.cacheTtlMs,
|
|
300
401
|
runtime: {
|
|
301
402
|
callUpstreamTool: upstreamRuntime.callTool,
|
|
@@ -407,7 +508,7 @@ function registerMcpPortalPlugin(api) {
|
|
|
407
508
|
const runtimeState = createPortalPluginRuntimeState({ configDir });
|
|
408
509
|
let corePromise;
|
|
409
510
|
const getCore = () => {
|
|
410
|
-
corePromise ??= createManagedPortalCore(configDir).catch((error) => {
|
|
511
|
+
corePromise ??= createManagedPortalCore(configDir, runtimeState).catch((error) => {
|
|
411
512
|
corePromise = void 0;
|
|
412
513
|
throw error;
|
|
413
514
|
});
|
|
@@ -424,6 +525,26 @@ function registerMcpPortalPlugin(api) {
|
|
|
424
525
|
}
|
|
425
526
|
api.on?.("before_tool_call", createBeforeToolCallHandler({
|
|
426
527
|
logger,
|
|
528
|
+
resolveApprovalTokenCallDigests: async ({ agentId, approvalCalls, context, params }) => {
|
|
529
|
+
const core = await getCore();
|
|
530
|
+
const scope = core.createAgentScope({
|
|
531
|
+
agentId,
|
|
532
|
+
agentScopeId: agentId,
|
|
533
|
+
...context.sessionId ? { sessionId: context.sessionId } : {},
|
|
534
|
+
...context.sessionKey ? { sessionKey: context.sessionKey } : {},
|
|
535
|
+
source: "openclaw-trusted"
|
|
536
|
+
});
|
|
537
|
+
const digestsByCallId = await core.approval.prepareCallDigests({
|
|
538
|
+
input: params,
|
|
539
|
+
scope
|
|
540
|
+
});
|
|
541
|
+
if (digestsByCallId === null) throw new Error("MCP Portal core could not prepare approval token digests.");
|
|
542
|
+
return approvalCalls.map((call) => {
|
|
543
|
+
const digest = digestsByCallId[call.id];
|
|
544
|
+
if (digest === void 0) throw new Error(`MCP Portal core did not prepare an approval token digest for call '${call.id}'.`);
|
|
545
|
+
return digest;
|
|
546
|
+
});
|
|
547
|
+
},
|
|
427
548
|
runtimeState
|
|
428
549
|
}), { priority: 80 });
|
|
429
550
|
api.on?.("before_prompt_build", createBeforePromptBuildHandler({ runtimeState }), { priority: 80 });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["isObjectRecord","isObjectRecord"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/effective-config-manifest.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/plugin-registration.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"sourcesContent":["import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\n\nimport type {\n\tOpenClawBeforePromptBuildEvent,\n\tOpenClawPluginHookContext,\n\tOpenClawPromptHookResult,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\nexport interface CreateBeforePromptBuildHandlerProps {\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nexport function createBeforePromptBuildHandler(\n\tprops: CreateBeforePromptBuildHandlerProps,\n): (\n\tevent: OpenClawBeforePromptBuildEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawPromptHookResult | undefined> {\n\treturn async (_event, context) => {\n\t\tconst agentId = context.agentId;\n\t\tif (agentId === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tif (!profile.promptContext.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst namespaces = profile.enabledNamespaces\n\t\t\t.toSorted()\n\t\t\t.slice(0, profile.promptContext.maxNamespaces);\n\t\tconst namespaceText =\n\t\t\tnamespaces.length === 0\n\t\t\t\t? ' (none in your profile)'\n\t\t\t\t: namespaces.map((name) => ` ${name}`).join('\\n');\n\t\treturn {\n\t\t\tappendSystemContext: [\n\t\t\t\t'MCP Portal namespaces available to this agent:',\n\t\t\t\tnamespaceText,\n\t\t\t\t'Use mcp_portal_search to find tools by intent, then mcp_portal_describe before mcp_portal_call.',\n\t\t\t].join('\\n'),\n\t\t};\n\t};\n}\n","import {\n\tmcpPortalCallPolicyDecision,\n\ttype McpPortalCallPolicyDecision,\n\ttype ResolvedMcpPortalProfile,\n} from '@agent-vm/config-contracts';\n\nexport interface PortalCallRequest {\n\treadonly arguments: Record<string, unknown>;\n\treadonly id: string;\n\treadonly namespace: string;\n\treadonly toolName: string;\n}\n\nexport function profileAllowsPortalCall(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): boolean {\n\tif (!profile.enabledNamespaces.includes(call.namespace)) {\n\t\treturn false;\n\t}\n\tconst enabledTools = profile.enabledToolsByNamespace[call.namespace];\n\tif (enabledTools !== undefined && !enabledTools.includes(call.toolName)) {\n\t\treturn false;\n\t}\n\tconst hiddenTools = profile.hiddenToolsByNamespace[call.namespace] ?? [];\n\treturn !hiddenTools.includes(call.toolName);\n}\n\nexport function profilePortalCallDecision(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): McpPortalCallPolicyDecision {\n\treturn mcpPortalCallPolicyDecision(profile, call);\n}\n","import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\n\nimport type {\n\tOpenClawBeforeToolCallEvent,\n\tOpenClawBeforeToolCallResult,\n\tOpenClawPluginHookContext,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\nimport {\n\tprofileAllowsPortalCall,\n\tprofilePortalCallDecision,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nexport interface CreateBeforeToolCallHandlerProps {\n\treadonly logger?: {\n\t\treadonly warn?: (message: string) => void;\n\t};\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCallRequest(value: unknown): PortalCallRequest | null {\n\tif (!isObjectRecord(value)) {\n\t\treturn null;\n\t}\n\tconst id = value.id;\n\tconst namespace = value.namespace;\n\tconst toolName = value.toolName;\n\tconst argumentsValue = value.arguments;\n\tif (\n\t\ttypeof id !== 'string' ||\n\t\ttypeof namespace !== 'string' ||\n\t\ttypeof toolName !== 'string' ||\n\t\t!isObjectRecord(argumentsValue)\n\t) {\n\t\treturn null;\n\t}\n\treturn { arguments: argumentsValue, id, namespace, toolName };\n}\n\nfunction parseCallRequests(params: Record<string, unknown>): readonly PortalCallRequest[] | null {\n\tconst calls = params.calls;\n\tif (!Array.isArray(calls)) {\n\t\treturn null;\n\t}\n\tconst parsedCalls: PortalCallRequest[] = [];\n\tfor (const call of calls) {\n\t\tconst parsedCall = parseCallRequest(call);\n\t\tif (parsedCall === null) {\n\t\t\treturn null;\n\t\t}\n\t\tparsedCalls.push(parsedCall);\n\t}\n\treturn parsedCalls;\n}\n\nexport function createBeforeToolCallHandler(\n\tprops: CreateBeforeToolCallHandlerProps,\n): (\n\tevent: OpenClawBeforeToolCallEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawBeforeToolCallResult | undefined> {\n\treturn async (event, context) => {\n\t\tif (event.toolName !== 'mcp_portal_call') {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (context.agentId === undefined) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: missing OpenClaw agent context for ${event.toolName}.`,\n\t\t\t};\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = context.agentId;\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn { block: true, blockReason: `mcp-portal: agent \"${agentId}\" is not configured.` };\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tconst calls = parseCallRequests(event.params);\n\t\tif (calls === null || calls.length === 0) {\n\t\t\treturn { block: true, blockReason: 'mcp-portal: malformed portal call batch.' };\n\t\t}\n\n\t\tfor (const call of calls) {\n\t\t\tif (!profileAllowsPortalCall(profile, call)) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\tblockReason: `policy: ${agentId}/${call.namespace}/${call.toolName} not enabled`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst approvalCalls: PortalCallRequest[] = [];\n\t\tfor (const call of calls) {\n\t\t\tconst decision = profilePortalCallDecision(profile, call);\n\t\t\tif (decision.kind === 'blocked') {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\tblockReason: `policy: ${agentId}/${call.namespace}/${call.toolName} is not callable`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (decision.kind === 'requires_approval') {\n\t\t\t\tapprovalCalls.push(call);\n\t\t\t}\n\t\t}\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst toolNames = approvalCalls\n\t\t\t.map((call) => `${call.namespace}.${call.toolName}`)\n\t\t\t.toSorted()\n\t\t\t.join(', ');\n\t\treturn {\n\t\t\trequireApproval: {\n\t\t\t\tdescription: `Allow MCP Portal batch for agent ${agentId}: ${toolNames}.`,\n\t\t\t\tpluginId: 'mcp-portal',\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttimeoutBehavior: 'deny',\n\t\t\t\ttimeoutMs: 60_000,\n\t\t\t\ttitle: `MCP Portal batch: ${toolNames}`,\n\t\t\t},\n\t\t};\n\t};\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst effectiveConfigManifestFileName = 'mcp-portal-effective-manifest.json';\n\nexport interface EffectiveConfigPaths {\n\treadonly mcpConfigPath: string;\n\treadonly portalConfigPath: string;\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isSafeManifestFileName(value: string): boolean {\n\treturn value.length > 0 && !value.includes('/') && !value.includes('\\\\');\n}\n\nfunction parseEffectiveConfigManifest(value: unknown): {\n\treadonly mcpConfigFile: string;\n\treadonly portalConfigFile: string;\n} {\n\tif (!isObjectRecord(value)) {\n\t\tthrow new Error('MCP Portal effective config manifest must be an object.');\n\t}\n\tif (value.schemaVersion !== 1) {\n\t\tthrow new Error('MCP Portal effective config manifest must use schemaVersion 1.');\n\t}\n\tif (typeof value.mcpConfigFile !== 'string' || !isSafeManifestFileName(value.mcpConfigFile)) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe mcpConfigFile.');\n\t}\n\tif (\n\t\ttypeof value.portalConfigFile !== 'string' ||\n\t\t!isSafeManifestFileName(value.portalConfigFile)\n\t) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe portalConfigFile.');\n\t}\n\treturn {\n\t\tmcpConfigFile: value.mcpConfigFile,\n\t\tportalConfigFile: value.portalConfigFile,\n\t};\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn (\n\t\tisObjectRecord(error) &&\n\t\ttypeof error.code === 'string' &&\n\t\t(error.code === 'ENOENT' || error.code === 'ENOTDIR')\n\t);\n}\n\nexport async function resolveEffectiveConfigPaths(\n\tconfigDir: string,\n): Promise<EffectiveConfigPaths> {\n\tconst manifestPath = join(configDir, effectiveConfigManifestFileName);\n\tlet manifestText: string;\n\ttry {\n\t\tmanifestText = await readFile(manifestPath, 'utf8');\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) {\n\t\t\treturn {\n\t\t\t\tmcpConfigPath: join(configDir, 'mcp.config.jsonc'),\n\t\t\t\tportalConfigPath: join(configDir, 'mcp-portal.config.jsonc'),\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\tconst manifest = parseEffectiveConfigManifest(JSON.parse(manifestText));\n\treturn {\n\t\tmcpConfigPath: join(configDir, manifest.mcpConfigFile),\n\t\tportalConfigPath: join(configDir, manifest.portalConfigFile),\n\t};\n}\n","import { z } from 'zod';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tconfigDir: z.string().min(1),\n\t})\n\t.strict();\n\nexport type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;\n\nexport function parsePortalConfig(value: unknown): PortalPluginConfig {\n\treturn portalPluginConfigSchema.parse(value ?? {});\n}\n","import { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly configDir: string;\n\treadonly getLoadedPortalConfig: () => McpPortalConfig | null;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet loadedPortalConfig: McpPortalConfig | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = resolveEffectiveConfigPaths(props.configDir)\n\t\t\t.then((effectiveConfigPaths) => loadPortalConfigFile(effectiveConfigPaths.portalConfigPath))\n\t\t\t.then((portalConfig) => {\n\t\t\t\tloadedPortalConfig = portalConfig;\n\t\t\t\treturn portalConfig;\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\t\tportalConfigPromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn portalConfigPromise;\n\t}\n\n\treturn {\n\t\tconfigDir: props.configDir,\n\t\tgetLoadedPortalConfig: () => loadedPortalConfig,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tloadPortalConfig,\n\t\tmarkPortalAvailable: () => {\n\t\t\tportalUnavailableReason = null;\n\t\t},\n\t\tmarkPortalUnavailable: (reason) => {\n\t\t\tportalUnavailableReason = reason;\n\t\t},\n\t};\n}\n","import {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\ttype McpPortalConfig,\n\tresolveMcpPortalProfile,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport {\n\tcreatePortalCore,\n\tcreateUpstreamMcpClientRuntime,\n\tlistPortalCoreToolDescriptors,\n\tresolveUpstreamServers,\n\ttype PortalCore,\n\ttype PortalCoreEvent,\n\ttype PortalCoreToolDescriptor,\n\ttype PortalToolSelector,\n} from '@agent-vm/mcp-portal/core';\n\nimport { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\nimport type {\n\tOpenClawPortalPluginApi,\n\tOpenClawPluginToolContext,\n\tOpenClawToolRegistration,\n\tOpenClawToolUpdateCallback,\n} from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport { createPortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\ninterface PortalPluginEntry {\n\treadonly description: string;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly register: (api: OpenClawPortalPluginApi) => void;\n}\n\ninterface TcpPoolConfig {\n\treadonly basePort: number;\n\treadonly size: number;\n}\n\ninterface ProfilePolicyMaps {\n\treadonly cacheTtlMs: number;\n\treadonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;\n\treadonly enabledToolsByNamespaceByAgent: Readonly<\n\t\tRecord<string, Readonly<Record<string, readonly string[]>>>\n\t>;\n\treadonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n}\n\nconst pluginId = 'mcp-portal';\n\nfunction hasFunction(value: unknown): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === 'function';\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isUnknownArray(value: unknown): value is readonly unknown[] {\n\treturn Array.isArray(value);\n}\n\nfunction getObjectProperty(value: unknown, property: string): unknown {\n\treturn isObjectRecord(value) ? value[property] : undefined;\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tif (api.pluginConfig !== undefined) {\n\t\treturn parsePortalConfig(api.pluginConfig).configDir;\n\t}\n\t// Managed agent-vm passes pluginConfig. The config fallbacks keep the plugin usable\n\t// in direct OpenClaw test harnesses that load plugin config through the root config.\n\tconst topLevelMcpConfigDir = getObjectProperty(\n\t\tgetObjectProperty(api.config, 'mcpPortal'),\n\t\t'configDir',\n\t);\n\tif (typeof topLevelMcpConfigDir === 'string' && topLevelMcpConfigDir.length > 0) {\n\t\treturn topLevelMcpConfigDir;\n\t}\n\tconst zones = getObjectProperty(api.config, 'zones');\n\tif (isUnknownArray(zones)) {\n\t\tconst firstZone = zones.at(0);\n\t\tconst zoneMcpConfigDir = getObjectProperty(\n\t\t\tgetObjectProperty(firstZone, 'mcpPortal'),\n\t\t\t'configDir',\n\t\t);\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'MCP Portal plugin requires configDir in plugin config or zone mcpPortal config.',\n\t);\n}\n\nexport function validatePortalPortAgainstTcpPool(props: {\n\treadonly port: number;\n\treadonly tcpPool: TcpPoolConfig | null;\n}): void {\n\tif (props.tcpPool === null) {\n\t\treturn;\n\t}\n\tconst firstTcpPoolPort = props.tcpPool.basePort;\n\tconst lastTcpPoolPortExclusive = props.tcpPool.basePort + props.tcpPool.size;\n\tif (props.port >= firstTcpPoolPort && props.port < lastTcpPoolPortExclusive) {\n\t\tthrow new Error(\n\t\t\t`MCP Portal port ${String(props.port)} overlaps the Tool VM TCP pool ` +\n\t\t\t\t`[${String(firstTcpPoolPort)}, ${String(lastTcpPoolPortExclusive)}).`,\n\t\t);\n\t}\n}\n\nfunction createLoggerAdapter(api: OpenClawPortalPluginApi): {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n} {\n\treturn {\n\t\terror: (message) => api.logger?.error?.(message),\n\t\tinfo: (message) => api.logger?.info?.(message),\n\t\twarn: (message) => api.logger?.warn?.(message),\n\t};\n}\n\nexport function validatePortalPluginApi(api: OpenClawPortalPluginApi): void {\n\tif (!hasFunction(api.registerTool)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerTool API.');\n\t}\n\tif (!hasFunction(api.on)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw before_tool_call hook API.');\n\t}\n\tconst hasLifecycleCleanupApi =\n\t\thasFunction(api.lifecycle?.registerRuntimeLifecycle) ||\n\t\thasFunction(api.registerRuntimeLifecycle);\n\tif (hasLifecycleCleanupApi) {\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction registerPortalRuntimeCleanup(\n\tapi: OpenClawPortalPluginApi,\n\tcleanup: () => Promise<void> | void,\n): void {\n\tconst runtimeLifecycle = {\n\t\tcleanup: async () => {\n\t\t\tawait cleanup();\n\t\t},\n\t\tdescription: 'Closes MCP Portal upstream clients owned by the agent-vm plugin.',\n\t\tid: 'mcp-portal-core',\n\t} satisfies Parameters<NonNullable<OpenClawPortalPluginApi['registerRuntimeLifecycle']>>[0];\n\tif (hasFunction(api.lifecycle?.registerRuntimeLifecycle)) {\n\t\tapi.lifecycle.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tif (hasFunction(api.registerRuntimeLifecycle)) {\n\t\tapi.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction selectorsFromNamespaceTools(\n\tnamespaceTools: Readonly<Record<string, readonly string[]>>,\n): readonly PortalToolSelector[] {\n\treturn Object.entries(namespaceTools).flatMap(([namespace, toolNames]) =>\n\t\ttoolNames.map((toolName) => ({ namespace, toolName })),\n\t);\n}\n\nfunction buildProfilePolicyMaps(portalConfig: McpPortalConfig): ProfilePolicyMaps {\n\tconst enabledNamespacesByAgent: Record<string, readonly string[]> = {};\n\tconst enabledToolsByNamespaceByAgent: Record<\n\t\tstring,\n\t\tReadonly<Record<string, readonly string[]>>\n\t> = {};\n\tconst hiddenToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst profileTtls: number[] = [];\n\n\tfor (const [agentId, agent] of Object.entries(portalConfig.agents)) {\n\t\tconst profile: ResolvedMcpPortalProfile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tenabledNamespacesByAgent[agentId] = profile.enabledNamespaces;\n\t\tenabledToolsByNamespaceByAgent[agentId] = profile.enabledToolsByNamespace;\n\t\thiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);\n\t\tprofileTtls.push(profile.cache.catalogTtlMs);\n\t}\n\n\treturn {\n\t\tcacheTtlMs: profileTtls.length === 0 ? 60_000 : Math.min(...profileTtls),\n\t\tenabledNamespacesByAgent,\n\t\tenabledToolsByNamespaceByAgent,\n\t\thiddenToolsByAgent,\n\t};\n}\n\nasync function resolveManagedPortalSecret(secret: SecretValue): Promise<string> {\n\tif (secret.source !== 'environment') {\n\t\tthrow new Error(\n\t\t\t'MCP Portal managed OpenClaw effective config must use environment secret refs.',\n\t\t);\n\t}\n\tconst value = process.env[secret.name];\n\tif (value === undefined || value.length === 0) {\n\t\tthrow new Error(`Missing environment secret ${secret.name} for MCP Portal native plugin.`);\n\t}\n\treturn value;\n}\n\nasync function createManagedPortalCore(configDir: string): Promise<PortalCore> {\n\tconst effectiveConfigPaths = await resolveEffectiveConfigPaths(configDir);\n\tconst [mcpConfig, portalConfig] = await Promise.all([\n\t\tloadMcpConfig(effectiveConfigPaths.mcpConfigPath),\n\t\tloadMcpPortalConfig(effectiveConfigPaths.portalConfigPath),\n\t]);\n\tconst upstreamServers = await resolveUpstreamServers({\n\t\tconfig: mcpConfig,\n\t\tresolveSecret: resolveManagedPortalSecret,\n\t});\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\n\treturn createPortalCore({\n\t\taccessPolicy: {\n\t\t\tdefaultPolicy: 'deny-all',\n\t\t\tenabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,\n\t\t\tenabledToolsByNamespaceByAgent: profilePolicyMaps.enabledToolsByNamespaceByAgent,\n\t\t\thiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent,\n\t\t},\n\t\tapprovalTrustBoundary: 'openclaw-before-tool-call-hook',\n\t\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: {\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tcloseAgentScope: upstreamRuntime.closeAgentScope,\n\t\t\tcloseSession: upstreamRuntime.closeSession,\n\t\t\tlistTools: upstreamRuntime.listTools,\n\t\t},\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n}\n\nfunction portalUpdateFromCoreEvent(event: PortalCoreEvent): Record<string, unknown> | null {\n\tif (event.kind === 'progress') {\n\t\treturn {\n\t\t\tmessage: event.message ?? 'MCP Portal progress',\n\t\t\t...(event.progress !== undefined ? { progress: event.progress } : {}),\n\t\t\trequestId: event.requestId,\n\t\t\t...(event.total !== undefined ? { total: event.total } : {}),\n\t\t\ttype: 'mcp_portal_progress',\n\t\t};\n\t}\n\tif (event.kind === 'partial_content') {\n\t\treturn {\n\t\t\tcontent: event.content,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_partial_content',\n\t\t};\n\t}\n\tif (event.kind === 'upstream_notification') {\n\t\treturn {\n\t\t\tmethod: event.method,\n\t\t\tparams: event.params,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_upstream_notification',\n\t\t};\n\t}\n\treturn null;\n}\n\nasync function forwardCoreEvent(\n\tevent: PortalCoreEvent,\n\tlogger: ReturnType<typeof createLoggerAdapter>,\n\tonUpdate: OpenClawToolUpdateCallback | undefined,\n): Promise<void> {\n\tconst update = portalUpdateFromCoreEvent(event);\n\tif (update !== null) {\n\t\ttry {\n\t\t\tawait onUpdate?.(update);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tlogger.warn(`[mcp-portal] OpenClaw onUpdate delivery failed: ${message}`);\n\t\t}\n\t}\n}\n\nfunction createNativeTool(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly descriptor: PortalCoreToolDescriptor;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly logger: ReturnType<typeof createLoggerAdapter>;\n}): OpenClawToolRegistration {\n\treturn {\n\t\tdescription: props.descriptor.description,\n\t\texecute: async (_toolCallId, params, signal, onUpdate) => {\n\t\t\tif (props.context.agentId === undefined || props.context.agentId.length === 0) {\n\t\t\t\tthrow new Error('mcp-portal: OpenClaw did not provide a trusted agentId.');\n\t\t\t}\n\t\t\tconst core = await props.getCore();\n\t\t\tconst scope = core.createAgentScope({\n\t\t\t\tagentId: props.context.agentId,\n\t\t\t\tagentScopeId: props.context.agentId,\n\t\t\t\t...(props.context.sessionId ? { sessionId: props.context.sessionId } : {}),\n\t\t\t\t...(props.context.sessionKey ? { sessionKey: props.context.sessionKey } : {}),\n\t\t\t\tsource: 'openclaw-trusted',\n\t\t\t});\n\t\t\tconst result = await core.collectPortalCoreResult(\n\t\t\t\tcore.callStream({\n\t\t\t\t\tinput: params,\n\t\t\t\t\tscope,\n\t\t\t\t\t...(signal !== undefined ? { signal } : {}),\n\t\t\t\t\ttoolName: props.descriptor.name,\n\t\t\t\t}),\n\t\t\t\t{ onEvent: (event) => forwardCoreEvent(event, props.logger, onUpdate) },\n\t\t\t);\n\t\t\treturn { content: JSON.stringify(result), details: result };\n\t\t},\n\t\tlabel: props.descriptor.name,\n\t\tname: props.descriptor.name,\n\t\tparameters: props.descriptor.inputSchema,\n\t};\n}\n\nfunction descriptorsForOpenClawContext(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly portalConfig: McpPortalConfig | null;\n}): readonly PortalCoreToolDescriptor[] {\n\tif (props.portalConfig === null || props.context.agentId === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst agent = props.portalConfig.agents[props.context.agentId];\n\tif (agent === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst profile = resolveMcpPortalProfile(props.portalConfig, agent.profile);\n\treturn listPortalCoreToolDescriptors(profile.enabledNamespaces);\n}\n\nfunction registerNativePortalTools(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly runtimeState: ReturnType<typeof createPortalPluginRuntimeState>;\n}): void {\n\tconst descriptorNames = listPortalCoreToolDescriptors().map((descriptor) => descriptor.name);\n\tconst logger = createLoggerAdapter(props.api);\n\tprops.api.registerTool?.(\n\t\t(context) => {\n\t\t\tconst descriptors = descriptorsForOpenClawContext({\n\t\t\t\tcontext,\n\t\t\t\tportalConfig: props.runtimeState.getLoadedPortalConfig(),\n\t\t\t});\n\t\t\treturn descriptors.map((descriptor) =>\n\t\t\t\tcreateNativeTool({ context, descriptor, getCore: props.getCore, logger }),\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tnames: descriptorNames,\n\t\t\toptional: true,\n\t\t},\n\t);\n}\n\nfunction shouldRegisterPortalRuntimeHooks(api: OpenClawPortalPluginApi): boolean {\n\treturn api.registrationMode === undefined || api.registrationMode === 'full';\n}\n\nfunction formatRegistrationMode(api: OpenClawPortalPluginApi): string {\n\treturn api.registrationMode ?? 'full';\n}\n\nexport function registerMcpPortalPlugin(api: OpenClawPortalPluginApi): void {\n\tconst logger = createLoggerAdapter(api);\n\tconst registerRuntimeHooks = shouldRegisterPortalRuntimeHooks(api);\n\tif (registerRuntimeHooks) {\n\t\tvalidatePortalPluginApi(api);\n\t} else if (!hasFunction(api.registerTool)) {\n\t\tlogger.warn(\n\t\t\t`[mcp-portal] skipped native portal tool registration for registrationMode='${formatRegistrationMode(api)}' because OpenClaw did not expose registerTool.`,\n\t\t);\n\t\treturn;\n\t}\n\tconst configDir = resolveConfigDir(api);\n\tconst runtimeState = createPortalPluginRuntimeState({ configDir });\n\tlet corePromise: Promise<PortalCore> | undefined;\n\tconst getCore = (): Promise<PortalCore> => {\n\t\tcorePromise ??= createManagedPortalCore(configDir).catch((error: unknown) => {\n\t\t\tcorePromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t\treturn corePromise;\n\t};\n\tregisterNativePortalTools({ api, getCore, runtimeState });\n\n\tif (!registerRuntimeHooks) {\n\t\tlogger.info(\n\t\t\t`[mcp-portal] registered native portal tools for registrationMode='${formatRegistrationMode(api)}'.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tapi.on?.('before_tool_call', createBeforeToolCallHandler({ logger, runtimeState }), {\n\t\tpriority: 80,\n\t});\n\n\tapi.on?.('before_prompt_build', createBeforePromptBuildHandler({ runtimeState }), {\n\t\tpriority: 80,\n\t});\n\n\tif (!api.on && api.registerPromptHook) {\n\t\tapi.registerPromptHook('before_prompt_build', async (context) => {\n\t\t\tconst handler = createBeforePromptBuildHandler({ runtimeState });\n\t\t\tconst result = await handler({}, context);\n\t\t\tif (result?.appendSystemContext !== undefined) {\n\t\t\t\tcontext.appendPrompt?.(result.appendSystemContext);\n\t\t\t}\n\t\t});\n\t}\n\n\tregisterPortalRuntimeCleanup(api, async () => {\n\t\tconst core = await corePromise?.catch(() => undefined);\n\t\tawait core?.close();\n\t});\n\tlogger.info('[mcp-portal] registered native portal tools and runtime hooks.');\n}\n\nconst pluginEntry = {\n\tdescription: 'Registers native OpenClaw MCP Portal tools and wires per-agent approval hooks.',\n\tid: pluginId,\n\tname: 'MCP Portal',\n\tregister: registerMcpPortalPlugin,\n} satisfies PortalPluginEntry;\n\nexport default pluginEntry;\n","export interface PortalPromptNamespaceSummary {\n\treadonly namespace: string;\n\treadonly toolCount: number;\n}\n\nexport interface PortalPromptDiagnostic {\n\treadonly hint?: string;\n\treadonly message: string;\n\treadonly namespace: string;\n\treadonly phase?: string;\n}\n\nfunction formatDiagnostic(entry: PortalPromptDiagnostic): string {\n\tconst phase = entry.phase === undefined ? '' : ` ${entry.phase}`;\n\tconst hint = entry.hint === undefined ? '' : ` Hint: ${entry.hint}`;\n\treturn `${entry.namespace}${phase}: ${entry.message}.${hint}`;\n}\n\nexport function createPortalPromptContext(props: {\n\treadonly diagnostics?: readonly PortalPromptDiagnostic[];\n\treadonly namespaces: readonly PortalPromptNamespaceSummary[];\n}): string {\n\tconst namespaceList =\n\t\tprops.namespaces.length > 0\n\t\t\t? props.namespaces.map((entry) => `${entry.namespace}(${entry.toolCount} tools)`).join(', ')\n\t\t\t: 'none configured';\n\tconst diagnostics =\n\t\tprops.diagnostics !== undefined && props.diagnostics.length > 0\n\t\t\t? [`Discovery diagnostics: ${props.diagnostics.map(formatDiagnostic).join('; ')}`]\n\t\t\t: [];\n\n\treturn [\n\t\t'MCP Portal is available as native OpenClaw tools.',\n\t\t'Use mcp_portal_list with requests[], mcp_portal_search with requests[],',\n\t\t'mcp_portal_describe with requests[], and mcp_portal_call with calls[].',\n\t\t'Responses are { ok, results, errors, diagnostics }; results is keyed by each request/call id and each value is discriminated by ok: true or ok: false.',\n\t\t'Call upstream tools by namespace + toolName inside calls[].',\n\t\t'Call mcp_portal_describe before mcp_portal_call unless you already saw the full schema for that tool in this portal session.',\n\t\t'Gateway owns MCP auth.',\n\t\t`Namespaces: ${namespaceList}`,\n\t\t...diagnostics,\n\t].join('\\n');\n}\n","import { redactCredentialText } from '@agent-vm/mcp-portal/core';\n\nexport function redactPortalSecrets(text: string, secretValues: readonly string[] = []): string {\n\treturn secretValues\n\t\t.filter((secretValue) => secretValue.length > 0)\n\t\t.reduce(\n\t\t\t(current, secretValue) => current.split(secretValue).join('[REDACTED]'),\n\t\t\tredactCredentialText(text),\n\t\t);\n}\n","export * from './openclaw-plugin-api.js';\nexport * from './plugin-registration.js';\nexport * from './before-prompt-build-handler.js';\nexport * from './before-tool-call-handler.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-tool-policy.js';\nexport * from './portal-prompt-context.js';\nexport * from './redaction.js';\nexport { default } from './plugin-registration.js';\n\nexport const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = '@agent-vm/openclaw-mcp-portal-plugin';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["isObjectRecord","isObjectRecord"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/effective-config-manifest.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/plugin-registration.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"sourcesContent":["import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\n\nimport type {\n\tOpenClawBeforePromptBuildEvent,\n\tOpenClawPluginHookContext,\n\tOpenClawPromptHookResult,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\nexport interface CreateBeforePromptBuildHandlerProps {\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nexport function createBeforePromptBuildHandler(\n\tprops: CreateBeforePromptBuildHandlerProps,\n): (\n\tevent: OpenClawBeforePromptBuildEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawPromptHookResult | undefined> {\n\treturn async (_event, context) => {\n\t\tconst agentId = context.agentId;\n\t\tif (agentId === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tif (!profile.promptContext.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst namespaces = profile.enabledNamespaces\n\t\t\t.toSorted()\n\t\t\t.slice(0, profile.promptContext.maxNamespaces);\n\t\tconst namespaceText =\n\t\t\tnamespaces.length === 0\n\t\t\t\t? ' (none in your profile)'\n\t\t\t\t: namespaces.map((name) => ` ${name}`).join('\\n');\n\t\treturn {\n\t\t\tappendSystemContext: [\n\t\t\t\t'MCP Portal namespaces available to this agent:',\n\t\t\t\tnamespaceText,\n\t\t\t\t'Use mcp_portal_search to find tools by intent, then mcp_portal_describe before mcp_portal_call.',\n\t\t\t].join('\\n'),\n\t\t};\n\t};\n}\n","import {\n\tmcpPortalCallPolicyDecision,\n\ttype McpPortalCallPolicyDecision,\n\ttype ResolvedMcpPortalProfile,\n} from '@agent-vm/config-contracts';\n\nexport interface PortalCallRequest {\n\treadonly arguments: Record<string, unknown>;\n\treadonly id: string;\n\treadonly namespace: string;\n\treadonly toolName: string;\n}\n\nexport function profileAllowsPortalCall(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): boolean {\n\tif (!profile.enabledNamespaces.includes(call.namespace)) {\n\t\treturn false;\n\t}\n\tconst enabledTools = profile.enabledToolsByNamespace[call.namespace];\n\tif (enabledTools !== undefined && !enabledTools.includes(call.toolName)) {\n\t\treturn false;\n\t}\n\tconst hiddenTools = profile.hiddenToolsByNamespace[call.namespace] ?? [];\n\treturn !hiddenTools.includes(call.toolName);\n}\n\nexport function profilePortalCallDecision(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): McpPortalCallPolicyDecision {\n\treturn mcpPortalCallPolicyDecision(profile, call);\n}\n","import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\nimport {\n\thashCallArguments,\n\tsignApprovalToken,\n\ttype ApprovalTokenCallDigest,\n} from '@agent-vm/mcp-portal/portal-auth/hmac-token';\n\nimport type {\n\tOpenClawBeforeToolCallEvent,\n\tOpenClawBeforeToolCallResult,\n\tOpenClawPluginHookContext,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\nimport {\n\tprofileAllowsPortalCall,\n\tprofilePortalCallDecision,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nconst approvalPromptTimeoutMs = 60_000;\nconst approvalTokenLifetimeMs = 5 * 60_000;\n\nexport interface CreateBeforeToolCallHandlerProps {\n\treadonly logger?: {\n\t\treadonly error?: (message: string) => void;\n\t\treadonly warn?: (message: string) => void;\n\t};\n\treadonly resolveApprovalTokenCallDigests?: (props: {\n\t\treadonly agentId: string;\n\t\treadonly approvalCalls: readonly PortalCallRequest[];\n\t\treadonly context: OpenClawPluginHookContext;\n\t\treadonly params: Record<string, unknown>;\n\t}) => Promise<readonly ApprovalTokenCallDigest[]>;\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCallRequest(value: unknown): PortalCallRequest | null {\n\tif (!isObjectRecord(value)) {\n\t\treturn null;\n\t}\n\tconst id = value.id;\n\tconst namespace = value.namespace;\n\tconst toolName = value.toolName;\n\tconst argumentsValue = value.arguments;\n\tif (\n\t\ttypeof id !== 'string' ||\n\t\ttypeof namespace !== 'string' ||\n\t\ttypeof toolName !== 'string' ||\n\t\t!isObjectRecord(argumentsValue)\n\t) {\n\t\treturn null;\n\t}\n\treturn { arguments: argumentsValue, id, namespace, toolName };\n}\n\nfunction parseCallRequests(params: Record<string, unknown>): readonly PortalCallRequest[] | null {\n\tconst calls = params.calls;\n\tif (!Array.isArray(calls)) {\n\t\treturn null;\n\t}\n\tconst parsedCalls: PortalCallRequest[] = [];\n\tfor (const call of calls) {\n\t\tconst parsedCall = parseCallRequest(call);\n\t\tif (parsedCall === null) {\n\t\t\treturn null;\n\t\t}\n\t\tparsedCalls.push(parsedCall);\n\t}\n\treturn parsedCalls;\n}\n\nfunction fallbackApprovalTokenCallDigests(\n\tcalls: readonly PortalCallRequest[],\n): readonly ApprovalTokenCallDigest[] {\n\treturn calls.map((call) => ({\n\t\targumentsHash: hashCallArguments(call.arguments),\n\t\tnamespace: call.namespace,\n\t\ttoolName: call.toolName,\n\t}));\n}\n\nfunction approvalTokenForCallDigests(props: {\n\treadonly agentId: string;\n\treadonly callDigests: readonly ApprovalTokenCallDigest[];\n\treadonly key: Buffer;\n\treadonly nowMs?: number;\n}): string {\n\tconst nowMs = props.nowMs ?? Date.now();\n\treturn signApprovalToken({\n\t\tagentId: props.agentId,\n\t\tcalls: props.callDigests,\n\t\texpiresAtMs: nowMs + approvalTokenLifetimeMs,\n\t\tissuedAtMs: nowMs,\n\t\tkey: props.key,\n\t});\n}\n\nfunction redactApprovalPreviewValue(key: string, value: unknown): unknown {\n\tif (/token|secret|password|credential|api[-_]?key/iu.test(key)) {\n\t\treturn '[redacted]';\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map((entry) => redactApprovalPreviewValue(key, entry));\n\t}\n\tif (typeof value === 'object' && value !== null) {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([entryKey, entryValue]) => [\n\t\t\t\tentryKey,\n\t\t\t\tredactApprovalPreviewValue(entryKey, entryValue),\n\t\t\t]),\n\t\t);\n\t}\n\treturn value;\n}\n\nfunction approvalCallPreview(call: PortalCallRequest): string {\n\tconst redactedArguments = redactApprovalPreviewValue('arguments', call.arguments);\n\tconst serializedArguments = JSON.stringify(redactedArguments);\n\tconst preview =\n\t\tserializedArguments.length > 500\n\t\t\t? `${serializedArguments.slice(0, 497)}...`\n\t\t\t: serializedArguments;\n\treturn `${call.id}: ${call.namespace}.${call.toolName} args=${preview}`;\n}\n\nexport function createBeforeToolCallHandler(\n\tprops: CreateBeforeToolCallHandlerProps,\n): (\n\tevent: OpenClawBeforeToolCallEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawBeforeToolCallResult | undefined> {\n\treturn async (event, context) => {\n\t\tif (event.toolName !== 'mcp_portal_call') {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (context.agentId === undefined) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: missing OpenClaw agent context for ${event.toolName}.`,\n\t\t\t};\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = context.agentId;\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn { block: true, blockReason: `mcp-portal: agent \"${agentId}\" is not configured.` };\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tconst calls = parseCallRequests(event.params);\n\t\tif (calls === null || calls.length === 0) {\n\t\t\treturn { block: true, blockReason: 'mcp-portal: malformed portal call batch.' };\n\t\t}\n\n\t\tconst disabledCalls = calls.filter((call) => !profileAllowsPortalCall(profile, call));\n\t\tif (disabledCalls.length > 0) {\n\t\t\tif (disabledCalls.length === calls.length) {\n\t\t\t\tconst call = disabledCalls[0];\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\tblockReason:\n\t\t\t\t\t\tcall === undefined\n\t\t\t\t\t\t\t? `policy: ${agentId} has no enabled MCP Portal calls in this batch`\n\t\t\t\t\t\t\t: `policy: ${agentId}/${call.namespace}/${call.toolName} not enabled`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst approvalCalls: PortalCallRequest[] = [];\n\t\tfor (const call of calls) {\n\t\t\tconst decision = profilePortalCallDecision(profile, call);\n\t\t\tif (decision.kind === 'requires_approval') {\n\t\t\t\tapprovalCalls.push(call);\n\t\t\t}\n\t\t}\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (approvalCalls.length !== calls.length) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst toolNames = approvalCalls\n\t\t\t.map((call) => `${call.namespace}.${call.toolName}`)\n\t\t\t.toSorted()\n\t\t\t.join(', ');\n\t\tlet portalApprovalToken: string;\n\t\ttry {\n\t\t\tconst callDigests =\n\t\t\t\t(await props.resolveApprovalTokenCallDigests?.({\n\t\t\t\t\tagentId,\n\t\t\t\t\tapprovalCalls,\n\t\t\t\t\tcontext,\n\t\t\t\t\tparams: event.params,\n\t\t\t\t})) ?? fallbackApprovalTokenCallDigests(approvalCalls);\n\t\t\tif (callDigests.length !== approvalCalls.length) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`prepared ${callDigests.length} approval token digests for ${approvalCalls.length} approval call(s)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tportalApprovalToken = approvalTokenForCallDigests({\n\t\t\t\tagentId,\n\t\t\t\tcallDigests,\n\t\t\t\tkey: props.runtimeState.getApprovalHmacKey(),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = `mcp-portal: failed to prepare approval token: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`;\n\t\t\tprops.logger?.error?.(message);\n\t\t\treturn { block: true, blockReason: message };\n\t\t}\n\t\tconst approvalPreview = approvalCalls.map(approvalCallPreview).join('\\n');\n\t\treturn {\n\t\t\tparams: { ...event.params, portalApprovalToken },\n\t\t\trequireApproval: {\n\t\t\t\tdescription: `Allow MCP Portal batch for agent ${agentId}:\\n${approvalPreview}`,\n\t\t\t\tpluginId: 'mcp-portal',\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttimeoutBehavior: 'deny',\n\t\t\t\ttimeoutMs: approvalPromptTimeoutMs,\n\t\t\t\ttitle: `MCP Portal batch: ${toolNames}`,\n\t\t\t},\n\t\t};\n\t};\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst effectiveConfigManifestFileName = 'mcp-portal-effective-manifest.json';\n\nexport interface EffectiveConfigPaths {\n\treadonly mcpConfigPath: string;\n\treadonly portalConfigPath: string;\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isSafeManifestFileName(value: string): boolean {\n\treturn value.length > 0 && !value.includes('/') && !value.includes('\\\\');\n}\n\nfunction parseEffectiveConfigManifest(value: unknown): {\n\treadonly mcpConfigFile: string;\n\treadonly portalConfigFile: string;\n} {\n\tif (!isObjectRecord(value)) {\n\t\tthrow new Error('MCP Portal effective config manifest must be an object.');\n\t}\n\tif (value.schemaVersion !== 1) {\n\t\tthrow new Error('MCP Portal effective config manifest must use schemaVersion 1.');\n\t}\n\tif (typeof value.mcpConfigFile !== 'string' || !isSafeManifestFileName(value.mcpConfigFile)) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe mcpConfigFile.');\n\t}\n\tif (\n\t\ttypeof value.portalConfigFile !== 'string' ||\n\t\t!isSafeManifestFileName(value.portalConfigFile)\n\t) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe portalConfigFile.');\n\t}\n\treturn {\n\t\tmcpConfigFile: value.mcpConfigFile,\n\t\tportalConfigFile: value.portalConfigFile,\n\t};\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn (\n\t\tisObjectRecord(error) &&\n\t\ttypeof error.code === 'string' &&\n\t\t(error.code === 'ENOENT' || error.code === 'ENOTDIR')\n\t);\n}\n\nexport async function resolveEffectiveConfigPaths(\n\tconfigDir: string,\n): Promise<EffectiveConfigPaths> {\n\tconst manifestPath = join(configDir, effectiveConfigManifestFileName);\n\tlet manifestText: string;\n\ttry {\n\t\tmanifestText = await readFile(manifestPath, 'utf8');\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) {\n\t\t\treturn {\n\t\t\t\tmcpConfigPath: join(configDir, 'mcp.config.jsonc'),\n\t\t\t\tportalConfigPath: join(configDir, 'mcp-portal.config.jsonc'),\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\tconst manifest = parseEffectiveConfigManifest(JSON.parse(manifestText));\n\treturn {\n\t\tmcpConfigPath: join(configDir, manifest.mcpConfigFile),\n\t\tportalConfigPath: join(configDir, manifest.portalConfigFile),\n\t};\n}\n","import { z } from 'zod';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tconfigDir: z.string().min(1),\n\t})\n\t.strict();\n\nexport type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;\n\nexport function parsePortalConfig(value: unknown): PortalPluginConfig {\n\treturn portalPluginConfigSchema.parse(value ?? {});\n}\n","import { randomBytes } from 'node:crypto';\n\nimport { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly consumeApprovalTokenId: (\n\t\tagentId: string,\n\t\tjti: string,\n\t\texpiresAtMs: number,\n\t) =>\n\t\t| { readonly ok: true }\n\t\t| { readonly ok: false; readonly reason: 'replay-cache-full' | 'replayed' };\n\treadonly configDir: string;\n\treadonly getApprovalHmacKey: () => Buffer;\n\treadonly getLoadedPortalConfig: () => McpPortalConfig | null;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet loadedPortalConfig: McpPortalConfig | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst approvalHmacKey = randomBytes(32);\n\tconst consumedApprovalTokenIds = new Map<string, number>();\n\tconst replayCacheLimit = 4096;\n\tconst replayCacheCleanupThreshold = replayCacheLimit / 2;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = resolveEffectiveConfigPaths(props.configDir)\n\t\t\t.then((effectiveConfigPaths) => loadPortalConfigFile(effectiveConfigPaths.portalConfigPath))\n\t\t\t.then((portalConfig) => {\n\t\t\t\tloadedPortalConfig = portalConfig;\n\t\t\t\treturn portalConfig;\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\t\tportalConfigPromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn portalConfigPromise;\n\t}\n\n\tfunction sweepExpiredApprovalTokenIds(nowMs: number): void {\n\t\tif (consumedApprovalTokenIds.size < replayCacheCleanupThreshold) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const [tokenKey, tokenExpiresAtMs] of consumedApprovalTokenIds) {\n\t\t\tif (tokenExpiresAtMs <= nowMs) {\n\t\t\t\tconsumedApprovalTokenIds.delete(tokenKey);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tconsumeApprovalTokenId: (agentId, jti, expiresAtMs) => {\n\t\t\tconst nowMs = Date.now();\n\t\t\tsweepExpiredApprovalTokenIds(nowMs);\n\t\t\tconst tokenKey = `${agentId}\\n${jti}`;\n\t\t\tif (consumedApprovalTokenIds.has(tokenKey)) {\n\t\t\t\treturn { ok: false, reason: 'replayed' };\n\t\t\t}\n\t\t\tif (consumedApprovalTokenIds.size >= replayCacheLimit) {\n\t\t\t\treturn { ok: false, reason: 'replay-cache-full' };\n\t\t\t}\n\t\t\tconsumedApprovalTokenIds.set(tokenKey, expiresAtMs);\n\t\t\treturn { ok: true };\n\t\t},\n\t\tconfigDir: props.configDir,\n\t\tgetApprovalHmacKey: () => approvalHmacKey,\n\t\tgetLoadedPortalConfig: () => loadedPortalConfig,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tloadPortalConfig,\n\t\tmarkPortalAvailable: () => {\n\t\t\tportalUnavailableReason = null;\n\t\t},\n\t\tmarkPortalUnavailable: (reason) => {\n\t\t\tportalUnavailableReason = reason;\n\t\t},\n\t};\n}\n","import {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\ttype McpPortalConfig,\n\tresolveMcpPortalProfile,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport {\n\tcreatePortalCore,\n\tcreatePortalPolicyApprovalEvaluator,\n\tcreateUpstreamMcpClientRuntime,\n\tlistPortalCoreToolDescriptors,\n\tresolveUpstreamServers,\n\ttype PortalCore,\n\ttype PortalCoreEvent,\n\ttype PortalCoreToolDescriptor,\n\ttype PortalToolSelector,\n} from '@agent-vm/mcp-portal/core';\n\nimport { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\nimport type {\n\tOpenClawPortalPluginApi,\n\tOpenClawPluginToolContext,\n\tOpenClawToolRegistration,\n\tOpenClawToolUpdateCallback,\n} from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport { createPortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\ninterface PortalPluginEntry {\n\treadonly description: string;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly register: (api: OpenClawPortalPluginApi) => void;\n}\n\ninterface TcpPoolConfig {\n\treadonly basePort: number;\n\treadonly size: number;\n}\n\ninterface ProfilePolicyMaps {\n\treadonly cacheTtlMs: number;\n\treadonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;\n\treadonly enabledToolsByNamespaceByAgent: Readonly<\n\t\tRecord<string, Readonly<Record<string, readonly string[]>>>\n\t>;\n\treadonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n}\n\nconst pluginId = 'mcp-portal';\n\nfunction hasFunction(value: unknown): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === 'function';\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isUnknownArray(value: unknown): value is readonly unknown[] {\n\treturn Array.isArray(value);\n}\n\nfunction getObjectProperty(value: unknown, property: string): unknown {\n\treturn isObjectRecord(value) ? value[property] : undefined;\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tif (api.pluginConfig !== undefined) {\n\t\treturn parsePortalConfig(api.pluginConfig).configDir;\n\t}\n\t// Managed agent-vm passes pluginConfig. The config fallbacks keep the plugin usable\n\t// in direct OpenClaw test harnesses that load plugin config through the root config.\n\tconst topLevelMcpConfigDir = getObjectProperty(\n\t\tgetObjectProperty(api.config, 'mcpPortal'),\n\t\t'configDir',\n\t);\n\tif (typeof topLevelMcpConfigDir === 'string' && topLevelMcpConfigDir.length > 0) {\n\t\treturn topLevelMcpConfigDir;\n\t}\n\tconst zones = getObjectProperty(api.config, 'zones');\n\tif (isUnknownArray(zones)) {\n\t\tconst firstZone = zones.at(0);\n\t\tconst zoneMcpConfigDir = getObjectProperty(\n\t\t\tgetObjectProperty(firstZone, 'mcpPortal'),\n\t\t\t'configDir',\n\t\t);\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'MCP Portal plugin requires configDir in plugin config or zone mcpPortal config.',\n\t);\n}\n\nexport function validatePortalPortAgainstTcpPool(props: {\n\treadonly port: number;\n\treadonly tcpPool: TcpPoolConfig | null;\n}): void {\n\tif (props.tcpPool === null) {\n\t\treturn;\n\t}\n\tconst firstTcpPoolPort = props.tcpPool.basePort;\n\tconst lastTcpPoolPortExclusive = props.tcpPool.basePort + props.tcpPool.size;\n\tif (props.port >= firstTcpPoolPort && props.port < lastTcpPoolPortExclusive) {\n\t\tthrow new Error(\n\t\t\t`MCP Portal port ${String(props.port)} overlaps the Tool VM TCP pool ` +\n\t\t\t\t`[${String(firstTcpPoolPort)}, ${String(lastTcpPoolPortExclusive)}).`,\n\t\t);\n\t}\n}\n\nfunction createLoggerAdapter(api: OpenClawPortalPluginApi): {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n} {\n\treturn {\n\t\terror: (message) => api.logger?.error?.(message),\n\t\tinfo: (message) => api.logger?.info?.(message),\n\t\twarn: (message) => api.logger?.warn?.(message),\n\t};\n}\n\nexport function validatePortalPluginApi(api: OpenClawPortalPluginApi): void {\n\tif (!hasFunction(api.registerTool)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerTool API.');\n\t}\n\tif (!hasFunction(api.on)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw before_tool_call hook API.');\n\t}\n\tconst hasLifecycleCleanupApi =\n\t\thasFunction(api.lifecycle?.registerRuntimeLifecycle) ||\n\t\thasFunction(api.registerRuntimeLifecycle);\n\tif (hasLifecycleCleanupApi) {\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction registerPortalRuntimeCleanup(\n\tapi: OpenClawPortalPluginApi,\n\tcleanup: () => Promise<void> | void,\n): void {\n\tconst runtimeLifecycle = {\n\t\tcleanup: async () => {\n\t\t\tawait cleanup();\n\t\t},\n\t\tdescription: 'Closes MCP Portal upstream clients owned by the agent-vm plugin.',\n\t\tid: 'mcp-portal-core',\n\t} satisfies Parameters<NonNullable<OpenClawPortalPluginApi['registerRuntimeLifecycle']>>[0];\n\tif (hasFunction(api.lifecycle?.registerRuntimeLifecycle)) {\n\t\tapi.lifecycle.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tif (hasFunction(api.registerRuntimeLifecycle)) {\n\t\tapi.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction selectorsFromNamespaceTools(\n\tnamespaceTools: Readonly<Record<string, readonly string[]>>,\n): readonly PortalToolSelector[] {\n\treturn Object.entries(namespaceTools).flatMap(([namespace, toolNames]) =>\n\t\ttoolNames.map((toolName) => ({ namespace, toolName })),\n\t);\n}\n\nfunction buildProfilePolicyMaps(portalConfig: McpPortalConfig): ProfilePolicyMaps {\n\tconst enabledNamespacesByAgent: Record<string, readonly string[]> = {};\n\tconst enabledToolsByNamespaceByAgent: Record<\n\t\tstring,\n\t\tReadonly<Record<string, readonly string[]>>\n\t> = {};\n\tconst hiddenToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst profileTtls: number[] = [];\n\n\tfor (const [agentId, agent] of Object.entries(portalConfig.agents)) {\n\t\tconst profile: ResolvedMcpPortalProfile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tenabledNamespacesByAgent[agentId] = profile.enabledNamespaces;\n\t\tenabledToolsByNamespaceByAgent[agentId] = profile.enabledToolsByNamespace;\n\t\thiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);\n\t\tprofileTtls.push(profile.cache.catalogTtlMs);\n\t}\n\n\treturn {\n\t\tcacheTtlMs: profileTtls.length === 0 ? 60_000 : Math.min(...profileTtls),\n\t\tenabledNamespacesByAgent,\n\t\tenabledToolsByNamespaceByAgent,\n\t\thiddenToolsByAgent,\n\t};\n}\n\nasync function resolveManagedPortalSecret(secret: SecretValue): Promise<string> {\n\tif (secret.source !== 'environment') {\n\t\tthrow new Error(\n\t\t\t'MCP Portal managed OpenClaw effective config must use environment secret refs.',\n\t\t);\n\t}\n\tconst value = process.env[secret.name];\n\tif (value === undefined || value.length === 0) {\n\t\tthrow new Error(`Missing environment secret ${secret.name} for MCP Portal native plugin.`);\n\t}\n\treturn value;\n}\n\nasync function createManagedPortalCore(\n\tconfigDir: string,\n\truntimeState: ReturnType<typeof createPortalPluginRuntimeState>,\n): Promise<PortalCore> {\n\tconst effectiveConfigPaths = await resolveEffectiveConfigPaths(configDir);\n\tconst [mcpConfig, portalConfig] = await Promise.all([\n\t\tloadMcpConfig(effectiveConfigPaths.mcpConfigPath),\n\t\tloadMcpPortalConfig(effectiveConfigPaths.portalConfigPath),\n\t]);\n\tconst upstreamServers = await resolveUpstreamServers({\n\t\tconfig: mcpConfig,\n\t\tresolveSecret: resolveManagedPortalSecret,\n\t});\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\tconst approval = createPortalPolicyApprovalEvaluator({\n\t\tconsumeTokenId: (agentId, jti, expiresAtMs) =>\n\t\t\truntimeState.consumeApprovalTokenId(agentId, jti, expiresAtMs),\n\t\tmissingApprovalTokenDecision: { kind: 'approval_required', level: 'standard' },\n\t\tresolveRecord: (agentId) => {\n\t\t\tconst agent = portalConfig.agents[agentId];\n\t\t\tif (agent === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\thmacKey: runtimeState.getApprovalHmacKey(),\n\t\t\t\tprofile: resolveMcpPortalProfile(portalConfig, agent.profile),\n\t\t\t};\n\t\t},\n\t});\n\n\treturn createPortalCore({\n\t\taccessPolicy: {\n\t\t\tdefaultPolicy: 'deny-all',\n\t\t\tenabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,\n\t\t\tenabledToolsByNamespaceByAgent: profilePolicyMaps.enabledToolsByNamespaceByAgent,\n\t\t\thiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent,\n\t\t},\n\t\tapproval,\n\t\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: {\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tcloseAgentScope: upstreamRuntime.closeAgentScope,\n\t\t\tcloseSession: upstreamRuntime.closeSession,\n\t\t\tlistTools: upstreamRuntime.listTools,\n\t\t},\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n}\n\nfunction portalUpdateFromCoreEvent(event: PortalCoreEvent): Record<string, unknown> | null {\n\tif (event.kind === 'progress') {\n\t\treturn {\n\t\t\tmessage: event.message ?? 'MCP Portal progress',\n\t\t\t...(event.progress !== undefined ? { progress: event.progress } : {}),\n\t\t\trequestId: event.requestId,\n\t\t\t...(event.total !== undefined ? { total: event.total } : {}),\n\t\t\ttype: 'mcp_portal_progress',\n\t\t};\n\t}\n\tif (event.kind === 'partial_content') {\n\t\treturn {\n\t\t\tcontent: event.content,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_partial_content',\n\t\t};\n\t}\n\tif (event.kind === 'upstream_notification') {\n\t\treturn {\n\t\t\tmethod: event.method,\n\t\t\tparams: event.params,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_upstream_notification',\n\t\t};\n\t}\n\treturn null;\n}\n\nasync function forwardCoreEvent(\n\tevent: PortalCoreEvent,\n\tlogger: ReturnType<typeof createLoggerAdapter>,\n\tonUpdate: OpenClawToolUpdateCallback | undefined,\n): Promise<void> {\n\tconst update = portalUpdateFromCoreEvent(event);\n\tif (update !== null) {\n\t\ttry {\n\t\t\tawait onUpdate?.(update);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tlogger.warn(`[mcp-portal] OpenClaw onUpdate delivery failed: ${message}`);\n\t\t}\n\t}\n}\n\nfunction createNativeTool(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly descriptor: PortalCoreToolDescriptor;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly logger: ReturnType<typeof createLoggerAdapter>;\n}): OpenClawToolRegistration {\n\treturn {\n\t\tdescription: props.descriptor.description,\n\t\texecute: async (_toolCallId, params, signal, onUpdate) => {\n\t\t\tif (props.context.agentId === undefined || props.context.agentId.length === 0) {\n\t\t\t\tthrow new Error('mcp-portal: OpenClaw did not provide a trusted agentId.');\n\t\t\t}\n\t\t\tconst core = await props.getCore();\n\t\t\tconst scope = core.createAgentScope({\n\t\t\t\tagentId: props.context.agentId,\n\t\t\t\tagentScopeId: props.context.agentId,\n\t\t\t\t...(props.context.sessionId ? { sessionId: props.context.sessionId } : {}),\n\t\t\t\t...(props.context.sessionKey ? { sessionKey: props.context.sessionKey } : {}),\n\t\t\t\tsource: 'openclaw-trusted',\n\t\t\t});\n\t\t\tconst result = await core.collectPortalCoreResult(\n\t\t\t\tcore.callStream({\n\t\t\t\t\tinput: params,\n\t\t\t\t\tscope,\n\t\t\t\t\t...(signal !== undefined ? { signal } : {}),\n\t\t\t\t\ttoolName: props.descriptor.name,\n\t\t\t\t}),\n\t\t\t\t{ onEvent: (event) => forwardCoreEvent(event, props.logger, onUpdate) },\n\t\t\t);\n\t\t\treturn { content: JSON.stringify(result), details: result };\n\t\t},\n\t\tlabel: props.descriptor.name,\n\t\tname: props.descriptor.name,\n\t\tparameters: props.descriptor.inputSchema,\n\t};\n}\n\nfunction descriptorsForOpenClawContext(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly portalConfig: McpPortalConfig | null;\n}): readonly PortalCoreToolDescriptor[] {\n\tif (props.portalConfig === null || props.context.agentId === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst agent = props.portalConfig.agents[props.context.agentId];\n\tif (agent === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst profile = resolveMcpPortalProfile(props.portalConfig, agent.profile);\n\treturn listPortalCoreToolDescriptors(profile.enabledNamespaces);\n}\n\nfunction registerNativePortalTools(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly runtimeState: ReturnType<typeof createPortalPluginRuntimeState>;\n}): void {\n\tconst descriptorNames = listPortalCoreToolDescriptors().map((descriptor) => descriptor.name);\n\tconst logger = createLoggerAdapter(props.api);\n\tprops.api.registerTool?.(\n\t\t(context) => {\n\t\t\tconst descriptors = descriptorsForOpenClawContext({\n\t\t\t\tcontext,\n\t\t\t\tportalConfig: props.runtimeState.getLoadedPortalConfig(),\n\t\t\t});\n\t\t\treturn descriptors.map((descriptor) =>\n\t\t\t\tcreateNativeTool({ context, descriptor, getCore: props.getCore, logger }),\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tnames: descriptorNames,\n\t\t\toptional: true,\n\t\t},\n\t);\n}\n\nfunction shouldRegisterPortalRuntimeHooks(api: OpenClawPortalPluginApi): boolean {\n\treturn api.registrationMode === undefined || api.registrationMode === 'full';\n}\n\nfunction formatRegistrationMode(api: OpenClawPortalPluginApi): string {\n\treturn api.registrationMode ?? 'full';\n}\n\nexport function registerMcpPortalPlugin(api: OpenClawPortalPluginApi): void {\n\tconst logger = createLoggerAdapter(api);\n\tconst registerRuntimeHooks = shouldRegisterPortalRuntimeHooks(api);\n\tif (registerRuntimeHooks) {\n\t\tvalidatePortalPluginApi(api);\n\t} else if (!hasFunction(api.registerTool)) {\n\t\tlogger.warn(\n\t\t\t`[mcp-portal] skipped native portal tool registration for registrationMode='${formatRegistrationMode(api)}' because OpenClaw did not expose registerTool.`,\n\t\t);\n\t\treturn;\n\t}\n\tconst configDir = resolveConfigDir(api);\n\tconst runtimeState = createPortalPluginRuntimeState({ configDir });\n\tlet corePromise: Promise<PortalCore> | undefined;\n\tconst getCore = (): Promise<PortalCore> => {\n\t\tcorePromise ??= createManagedPortalCore(configDir, runtimeState).catch((error: unknown) => {\n\t\t\tcorePromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t\treturn corePromise;\n\t};\n\tregisterNativePortalTools({ api, getCore, runtimeState });\n\n\tif (!registerRuntimeHooks) {\n\t\tlogger.info(\n\t\t\t`[mcp-portal] registered native portal tools for registrationMode='${formatRegistrationMode(api)}'.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tapi.on?.(\n\t\t'before_tool_call',\n\t\tcreateBeforeToolCallHandler({\n\t\t\tlogger,\n\t\t\tresolveApprovalTokenCallDigests: async ({ agentId, approvalCalls, context, params }) => {\n\t\t\t\tconst core = await getCore();\n\t\t\t\tconst scope = core.createAgentScope({\n\t\t\t\t\tagentId,\n\t\t\t\t\tagentScopeId: agentId,\n\t\t\t\t\t...(context.sessionId ? { sessionId: context.sessionId } : {}),\n\t\t\t\t\t...(context.sessionKey ? { sessionKey: context.sessionKey } : {}),\n\t\t\t\t\tsource: 'openclaw-trusted',\n\t\t\t\t});\n\t\t\t\tconst digestsByCallId = await core.approval.prepareCallDigests({ input: params, scope });\n\t\t\t\tif (digestsByCallId === null) {\n\t\t\t\t\tthrow new Error('MCP Portal core could not prepare approval token digests.');\n\t\t\t\t}\n\t\t\t\treturn approvalCalls.map((call) => {\n\t\t\t\t\tconst digest = digestsByCallId[call.id];\n\t\t\t\t\tif (digest === undefined) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`MCP Portal core did not prepare an approval token digest for call '${call.id}'.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn digest;\n\t\t\t\t});\n\t\t\t},\n\t\t\truntimeState,\n\t\t}),\n\t\t{\n\t\t\tpriority: 80,\n\t\t},\n\t);\n\n\tapi.on?.('before_prompt_build', createBeforePromptBuildHandler({ runtimeState }), {\n\t\tpriority: 80,\n\t});\n\n\tif (!api.on && api.registerPromptHook) {\n\t\tapi.registerPromptHook('before_prompt_build', async (context) => {\n\t\t\tconst handler = createBeforePromptBuildHandler({ runtimeState });\n\t\t\tconst result = await handler({}, context);\n\t\t\tif (result?.appendSystemContext !== undefined) {\n\t\t\t\tcontext.appendPrompt?.(result.appendSystemContext);\n\t\t\t}\n\t\t});\n\t}\n\n\tregisterPortalRuntimeCleanup(api, async () => {\n\t\tconst core = await corePromise?.catch(() => undefined);\n\t\tawait core?.close();\n\t});\n\tlogger.info('[mcp-portal] registered native portal tools and runtime hooks.');\n}\n\nconst pluginEntry = {\n\tdescription: 'Registers native OpenClaw MCP Portal tools and wires per-agent approval hooks.',\n\tid: pluginId,\n\tname: 'MCP Portal',\n\tregister: registerMcpPortalPlugin,\n} satisfies PortalPluginEntry;\n\nexport default pluginEntry;\n","export interface PortalPromptNamespaceSummary {\n\treadonly namespace: string;\n\treadonly toolCount: number;\n}\n\nexport interface PortalPromptDiagnostic {\n\treadonly hint?: string;\n\treadonly message: string;\n\treadonly namespace: string;\n\treadonly phase?: string;\n}\n\nfunction formatDiagnostic(entry: PortalPromptDiagnostic): string {\n\tconst phase = entry.phase === undefined ? '' : ` ${entry.phase}`;\n\tconst hint = entry.hint === undefined ? '' : ` Hint: ${entry.hint}`;\n\treturn `${entry.namespace}${phase}: ${entry.message}.${hint}`;\n}\n\nexport function createPortalPromptContext(props: {\n\treadonly diagnostics?: readonly PortalPromptDiagnostic[];\n\treadonly namespaces: readonly PortalPromptNamespaceSummary[];\n}): string {\n\tconst namespaceList =\n\t\tprops.namespaces.length > 0\n\t\t\t? props.namespaces.map((entry) => `${entry.namespace}(${entry.toolCount} tools)`).join(', ')\n\t\t\t: 'none configured';\n\tconst diagnostics =\n\t\tprops.diagnostics !== undefined && props.diagnostics.length > 0\n\t\t\t? [`Discovery diagnostics: ${props.diagnostics.map(formatDiagnostic).join('; ')}`]\n\t\t\t: [];\n\n\treturn [\n\t\t'MCP Portal is available as native OpenClaw tools.',\n\t\t'Use mcp_portal_list with requests[], mcp_portal_search with requests[],',\n\t\t'mcp_portal_describe with requests[], and mcp_portal_call with calls[].',\n\t\t'Responses are { ok, results, errors, diagnostics }; results is keyed by each request/call id and each value is discriminated by ok: true or ok: false.',\n\t\t'Call upstream tools by namespace + toolName inside calls[].',\n\t\t'Call mcp_portal_describe before mcp_portal_call unless you already saw the full schema for that tool in this portal session.',\n\t\t'Gateway owns MCP auth.',\n\t\t`Namespaces: ${namespaceList}`,\n\t\t...diagnostics,\n\t].join('\\n');\n}\n","import { redactCredentialText } from '@agent-vm/mcp-portal/core';\n\nexport function redactPortalSecrets(text: string, secretValues: readonly string[] = []): string {\n\treturn secretValues\n\t\t.filter((secretValue) => secretValue.length > 0)\n\t\t.reduce(\n\t\t\t(current, secretValue) => current.split(secretValue).join('[REDACTED]'),\n\t\t\tredactCredentialText(text),\n\t\t);\n}\n","export * from './openclaw-plugin-api.js';\nexport * from './plugin-registration.js';\nexport * from './before-prompt-build-handler.js';\nexport * from './before-tool-call-handler.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-tool-policy.js';\nexport * from './portal-prompt-context.js';\nexport * from './redaction.js';\nexport { default } from './plugin-registration.js';\n\nexport const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = '@agent-vm/openclaw-mcp-portal-plugin';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-vm/openclaw-mcp-portal-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.82",
|
|
4
4
|
"description": "OpenClaw plugin that registers native MCP Portal tools over configured upstream MCP servers.",
|
|
5
5
|
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"zod": "^4.4.3",
|
|
34
|
-
"@agent-vm/
|
|
35
|
-
"@agent-vm/
|
|
34
|
+
"@agent-vm/config-contracts": "0.0.82",
|
|
35
|
+
"@agent-vm/mcp-portal": "0.0.82"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"openclaw": "^2026.5.7",
|