@agent-vm/openclaw-mcp-portal-plugin 0.0.68 → 0.0.69
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 +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -6
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpPortalConfig, ResolvedMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
1
|
+
import { McpConfig, McpPortalConfig, ResolvedMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ChildProcess, SpawnOptions } from "node:child_process";
|
|
4
4
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
@@ -110,6 +110,11 @@ interface TcpPoolConfig {
|
|
|
110
110
|
readonly basePort: number;
|
|
111
111
|
readonly size: number;
|
|
112
112
|
}
|
|
113
|
+
declare function createPortalSubprocessConfigEnv(props: {
|
|
114
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
115
|
+
readonly mcpConfig: McpConfig;
|
|
116
|
+
readonly mcpPortalConfig: McpPortalConfig;
|
|
117
|
+
}): Readonly<Record<string, string>>;
|
|
113
118
|
declare function validatePortalPortAgainstTcpPool(props: {
|
|
114
119
|
readonly port: number;
|
|
115
120
|
readonly tcpPool: TcpPoolConfig | null;
|
|
@@ -193,6 +198,7 @@ interface CreatePortalSubprocessSupervisorProps {
|
|
|
193
198
|
readonly maxRestarts?: number;
|
|
194
199
|
readonly onFatal?: (reason: string) => void;
|
|
195
200
|
readonly port: number;
|
|
201
|
+
readonly portalEnv?: Readonly<Record<string, string>>;
|
|
196
202
|
readonly spawnFn?: PortalSubprocessSpawnFunction;
|
|
197
203
|
readonly stopGraceMs?: number;
|
|
198
204
|
}
|
|
@@ -241,5 +247,5 @@ declare function redactPortalSecrets(text: string, secretValues?: readonly strin
|
|
|
241
247
|
//#region src/index.d.ts
|
|
242
248
|
declare const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-mcp-portal-plugin";
|
|
243
249
|
//#endregion
|
|
244
|
-
export { CreateBeforePromptBuildHandlerProps, CreateBeforeToolCallHandlerProps, CreateHmacKeyRegistryProps, CreatePortalSubprocessSupervisorProps, HmacKeyRegistry, OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME, OpenClawAgentTurnPrepareEvent, OpenClawApprovalResolution, OpenClawBeforePromptBuildEvent, OpenClawBeforeToolCallEvent, OpenClawBeforeToolCallResult, OpenClawHttpRouteRegistration, OpenClawPluginHookContext, OpenClawPluginHookEventMap, OpenClawPluginHookOptions, OpenClawPluginHookResultMap, OpenClawPluginHostCleanupReason, OpenClawPluginService, OpenClawPortalPluginApi, OpenClawPromptHookContext, OpenClawPromptHookResult, OpenClawRuntimeLifecycleRegistrar, OpenClawRuntimeLifecycleRegistration, PortalCallRequest, PortalPluginConfig, PortalPluginRuntimeState, PortalPromptDiagnostic, PortalPromptNamespaceSummary, PortalSubprocessLogger, PortalSubprocessSpawnFunction, PortalSubprocessSupervisor, createBeforePromptBuildHandler, createBeforeToolCallHandler, createHmacKeyRegistry, createPortalPluginRuntimeState, createPortalPromptContext, createPortalSubprocessSupervisor, pluginEntry as default, defaultPortalBinPath, materializedPortalToolNames, parsePortalConfig, portalPluginConfigSchema, portalServerNameForAgent, profileAllowsPortalCall, profileRequiresPortalApproval, redactPortalSecrets, registerMcpPortalPlugin, validatePortalPluginApi, validatePortalPortAgainstTcpPool };
|
|
250
|
+
export { CreateBeforePromptBuildHandlerProps, CreateBeforeToolCallHandlerProps, CreateHmacKeyRegistryProps, CreatePortalSubprocessSupervisorProps, HmacKeyRegistry, OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME, OpenClawAgentTurnPrepareEvent, OpenClawApprovalResolution, OpenClawBeforePromptBuildEvent, OpenClawBeforeToolCallEvent, OpenClawBeforeToolCallResult, OpenClawHttpRouteRegistration, OpenClawPluginHookContext, OpenClawPluginHookEventMap, OpenClawPluginHookOptions, OpenClawPluginHookResultMap, OpenClawPluginHostCleanupReason, OpenClawPluginService, OpenClawPortalPluginApi, OpenClawPromptHookContext, OpenClawPromptHookResult, OpenClawRuntimeLifecycleRegistrar, OpenClawRuntimeLifecycleRegistration, PortalCallRequest, PortalPluginConfig, PortalPluginRuntimeState, PortalPromptDiagnostic, PortalPromptNamespaceSummary, PortalSubprocessLogger, PortalSubprocessSpawnFunction, PortalSubprocessSupervisor, createBeforePromptBuildHandler, createBeforeToolCallHandler, createHmacKeyRegistry, createPortalPluginRuntimeState, createPortalPromptContext, createPortalSubprocessConfigEnv, createPortalSubprocessSupervisor, pluginEntry as default, defaultPortalBinPath, materializedPortalToolNames, parsePortalConfig, portalPluginConfigSchema, portalServerNameForAgent, profileAllowsPortalCall, profileRequiresPortalApproval, redactPortalSecrets, registerMcpPortalPlugin, validatePortalPluginApi, validatePortalPortAgainstTcpPool };
|
|
245
251
|
//# sourceMappingURL=index.d.ts.map
|
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/hmac-key-registry.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/before-tool-call-handler.ts","../src/portal-config.ts","../src/portal-subprocess-supervisor.ts","../src/portal-tool-policy.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"mappings":";;;;;;UAEiB,yBAAA;EAAA,SACP,OAAA;EAAA,SACA,YAAA,IAAgB,OAAA;AAAA;AAAA,UAGT,yBAAA;EAAA,SACP,OAAA;EAAA,SACA,SAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGO,6BAAA;EAAA,SACP,QAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGO,8BAAA;EAAA,SACP,QAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGO,2BAAA;EAAA,SACP,MAAA,EAAQ,MAAA;EAAA,SACR,UAAA;EAAA,SACA,QAAA;AAAA;AAAA,KAGE,0BAAA;AAAA,UAOK,4BAAA;EAAA,SACP,KAAA;EAAA,SACA,WAAA;EAAA,SACA,eAAA;IAAA,SACC,WAAA;IAAA,SACA,YAAA,IAAgB,QAAA,EAAU,0BAAA,KAA+B,OAAA;IAAA,SACzD,QAAA;IAAA,SACA,QAAA;IAAA,SACA,eAAA;IAAA,SACA,SAAA;IAAA,SACA,KAAA;EAAA;AAAA;AAAA,UAIM,wBAAA;EAAA,SACP,aAAA;EAAA,SACA,mBAAA;EAAA,SACA,cAAA;EAAA,SACA,oBAAA;AAAA;AAAA,KAGE,0BAAA;EAAA,SACF,kBAAA,EAAoB,6BAAA;EAAA,SACpB,mBAAA,EAAqB,8BAAA;EAAA,SACrB,gBAAA,EAAkB,2BAAA;AAAA;AAAA,KAGhB,2BAAA;EAAA,SACF,kBAAA,EAAoB,wBAAA;EAAA,SACpB,mBAAA,EAAqB,wBAAA;EAAA,SACrB,gBAAA,EAAkB,4BAAA;AAAA;AAAA,UAGX,yBAAA;EAAA,SACP,QAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGO,6BAAA;EAAA,SACP,IAAA;EAAA,SACA,OAAA,GACR,OAAA,EAAS,eAAA,EACT,QAAA,EAAU,cAAA,KACN,OAAA;EAAA,SACI,KAAA;EAAA,SACA,IAAA;EAAA,SACA,eAAA;AAAA;AAAA,UAGO,qBAAA;EAAA,SACP,EAAA;EAAA,SACA,KAAA,QAAa,OAAA;EAAA,SACb,IAAA,SAAa,OAAA;AAAA;AAAA,KAGX,+BAAA;AAAA,UAEK,oCAAA;EAAA,SACP,EAAA;EAAA,SACA,WAAA;EAAA,SACA,OAAA,IAAW,OAAA;IAAA,SACV,MAAA,EAAQ,+BAAA;IAAA,SACR,UAAA;IAAA,SACA,KAAA;EAAA,MACJ,OAAA;AAAA;AAAA,KAGK,iCAAA,IACX,SAAA,EAAW,oCAAA;AAAA,UAGK,uBAAA;EAAA,SACP,MAAA;EAAA,SACA,SAAA;IAAA,SACC,wBAAA,EAA0B,iCAAA;EAAA;EAAA,SAE3B,MAAA;IAAA,SACC,KAAA,IAAS,OAAA;IAAA,SACT,KAAA,IAAS,OAAA;IAAA,SACT,IAAA,IAAQ,OAAA;IAAA,SACR,IAAA,IAAQ,OAAA;EAAA;EAAA,SAET,YAAA;EAAA,SACA,gBAAA;EAAA,SACA,wBAAA,GAA2B,iCAAA;EAAA,SAC3B,eAAA,IAAmB,OAAA,EAAS,qBAAA;EAAA,SAC5B,EAAA,4BAA8B,0BAAA,EACtC,QAAA,EAAU,SAAA,EACV,OAAA,GACC,KAAA,EAAO,0BAAA,CAA2B,SAAA,GAClC,OAAA,EAAS,yBAAA,KAEP,2BAAA,CAA4B,SAAA,IAC5B,OAAA,CAAQ,2BAAA,CAA4B,SAAA,kBAEvC,OAAA,GAAU,yBAAA;EAAA,SAEF,kBAAA,IACR,QAAA,gDACA,OAAA,GAAU,OAAA,EAAS,yBAAA,KAA8B,OAAA;EAAA,SAEzC,iBAAA,IAAqB,YAAA,EAAc,6BAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-plugin-api.ts","../src/plugin-registration.ts","../src/hmac-key-registry.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/before-tool-call-handler.ts","../src/portal-config.ts","../src/portal-subprocess-supervisor.ts","../src/portal-tool-policy.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,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { loadMcpConfig, loadMcpPortalConfig, mcpPortalCallRequiresApproval, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
2
3
|
import { hashCallArguments, portalHmacKeyEnvName, redactCredentialText, signApprovalToken } from "@agent-vm/mcp-portal";
|
|
3
4
|
import { randomBytes } from "node:crypto";
|
|
4
5
|
import { z } from "zod";
|
|
5
|
-
import { join } from "node:path";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
//#region src/before-prompt-build-handler.ts
|
|
8
8
|
function createBeforePromptBuildHandler(props) {
|
|
@@ -239,7 +239,7 @@ const inheritedPortalEnvNames = [
|
|
|
239
239
|
"TMP",
|
|
240
240
|
"TMPDIR"
|
|
241
241
|
];
|
|
242
|
-
function createPortalSubprocessEnv(hmacEnv) {
|
|
242
|
+
function createPortalSubprocessEnv(hmacEnv, portalEnv = {}) {
|
|
243
243
|
const env = {};
|
|
244
244
|
for (const name of inheritedPortalEnvNames) {
|
|
245
245
|
const value = process.env[name];
|
|
@@ -247,6 +247,7 @@ function createPortalSubprocessEnv(hmacEnv) {
|
|
|
247
247
|
}
|
|
248
248
|
return {
|
|
249
249
|
...env,
|
|
250
|
+
...portalEnv,
|
|
250
251
|
...hmacEnv
|
|
251
252
|
};
|
|
252
253
|
}
|
|
@@ -327,7 +328,7 @@ function createPortalSubprocessSupervisor(props) {
|
|
|
327
328
|
let restartCount = 0;
|
|
328
329
|
const spawnChild = () => {
|
|
329
330
|
const nextChild = spawnFn(props.binPath, ["--config-dir", props.configDir], {
|
|
330
|
-
env: createPortalSubprocessEnv(props.hmacEnv),
|
|
331
|
+
env: createPortalSubprocessEnv(props.hmacEnv, props.portalEnv),
|
|
331
332
|
stdio: [
|
|
332
333
|
"ignore",
|
|
333
334
|
"pipe",
|
|
@@ -448,6 +449,12 @@ function createPortalSubprocessSupervisor(props) {
|
|
|
448
449
|
//#endregion
|
|
449
450
|
//#region src/plugin-registration.ts
|
|
450
451
|
const pluginId = "mcp-portal";
|
|
452
|
+
const onePasswordCliEnvNames = [
|
|
453
|
+
"OP_SERVICE_ACCOUNT_TOKEN",
|
|
454
|
+
"OP_ACCOUNT",
|
|
455
|
+
"OP_CONNECT_HOST",
|
|
456
|
+
"OP_CONNECT_TOKEN"
|
|
457
|
+
];
|
|
451
458
|
function hasFunction(value) {
|
|
452
459
|
return typeof value === "function";
|
|
453
460
|
}
|
|
@@ -463,6 +470,57 @@ function getObjectProperty(value, property) {
|
|
|
463
470
|
function messageFromUnknown(error) {
|
|
464
471
|
return error instanceof Error ? error.message : String(error);
|
|
465
472
|
}
|
|
473
|
+
function addEnvironmentSecretName(names, secret) {
|
|
474
|
+
if (secret.source === "environment") names.add(secret.name);
|
|
475
|
+
}
|
|
476
|
+
function secretUsesOnePassword(secret) {
|
|
477
|
+
return secret.source === "1password";
|
|
478
|
+
}
|
|
479
|
+
function collectMcpConfigEnvironmentSecretNames(config) {
|
|
480
|
+
const names = /* @__PURE__ */ new Set();
|
|
481
|
+
for (const provider of Object.values(config.providers)) {
|
|
482
|
+
const transport = provider.transport;
|
|
483
|
+
const secrets = transport.kind === "stdio" ? Object.values(transport.env) : Object.values(transport.headers);
|
|
484
|
+
for (const secret of secrets) addEnvironmentSecretName(names, secret);
|
|
485
|
+
}
|
|
486
|
+
return names;
|
|
487
|
+
}
|
|
488
|
+
function collectMcpPortalConfigEnvironmentSecretNames(config) {
|
|
489
|
+
const names = /* @__PURE__ */ new Set();
|
|
490
|
+
addEnvironmentSecretName(names, config.server.accessHeader.secret);
|
|
491
|
+
for (const agent of Object.values(config.agents)) if (agent.hmacKey !== void 0) addEnvironmentSecretName(names, agent.hmacKey);
|
|
492
|
+
return names;
|
|
493
|
+
}
|
|
494
|
+
function mcpConfigUsesOnePassword(config) {
|
|
495
|
+
return Object.values(config.providers).some((provider) => {
|
|
496
|
+
const transport = provider.transport;
|
|
497
|
+
return (transport.kind === "stdio" ? Object.values(transport.env) : Object.values(transport.headers)).some(secretUsesOnePassword);
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function mcpPortalConfigUsesOnePassword(config) {
|
|
501
|
+
return secretUsesOnePassword(config.server.accessHeader.secret) || Object.values(config.agents).some((agent) => agent.hmacKey !== void 0 && secretUsesOnePassword(agent.hmacKey));
|
|
502
|
+
}
|
|
503
|
+
function resolveRequiredPortalEnv(props) {
|
|
504
|
+
const resolvedEnv = {};
|
|
505
|
+
for (const name of [...props.names].toSorted()) {
|
|
506
|
+
const value = props.env[name];
|
|
507
|
+
if (value === void 0 || value.length === 0) throw new Error(`Missing environment secret ${name} for MCP Portal subprocess.`);
|
|
508
|
+
resolvedEnv[name] = value;
|
|
509
|
+
}
|
|
510
|
+
return resolvedEnv;
|
|
511
|
+
}
|
|
512
|
+
function createPortalSubprocessConfigEnv(props) {
|
|
513
|
+
const env = props.env ?? process.env;
|
|
514
|
+
const portalEnv = { ...resolveRequiredPortalEnv({
|
|
515
|
+
env,
|
|
516
|
+
names: new Set([...collectMcpConfigEnvironmentSecretNames(props.mcpConfig), ...collectMcpPortalConfigEnvironmentSecretNames(props.mcpPortalConfig)])
|
|
517
|
+
}) };
|
|
518
|
+
if (mcpConfigUsesOnePassword(props.mcpConfig) || mcpPortalConfigUsesOnePassword(props.mcpPortalConfig)) for (const name of onePasswordCliEnvNames) {
|
|
519
|
+
const value = env[name];
|
|
520
|
+
if (value !== void 0 && value.length > 0) portalEnv[name] = value;
|
|
521
|
+
}
|
|
522
|
+
return portalEnv;
|
|
523
|
+
}
|
|
466
524
|
function resolveConfigDir(api) {
|
|
467
525
|
const pluginConfig = parsePortalConfig(api.pluginConfig ?? {});
|
|
468
526
|
if (pluginConfig.configDir !== void 0) return pluginConfig.configDir;
|
|
@@ -528,6 +586,7 @@ function registerPortalService(props) {
|
|
|
528
586
|
id: "mcp-portal-subprocess",
|
|
529
587
|
start: async () => {
|
|
530
588
|
const mcpPortalConfig = await props.runtimeState.loadPortalConfig();
|
|
589
|
+
const mcpConfig = await loadMcpConfig(join(props.configDir, "mcp.config.jsonc"));
|
|
531
590
|
validatePortalPortAgainstTcpPool({
|
|
532
591
|
port: mcpPortalConfig.server.port,
|
|
533
592
|
tcpPool: tcpPoolConfigFromApi(props.api)
|
|
@@ -544,7 +603,11 @@ function registerPortalService(props) {
|
|
|
544
603
|
props.runtimeState.markPortalUnavailable(reason);
|
|
545
604
|
props.api.logger?.error?.(`[mcp-portal] subprocess supervisor fatal: ${reason}`);
|
|
546
605
|
},
|
|
547
|
-
port: mcpPortalConfig.server.port
|
|
606
|
+
port: mcpPortalConfig.server.port,
|
|
607
|
+
portalEnv: createPortalSubprocessConfigEnv({
|
|
608
|
+
mcpConfig,
|
|
609
|
+
mcpPortalConfig
|
|
610
|
+
})
|
|
548
611
|
});
|
|
549
612
|
await supervisor.start();
|
|
550
613
|
props.runtimeState.markPortalAvailable();
|
|
@@ -611,6 +674,6 @@ function redactPortalSecrets(text, secretValues = []) {
|
|
|
611
674
|
//#region src/index.ts
|
|
612
675
|
const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-mcp-portal-plugin";
|
|
613
676
|
//#endregion
|
|
614
|
-
export { OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME, createBeforePromptBuildHandler, createBeforeToolCallHandler, createHmacKeyRegistry, createPortalPluginRuntimeState, createPortalPromptContext, createPortalSubprocessSupervisor, pluginEntry as default, defaultPortalBinPath, materializedPortalToolNames, parsePortalConfig, portalPluginConfigSchema, portalServerNameForAgent, profileAllowsPortalCall, profileRequiresPortalApproval, redactPortalSecrets, registerMcpPortalPlugin, validatePortalPluginApi, validatePortalPortAgainstTcpPool };
|
|
677
|
+
export { OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME, createBeforePromptBuildHandler, createBeforeToolCallHandler, createHmacKeyRegistry, createPortalPluginRuntimeState, createPortalPromptContext, createPortalSubprocessConfigEnv, createPortalSubprocessSupervisor, pluginEntry as default, defaultPortalBinPath, materializedPortalToolNames, parsePortalConfig, portalPluginConfigSchema, portalServerNameForAgent, profileAllowsPortalCall, profileRequiresPortalApproval, redactPortalSecrets, registerMcpPortalPlugin, validatePortalPluginApi, validatePortalPortAgainstTcpPool };
|
|
615
678
|
|
|
616
679
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["isObjectRecord","errorMessage"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/hmac-key-registry.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/portal-subprocess-supervisor.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\tmcpPortalCallRequiresApproval,\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\nfunction encodePortalServerNameSegment(value: string): string {\n\tconst encodedCharacters: string[] = [];\n\tfor (let index = 0; index < value.length; index += 1) {\n\t\tconst character = value.charAt(index);\n\t\tif (/^[A-Za-z0-9]$/u.test(character)) {\n\t\t\tencodedCharacters.push(character);\n\t\t} else {\n\t\t\tencodedCharacters.push(`_${character.charCodeAt(0).toString(16).padStart(2, '0')}_`);\n\t\t}\n\t}\n\treturn encodedCharacters.join('');\n}\n\nexport function portalServerNameForAgent(agentId: string): string {\n\treturn `mcp_portal_${encodePortalServerNameSegment(agentId)}`;\n}\n\nexport function materializedPortalToolNames(serverName: string): readonly string[] {\n\treturn [\n\t\t`${serverName}__mcp_portal_list`,\n\t\t`${serverName}__mcp_portal_search`,\n\t\t`${serverName}__mcp_portal_describe`,\n\t\t`${serverName}__mcp_portal_call`,\n\t];\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.length > 0 && !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 profileRequiresPortalApproval(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): boolean {\n\treturn mcpPortalCallRequiresApproval(profile, call);\n}\n","import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\nimport { hashCallArguments, signApprovalToken } from '@agent-vm/mcp-portal';\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\tportalServerNameForAgent,\n\tprofileAllowsPortalCall,\n\tprofileRequiresPortalApproval,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nconst approvalTokenTtlMs = 60_000;\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 portalAgentIdFromToolName(toolName: string, agentIds: readonly string[]): string | null {\n\treturn (\n\t\tagentIds.find((agentId) =>\n\t\t\ttoolName.startsWith(`${portalServerNameForAgent(agentId)}__mcp_portal_`),\n\t\t) ?? null\n\t);\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 errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\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\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = portalAgentIdFromToolName(event.toolName, Object.keys(portalConfig.agents));\n\t\tif (agentId === null) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalUnavailableReason = props.runtimeState.getPortalUnavailableReason();\n\t\tif (portalUnavailableReason !== null) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: portal subprocess unavailable (${portalUnavailableReason}).`,\n\t\t\t};\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\tif (context.agentId !== agentId) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: tool ${event.toolName} is not assigned to agent ${context.agentId}.`,\n\t\t\t};\n\t\t}\n\t\tif (!event.toolName.endsWith('__mcp_portal_call')) {\n\t\t\treturn undefined;\n\t\t}\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 = calls.filter((call) => profileRequiresPortalApproval(profile, call));\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst token = signApprovalToken({\n\t\t\tagentId,\n\t\t\tcalls: approvalCalls.map((call) => ({\n\t\t\t\targumentsHash: hashCallArguments(call.arguments),\n\t\t\t\tnamespace: call.namespace,\n\t\t\t\ttoolName: call.toolName,\n\t\t\t})),\n\t\t\texpiresAtMs: Date.now() + approvalTokenTtlMs,\n\t\t\tkey: props.runtimeState.getKeyRegistry().getKey(agentId),\n\t\t});\n\t\ttry {\n\t\t\tevent.params.portalApprovalToken = token;\n\t\t} catch (error) {\n\t\t\tprops.logger?.warn?.(\n\t\t\t\t`[mcp-portal] could not attach server-side approval token: ${errorMessage(error)}`,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: 'mcp-portal: could not attach server-side approval token.',\n\t\t\t};\n\t\t}\n\t\tif (event.params.portalApprovalToken !== token) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: 'mcp-portal: could not attach server-side approval token.',\n\t\t\t};\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 { randomBytes } from 'node:crypto';\n\nimport { portalHmacKeyEnvName } from '@agent-vm/mcp-portal';\n\nconst hmacKeyBytes = 32;\n\nexport interface CreateHmacKeyRegistryProps {\n\treadonly agentIds: readonly string[];\n}\n\nexport interface HmacKeyRegistry {\n\treadonly agentIds: readonly string[];\n\treadonly getKey: (agentId: string) => Buffer;\n\treadonly serializeForEnv: () => Readonly<Record<string, string>>;\n}\n\nexport function createHmacKeyRegistry(props: CreateHmacKeyRegistryProps): HmacKeyRegistry {\n\tconst keysByAgent = new Map<string, Buffer>();\n\tfor (const agentId of props.agentIds) {\n\t\tkeysByAgent.set(agentId, randomBytes(hmacKeyBytes));\n\t}\n\n\treturn {\n\t\tagentIds: [...props.agentIds],\n\t\tgetKey: (agentId) => {\n\t\t\tconst key = keysByAgent.get(agentId);\n\t\t\tif (key === undefined) {\n\t\t\t\tthrow new Error(`HMAC key registry: unknown agent \"${agentId}\".`);\n\t\t\t}\n\t\t\treturn key;\n\t\t},\n\t\tserializeForEnv: () =>\n\t\t\tObject.fromEntries(\n\t\t\t\t[...keysByAgent.entries()].map(([agentId, key]) => [\n\t\t\t\t\tportalHmacKeyEnvName(agentId),\n\t\t\t\t\tkey.toString('hex'),\n\t\t\t\t]),\n\t\t\t),\n\t};\n}\n","import { z } from 'zod';\n\nexport const defaultPortalBinPath = '/opt/agent-vm/portal/bin/agent-vm-mcp-portal-server';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tbinPath: z.string().min(1).default(defaultPortalBinPath),\n\t\tconfigDir: z.string().min(1).optional(),\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 { join } from 'node:path';\n\nimport { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport type { HmacKeyRegistry } from './hmac-key-registry.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly configDir: string;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly getKeyRegistry: () => HmacKeyRegistry;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n\treadonly setKeyRegistry: (registry: HmacKeyRegistry) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet keyRegistry: HmacKeyRegistry | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\tconst portalConfigPath = join(props.configDir, 'mcp-portal.config.jsonc');\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = loadPortalConfigFile(portalConfigPath).catch((error: unknown) => {\n\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\tportalConfigPromise = null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn nextPromise;\n\t}\n\n\treturn {\n\t\tconfigDir: props.configDir,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tgetKeyRegistry: () => {\n\t\t\tif (keyRegistry === null) {\n\t\t\t\tthrow new Error('MCP Portal HMAC key registry is not initialized.');\n\t\t\t}\n\t\t\treturn keyRegistry;\n\t\t},\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\tsetKeyRegistry: (registry) => {\n\t\t\tkeyRegistry = registry;\n\t\t},\n\t};\n}\n","import { spawn } from 'node:child_process';\nimport type { ChildProcess, SpawnOptions } from 'node:child_process';\n\nexport interface PortalSubprocessLogger {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n}\n\nexport type PortalSubprocessSpawnFunction = (\n\tcommand: string,\n\targs: readonly string[],\n\toptions: SpawnOptions,\n) => ChildProcess;\n\nexport interface CreatePortalSubprocessSupervisorProps {\n\treadonly backoffSteps?: readonly number[];\n\treadonly binPath: string;\n\treadonly configDir: string;\n\treadonly fetchFn?: typeof fetch;\n\treadonly healthPollIntervalMs?: number;\n\treadonly healthTimeoutMs?: number;\n\treadonly host: string;\n\treadonly hmacEnv: Readonly<Record<string, string>>;\n\treadonly logger: PortalSubprocessLogger;\n\treadonly maxRestarts?: number;\n\treadonly onFatal?: (reason: string) => void;\n\treadonly port: number;\n\treadonly spawnFn?: PortalSubprocessSpawnFunction;\n\treadonly stopGraceMs?: number;\n}\n\nexport interface PortalSubprocessSupervisor {\n\treadonly isAlive: () => boolean;\n\treadonly start: () => Promise<void>;\n\treadonly stop: () => Promise<void>;\n}\n\nconst defaultBackoffSteps = [200, 400, 800, 1_600, 3_200, 5_000] as const;\nconst inheritedPortalEnvNames = ['HOME', 'PATH', 'TEMP', 'TMP', 'TMPDIR'] as const;\n\nfunction createPortalSubprocessEnv(\n\thmacEnv: Readonly<Record<string, string>>,\n): Readonly<Record<string, string>> {\n\tconst env: Record<string, string> = {};\n\tfor (const name of inheritedPortalEnvNames) {\n\t\tconst value = process.env[name];\n\t\tif (value !== undefined) {\n\t\t\tenv[name] = value;\n\t\t}\n\t}\n\treturn { ...env, ...hmacEnv };\n}\n\nfunction logSubprocessOutput(props: {\n\treadonly chunk: Buffer | string;\n\treadonly logger: PortalSubprocessLogger;\n\treadonly streamName: 'stderr' | 'stdout';\n}): void {\n\tconst text = String(props.chunk);\n\tfor (const line of text.split(/\\r?\\n/u)) {\n\t\tif (line.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = `[mcp-portal ${props.streamName}] ${line}`;\n\t\tif (props.streamName === 'stderr') {\n\t\t\tprops.logger.warn(message);\n\t\t} else {\n\t\t\tprops.logger.info(message);\n\t\t}\n\t}\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tsetTimeout(resolve, ms);\n\t});\n}\n\nasync function waitForExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n\treturn new Promise<boolean>((resolve) => {\n\t\tlet settled = false;\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tchild.off('exit', handleExit);\n\t\t\tresolve(false);\n\t\t}, timeoutMs);\n\t\tconst handleExit = (): void => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(true);\n\t\t};\n\t\tchild.once('exit', handleExit);\n\t});\n}\n\ninterface WaitForHealthProps {\n\treadonly fetchFn: typeof fetch;\n\treadonly host: string;\n\treadonly intervalMs: number;\n\treadonly port: number;\n\treadonly timeoutMs: number;\n}\n\nasync function waitForHealthAttempt(props: {\n\treadonly fetchFn: typeof fetch;\n\treadonly host: string;\n\treadonly intervalMs: number;\n\treadonly lastError: unknown;\n\treadonly port: number;\n\treadonly startedAt: number;\n\treadonly timeoutMs: number;\n}): Promise<void> {\n\tif (Date.now() - props.startedAt > props.timeoutMs) {\n\t\tconst message =\n\t\t\tprops.lastError instanceof Error ? props.lastError.message : String(props.lastError);\n\t\tthrow new Error(`Timed out waiting for MCP Portal health: ${message}`);\n\t}\n\ttry {\n\t\tconst response = await props.fetchFn(`http://${props.host}:${String(props.port)}/health`);\n\t\tif (response.ok) {\n\t\t\treturn;\n\t\t}\n\t\tawait delay(props.intervalMs);\n\t\treturn waitForHealthAttempt({\n\t\t\t...props,\n\t\t\tlastError: new Error(`health returned ${String(response.status)}`),\n\t\t});\n\t} catch (error) {\n\t\tawait delay(props.intervalMs);\n\t\treturn waitForHealthAttempt({ ...props, lastError: error });\n\t}\n}\n\nasync function waitForHealth(props: WaitForHealthProps): Promise<void> {\n\tconst startedAt = Date.now();\n\treturn waitForHealthAttempt({ ...props, lastError: undefined, startedAt });\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\ninterface SpawnedPortalChild {\n\treadonly child: ChildProcess;\n\treadonly enableAutoRestart: () => void;\n\treadonly earlyFailure: Promise<never>;\n}\n\nexport function createPortalSubprocessSupervisor(\n\tprops: CreatePortalSubprocessSupervisorProps,\n): PortalSubprocessSupervisor {\n\tconst spawnFn: PortalSubprocessSpawnFunction =\n\t\tprops.spawnFn ?? ((command, args, options) => spawn(command, [...args], options));\n\tconst fetchFn = props.fetchFn ?? fetch;\n\tconst healthPollIntervalMs = props.healthPollIntervalMs ?? 200;\n\tconst healthTimeoutMs = props.healthTimeoutMs ?? 10_000;\n\tconst stopGraceMs = props.stopGraceMs ?? 5_000;\n\tconst maxRestarts = props.maxRestarts ?? 5;\n\tconst backoffSteps = props.backoffSteps ?? defaultBackoffSteps;\n\tlet child: ChildProcess | null = null;\n\tlet stopping = false;\n\tlet restartCount = 0;\n\n\tconst spawnChild = (): SpawnedPortalChild => {\n\t\tconst nextChild = spawnFn(props.binPath, ['--config-dir', props.configDir], {\n\t\t\tenv: createPortalSubprocessEnv(props.hmacEnv),\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t});\n\t\tlet autoRestartEnabled = false;\n\t\tlet failureHandled = false;\n\t\tlet rejectEarlyFailure: ((error: Error) => void) | undefined;\n\t\tconst earlyFailure = new Promise<never>((_resolve, reject) => {\n\t\t\trejectEarlyFailure = reject;\n\t\t});\n\t\tconst rejectBeforeHealth = (error: Error): void => {\n\t\t\tif (rejectEarlyFailure === undefined) {\n\t\t\t\tthrow new Error('MCP Portal early-failure rejector was not initialized.');\n\t\t\t}\n\t\t\trejectEarlyFailure(error);\n\t\t};\n\t\tchild = nextChild;\n\t\tnextChild.stdout?.on('data', (chunk: Buffer | string) => {\n\t\t\tlogSubprocessOutput({ chunk, logger: props.logger, streamName: 'stdout' });\n\t\t});\n\t\tnextChild.stdout?.on('error', (error: Error) => {\n\t\t\tprops.logger.warn(`[mcp-portal stdout] stream error: ${error.message}`);\n\t\t});\n\t\tnextChild.stderr?.on('data', (chunk: Buffer | string) => {\n\t\t\tlogSubprocessOutput({ chunk, logger: props.logger, streamName: 'stderr' });\n\t\t});\n\t\tnextChild.stderr?.on('error', (error: Error) => {\n\t\t\tprops.logger.warn(`[mcp-portal stderr] stream error: ${error.message}`);\n\t\t});\n\t\tnextChild.on('error', (error: Error) => {\n\t\t\tprops.logger.error(`[mcp-portal] subprocess spawn failed: ${error.message}`);\n\t\t\tif (failureHandled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailureHandled = true;\n\t\t\tif (child === nextChild) {\n\t\t\t\tchild = null;\n\t\t\t}\n\t\t\tif (stopping) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (autoRestartEnabled) {\n\t\t\t\tvoid scheduleRestart();\n\t\t\t} else {\n\t\t\t\trejectBeforeHealth(error);\n\t\t\t}\n\t\t});\n\t\tnextChild.on('exit', (code: number | null, signal: NodeJS.Signals | null) => {\n\t\t\tif (failureHandled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailureHandled = true;\n\t\t\tif (child === nextChild) {\n\t\t\t\tchild = null;\n\t\t\t}\n\t\t\tif (stopping) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (autoRestartEnabled) {\n\t\t\t\tvoid scheduleRestart();\n\t\t\t} else {\n\t\t\t\trejectBeforeHealth(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t`MCP Portal subprocess exited before health check completed (code=${String(code)} signal=${String(signal)}).`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tchild: nextChild,\n\t\t\tearlyFailure,\n\t\t\tenableAutoRestart: () => {\n\t\t\t\tautoRestartEnabled = true;\n\t\t\t},\n\t\t};\n\t};\n\n\tconst spawnChildAndWaitForHealth = async (): Promise<void> => {\n\t\tconst spawnedChild = spawnChild();\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\twaitForHealth({\n\t\t\t\t\tfetchFn,\n\t\t\t\t\thost: props.host,\n\t\t\t\t\tintervalMs: healthPollIntervalMs,\n\t\t\t\t\tport: props.port,\n\t\t\t\t\ttimeoutMs: healthTimeoutMs,\n\t\t\t\t}),\n\t\t\t\tspawnedChild.earlyFailure,\n\t\t\t]);\n\t\t} catch (error) {\n\t\t\tif (child === spawnedChild.child) {\n\t\t\t\tchild = null;\n\t\t\t\tif (!spawnedChild.child.killed) {\n\t\t\t\t\tspawnedChild.child.kill('SIGTERM');\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tspawnedChild.enableAutoRestart();\n\t\trestartCount = 0;\n\t\tprops.logger.info('[mcp-portal] subprocess is healthy.');\n\t};\n\n\tconst scheduleRestart = async (): Promise<void> => {\n\t\trestartCount += 1;\n\t\tif (restartCount > maxRestarts) {\n\t\t\tprops.logger.error('[mcp-portal] subprocess restart limit exhausted.');\n\t\t\tprops.onFatal?.('backoff-exhausted');\n\t\t\treturn;\n\t\t}\n\t\tconst backoffIndex = Math.min(restartCount - 1, backoffSteps.length - 1);\n\t\tconst backoffMs = backoffSteps[backoffIndex] ?? backoffSteps[backoffSteps.length - 1] ?? 5_000;\n\t\tprops.logger.warn(`[mcp-portal] subprocess exited; restarting in ${String(backoffMs)}ms.`);\n\t\tawait delay(backoffMs);\n\t\tif (stopping) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tawait spawnChildAndWaitForHealth();\n\t\t} catch (error) {\n\t\t\tprops.logger.error(`[mcp-portal] subprocess restart failed: ${errorMessage(error)}`);\n\t\t\tif (!stopping) {\n\t\t\t\tawait scheduleRestart();\n\t\t\t}\n\t\t}\n\t};\n\n\treturn {\n\t\tisAlive: () => child !== null && !child.killed,\n\t\tstart: async () => {\n\t\t\tstopping = false;\n\t\t\tawait spawnChildAndWaitForHealth();\n\t\t},\n\t\tstop: async () => {\n\t\t\tstopping = true;\n\t\t\tconst activeChild = child;\n\t\t\tchild = null;\n\t\t\tif (activeChild === null || activeChild.killed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactiveChild.kill('SIGTERM');\n\t\t\tconst exited = await waitForExit(activeChild, stopGraceMs);\n\t\t\tif (!exited && !activeChild.killed) {\n\t\t\t\tactiveChild.kill('SIGKILL');\n\t\t\t}\n\t\t},\n\t};\n}\n","import { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { createHmacKeyRegistry } from './hmac-key-registry.js';\nimport type { OpenClawPortalPluginApi } from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport {\n\tcreatePortalPluginRuntimeState,\n\ttype PortalPluginRuntimeState,\n} from './portal-plugin-runtime-state.js';\nimport {\n\tcreatePortalSubprocessSupervisor,\n\ttype PortalSubprocessSupervisor,\n} from './portal-subprocess-supervisor.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\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 messageFromUnknown(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tconst pluginConfig = parsePortalConfig(api.pluginConfig ?? {});\n\tif (pluginConfig.configDir !== undefined) {\n\t\treturn pluginConfig.configDir;\n\t}\n\tconst topLevelMcpConfigDir = getObjectProperty(getObjectProperty(api.config, 'mcp'), 'configDir');\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(getObjectProperty(firstZone, 'mcp'), 'configDir');\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error('MCP Portal plugin requires configDir in plugin config or zone mcp config.');\n}\n\nfunction tcpPoolConfigFromApi(api: OpenClawPortalPluginApi): TcpPoolConfig | null {\n\tconst tcpPool = getObjectProperty(api.config, 'tcpPool');\n\tconst basePort = getObjectProperty(tcpPool, 'basePort');\n\tconst size = getObjectProperty(tcpPool, 'size');\n\treturn typeof basePort === 'number' && typeof size === 'number' ? { basePort, size } : null;\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.registerService)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerService API.');\n\t}\n\tif (!hasFunction(api.on) && !hasFunction(api.registerPromptHook)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw prompt hook registration 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: 'Stops the MCP Portal subprocess supervised by the agent-vm plugin.',\n\t\tid: 'mcp-portal-subprocess',\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 registerPortalService(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly configDir: string;\n\treadonly runtimeState: PortalPluginRuntimeState;\n}): { readonly getSupervisor: () => PortalSubprocessSupervisor | null } {\n\tconst portalConfig = parsePortalConfig(props.api.pluginConfig ?? {});\n\tlet supervisor: PortalSubprocessSupervisor | null = null;\n\n\tprops.api.registerService?.({\n\t\tid: 'mcp-portal-subprocess',\n\t\tstart: async () => {\n\t\t\tconst mcpPortalConfig = await props.runtimeState.loadPortalConfig();\n\t\t\tvalidatePortalPortAgainstTcpPool({\n\t\t\t\tport: mcpPortalConfig.server.port,\n\t\t\t\ttcpPool: tcpPoolConfigFromApi(props.api),\n\t\t\t});\n\t\t\tconst keyRegistry = createHmacKeyRegistry({\n\t\t\t\tagentIds: Object.keys(mcpPortalConfig.agents).toSorted(),\n\t\t\t});\n\t\t\tprops.runtimeState.setKeyRegistry(keyRegistry);\n\t\t\tsupervisor = createPortalSubprocessSupervisor({\n\t\t\t\tbinPath: portalConfig.binPath,\n\t\t\t\tconfigDir: props.configDir,\n\t\t\t\thost: mcpPortalConfig.server.host,\n\t\t\t\thmacEnv: keyRegistry.serializeForEnv(),\n\t\t\t\tlogger: createLoggerAdapter(props.api),\n\t\t\t\tonFatal: (reason) => {\n\t\t\t\t\tprops.runtimeState.markPortalUnavailable(reason);\n\t\t\t\t\tprops.api.logger?.error?.(`[mcp-portal] subprocess supervisor fatal: ${reason}`);\n\t\t\t\t},\n\t\t\t\tport: mcpPortalConfig.server.port,\n\t\t\t});\n\t\t\tawait supervisor.start();\n\t\t\tprops.runtimeState.markPortalAvailable();\n\t\t},\n\t\tstop: async () => {\n\t\t\tawait supervisor?.stop();\n\t\t},\n\t});\n\n\treturn { getSupervisor: () => supervisor };\n}\n\nexport function registerMcpPortalPlugin(api: OpenClawPortalPluginApi): void {\n\tif (api.registrationMode !== undefined && api.registrationMode !== 'full') {\n\t\treturn;\n\t}\n\tvalidatePortalPluginApi(api);\n\tconst configDir = resolveConfigDir(api);\n\tconst runtimeState = createPortalPluginRuntimeState({ configDir });\n\tconst registeredService = registerPortalService({ api, configDir, runtimeState });\n\n\tapi.on?.(\n\t\t'before_tool_call',\n\t\tcreateBeforeToolCallHandler({ logger: createLoggerAdapter(api), runtimeState }),\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, () => registeredService.getSupervisor()?.stop());\n\tvoid runtimeState.loadPortalConfig().catch((error: unknown) => {\n\t\tapi.logger?.error?.(\n\t\t\t`[mcp-portal] failed to initialize portal config: ${messageFromUnknown(error)}`,\n\t\t);\n\t});\n}\n\nconst pluginEntry = {\n\tdescription: 'Supervises the MCP Portal subprocess 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 message: string;\n\treadonly namespace: string;\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? [\n\t\t\t\t\t`Discovery diagnostics: ${props.diagnostics\n\t\t\t\t\t\t.map((entry) => `${entry.namespace}: ${entry.message}`)\n\t\t\t\t\t\t.join('; ')}`,\n\t\t\t\t]\n\t\t\t: [];\n\n\treturn [\n\t\t'MCP Portal is available as an MCP server.',\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';\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 './hmac-key-registry.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-subprocess-supervisor.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","errorMessage"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/hmac-key-registry.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/portal-subprocess-supervisor.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\tmcpPortalCallRequiresApproval,\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\nfunction encodePortalServerNameSegment(value: string): string {\n\tconst encodedCharacters: string[] = [];\n\tfor (let index = 0; index < value.length; index += 1) {\n\t\tconst character = value.charAt(index);\n\t\tif (/^[A-Za-z0-9]$/u.test(character)) {\n\t\t\tencodedCharacters.push(character);\n\t\t} else {\n\t\t\tencodedCharacters.push(`_${character.charCodeAt(0).toString(16).padStart(2, '0')}_`);\n\t\t}\n\t}\n\treturn encodedCharacters.join('');\n}\n\nexport function portalServerNameForAgent(agentId: string): string {\n\treturn `mcp_portal_${encodePortalServerNameSegment(agentId)}`;\n}\n\nexport function materializedPortalToolNames(serverName: string): readonly string[] {\n\treturn [\n\t\t`${serverName}__mcp_portal_list`,\n\t\t`${serverName}__mcp_portal_search`,\n\t\t`${serverName}__mcp_portal_describe`,\n\t\t`${serverName}__mcp_portal_call`,\n\t];\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.length > 0 && !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 profileRequiresPortalApproval(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: { readonly namespace: string; readonly toolName: string },\n): boolean {\n\treturn mcpPortalCallRequiresApproval(profile, call);\n}\n","import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\nimport { hashCallArguments, signApprovalToken } from '@agent-vm/mcp-portal';\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\tportalServerNameForAgent,\n\tprofileAllowsPortalCall,\n\tprofileRequiresPortalApproval,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nconst approvalTokenTtlMs = 60_000;\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 portalAgentIdFromToolName(toolName: string, agentIds: readonly string[]): string | null {\n\treturn (\n\t\tagentIds.find((agentId) =>\n\t\t\ttoolName.startsWith(`${portalServerNameForAgent(agentId)}__mcp_portal_`),\n\t\t) ?? null\n\t);\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 errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\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\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = portalAgentIdFromToolName(event.toolName, Object.keys(portalConfig.agents));\n\t\tif (agentId === null) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalUnavailableReason = props.runtimeState.getPortalUnavailableReason();\n\t\tif (portalUnavailableReason !== null) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: portal subprocess unavailable (${portalUnavailableReason}).`,\n\t\t\t};\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\tif (context.agentId !== agentId) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: tool ${event.toolName} is not assigned to agent ${context.agentId}.`,\n\t\t\t};\n\t\t}\n\t\tif (!event.toolName.endsWith('__mcp_portal_call')) {\n\t\t\treturn undefined;\n\t\t}\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 = calls.filter((call) => profileRequiresPortalApproval(profile, call));\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst token = signApprovalToken({\n\t\t\tagentId,\n\t\t\tcalls: approvalCalls.map((call) => ({\n\t\t\t\targumentsHash: hashCallArguments(call.arguments),\n\t\t\t\tnamespace: call.namespace,\n\t\t\t\ttoolName: call.toolName,\n\t\t\t})),\n\t\t\texpiresAtMs: Date.now() + approvalTokenTtlMs,\n\t\t\tkey: props.runtimeState.getKeyRegistry().getKey(agentId),\n\t\t});\n\t\ttry {\n\t\t\tevent.params.portalApprovalToken = token;\n\t\t} catch (error) {\n\t\t\tprops.logger?.warn?.(\n\t\t\t\t`[mcp-portal] could not attach server-side approval token: ${errorMessage(error)}`,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: 'mcp-portal: could not attach server-side approval token.',\n\t\t\t};\n\t\t}\n\t\tif (event.params.portalApprovalToken !== token) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: 'mcp-portal: could not attach server-side approval token.',\n\t\t\t};\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 { randomBytes } from 'node:crypto';\n\nimport { portalHmacKeyEnvName } from '@agent-vm/mcp-portal';\n\nconst hmacKeyBytes = 32;\n\nexport interface CreateHmacKeyRegistryProps {\n\treadonly agentIds: readonly string[];\n}\n\nexport interface HmacKeyRegistry {\n\treadonly agentIds: readonly string[];\n\treadonly getKey: (agentId: string) => Buffer;\n\treadonly serializeForEnv: () => Readonly<Record<string, string>>;\n}\n\nexport function createHmacKeyRegistry(props: CreateHmacKeyRegistryProps): HmacKeyRegistry {\n\tconst keysByAgent = new Map<string, Buffer>();\n\tfor (const agentId of props.agentIds) {\n\t\tkeysByAgent.set(agentId, randomBytes(hmacKeyBytes));\n\t}\n\n\treturn {\n\t\tagentIds: [...props.agentIds],\n\t\tgetKey: (agentId) => {\n\t\t\tconst key = keysByAgent.get(agentId);\n\t\t\tif (key === undefined) {\n\t\t\t\tthrow new Error(`HMAC key registry: unknown agent \"${agentId}\".`);\n\t\t\t}\n\t\t\treturn key;\n\t\t},\n\t\tserializeForEnv: () =>\n\t\t\tObject.fromEntries(\n\t\t\t\t[...keysByAgent.entries()].map(([agentId, key]) => [\n\t\t\t\t\tportalHmacKeyEnvName(agentId),\n\t\t\t\t\tkey.toString('hex'),\n\t\t\t\t]),\n\t\t\t),\n\t};\n}\n","import { z } from 'zod';\n\nexport const defaultPortalBinPath = '/opt/agent-vm/portal/bin/agent-vm-mcp-portal-server';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tbinPath: z.string().min(1).default(defaultPortalBinPath),\n\t\tconfigDir: z.string().min(1).optional(),\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 { join } from 'node:path';\n\nimport { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport type { HmacKeyRegistry } from './hmac-key-registry.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly configDir: string;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly getKeyRegistry: () => HmacKeyRegistry;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n\treadonly setKeyRegistry: (registry: HmacKeyRegistry) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet keyRegistry: HmacKeyRegistry | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\tconst portalConfigPath = join(props.configDir, 'mcp-portal.config.jsonc');\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = loadPortalConfigFile(portalConfigPath).catch((error: unknown) => {\n\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\tportalConfigPromise = null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn nextPromise;\n\t}\n\n\treturn {\n\t\tconfigDir: props.configDir,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tgetKeyRegistry: () => {\n\t\t\tif (keyRegistry === null) {\n\t\t\t\tthrow new Error('MCP Portal HMAC key registry is not initialized.');\n\t\t\t}\n\t\t\treturn keyRegistry;\n\t\t},\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\tsetKeyRegistry: (registry) => {\n\t\t\tkeyRegistry = registry;\n\t\t},\n\t};\n}\n","import { spawn } from 'node:child_process';\nimport type { ChildProcess, SpawnOptions } from 'node:child_process';\n\nexport interface PortalSubprocessLogger {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n}\n\nexport type PortalSubprocessSpawnFunction = (\n\tcommand: string,\n\targs: readonly string[],\n\toptions: SpawnOptions,\n) => ChildProcess;\n\nexport interface CreatePortalSubprocessSupervisorProps {\n\treadonly backoffSteps?: readonly number[];\n\treadonly binPath: string;\n\treadonly configDir: string;\n\treadonly fetchFn?: typeof fetch;\n\treadonly healthPollIntervalMs?: number;\n\treadonly healthTimeoutMs?: number;\n\treadonly host: string;\n\treadonly hmacEnv: Readonly<Record<string, string>>;\n\treadonly logger: PortalSubprocessLogger;\n\treadonly maxRestarts?: number;\n\treadonly onFatal?: (reason: string) => void;\n\treadonly port: number;\n\treadonly portalEnv?: Readonly<Record<string, string>>;\n\treadonly spawnFn?: PortalSubprocessSpawnFunction;\n\treadonly stopGraceMs?: number;\n}\n\nexport interface PortalSubprocessSupervisor {\n\treadonly isAlive: () => boolean;\n\treadonly start: () => Promise<void>;\n\treadonly stop: () => Promise<void>;\n}\n\nconst defaultBackoffSteps = [200, 400, 800, 1_600, 3_200, 5_000] as const;\nconst inheritedPortalEnvNames = ['HOME', 'PATH', 'TEMP', 'TMP', 'TMPDIR'] as const;\n\nfunction createPortalSubprocessEnv(\n\thmacEnv: Readonly<Record<string, string>>,\n\tportalEnv: Readonly<Record<string, string>> = {},\n): Readonly<Record<string, string>> {\n\tconst env: Record<string, string> = {};\n\tfor (const name of inheritedPortalEnvNames) {\n\t\tconst value = process.env[name];\n\t\tif (value !== undefined) {\n\t\t\tenv[name] = value;\n\t\t}\n\t}\n\treturn { ...env, ...portalEnv, ...hmacEnv };\n}\n\nfunction logSubprocessOutput(props: {\n\treadonly chunk: Buffer | string;\n\treadonly logger: PortalSubprocessLogger;\n\treadonly streamName: 'stderr' | 'stdout';\n}): void {\n\tconst text = String(props.chunk);\n\tfor (const line of text.split(/\\r?\\n/u)) {\n\t\tif (line.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = `[mcp-portal ${props.streamName}] ${line}`;\n\t\tif (props.streamName === 'stderr') {\n\t\t\tprops.logger.warn(message);\n\t\t} else {\n\t\t\tprops.logger.info(message);\n\t\t}\n\t}\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tsetTimeout(resolve, ms);\n\t});\n}\n\nasync function waitForExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n\treturn new Promise<boolean>((resolve) => {\n\t\tlet settled = false;\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tchild.off('exit', handleExit);\n\t\t\tresolve(false);\n\t\t}, timeoutMs);\n\t\tconst handleExit = (): void => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(true);\n\t\t};\n\t\tchild.once('exit', handleExit);\n\t});\n}\n\ninterface WaitForHealthProps {\n\treadonly fetchFn: typeof fetch;\n\treadonly host: string;\n\treadonly intervalMs: number;\n\treadonly port: number;\n\treadonly timeoutMs: number;\n}\n\nasync function waitForHealthAttempt(props: {\n\treadonly fetchFn: typeof fetch;\n\treadonly host: string;\n\treadonly intervalMs: number;\n\treadonly lastError: unknown;\n\treadonly port: number;\n\treadonly startedAt: number;\n\treadonly timeoutMs: number;\n}): Promise<void> {\n\tif (Date.now() - props.startedAt > props.timeoutMs) {\n\t\tconst message =\n\t\t\tprops.lastError instanceof Error ? props.lastError.message : String(props.lastError);\n\t\tthrow new Error(`Timed out waiting for MCP Portal health: ${message}`);\n\t}\n\ttry {\n\t\tconst response = await props.fetchFn(`http://${props.host}:${String(props.port)}/health`);\n\t\tif (response.ok) {\n\t\t\treturn;\n\t\t}\n\t\tawait delay(props.intervalMs);\n\t\treturn waitForHealthAttempt({\n\t\t\t...props,\n\t\t\tlastError: new Error(`health returned ${String(response.status)}`),\n\t\t});\n\t} catch (error) {\n\t\tawait delay(props.intervalMs);\n\t\treturn waitForHealthAttempt({ ...props, lastError: error });\n\t}\n}\n\nasync function waitForHealth(props: WaitForHealthProps): Promise<void> {\n\tconst startedAt = Date.now();\n\treturn waitForHealthAttempt({ ...props, lastError: undefined, startedAt });\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\ninterface SpawnedPortalChild {\n\treadonly child: ChildProcess;\n\treadonly enableAutoRestart: () => void;\n\treadonly earlyFailure: Promise<never>;\n}\n\nexport function createPortalSubprocessSupervisor(\n\tprops: CreatePortalSubprocessSupervisorProps,\n): PortalSubprocessSupervisor {\n\tconst spawnFn: PortalSubprocessSpawnFunction =\n\t\tprops.spawnFn ?? ((command, args, options) => spawn(command, [...args], options));\n\tconst fetchFn = props.fetchFn ?? fetch;\n\tconst healthPollIntervalMs = props.healthPollIntervalMs ?? 200;\n\tconst healthTimeoutMs = props.healthTimeoutMs ?? 10_000;\n\tconst stopGraceMs = props.stopGraceMs ?? 5_000;\n\tconst maxRestarts = props.maxRestarts ?? 5;\n\tconst backoffSteps = props.backoffSteps ?? defaultBackoffSteps;\n\tlet child: ChildProcess | null = null;\n\tlet stopping = false;\n\tlet restartCount = 0;\n\n\tconst spawnChild = (): SpawnedPortalChild => {\n\t\tconst nextChild = spawnFn(props.binPath, ['--config-dir', props.configDir], {\n\t\t\tenv: createPortalSubprocessEnv(props.hmacEnv, props.portalEnv),\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t});\n\t\tlet autoRestartEnabled = false;\n\t\tlet failureHandled = false;\n\t\tlet rejectEarlyFailure: ((error: Error) => void) | undefined;\n\t\tconst earlyFailure = new Promise<never>((_resolve, reject) => {\n\t\t\trejectEarlyFailure = reject;\n\t\t});\n\t\tconst rejectBeforeHealth = (error: Error): void => {\n\t\t\tif (rejectEarlyFailure === undefined) {\n\t\t\t\tthrow new Error('MCP Portal early-failure rejector was not initialized.');\n\t\t\t}\n\t\t\trejectEarlyFailure(error);\n\t\t};\n\t\tchild = nextChild;\n\t\tnextChild.stdout?.on('data', (chunk: Buffer | string) => {\n\t\t\tlogSubprocessOutput({ chunk, logger: props.logger, streamName: 'stdout' });\n\t\t});\n\t\tnextChild.stdout?.on('error', (error: Error) => {\n\t\t\tprops.logger.warn(`[mcp-portal stdout] stream error: ${error.message}`);\n\t\t});\n\t\tnextChild.stderr?.on('data', (chunk: Buffer | string) => {\n\t\t\tlogSubprocessOutput({ chunk, logger: props.logger, streamName: 'stderr' });\n\t\t});\n\t\tnextChild.stderr?.on('error', (error: Error) => {\n\t\t\tprops.logger.warn(`[mcp-portal stderr] stream error: ${error.message}`);\n\t\t});\n\t\tnextChild.on('error', (error: Error) => {\n\t\t\tprops.logger.error(`[mcp-portal] subprocess spawn failed: ${error.message}`);\n\t\t\tif (failureHandled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailureHandled = true;\n\t\t\tif (child === nextChild) {\n\t\t\t\tchild = null;\n\t\t\t}\n\t\t\tif (stopping) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (autoRestartEnabled) {\n\t\t\t\tvoid scheduleRestart();\n\t\t\t} else {\n\t\t\t\trejectBeforeHealth(error);\n\t\t\t}\n\t\t});\n\t\tnextChild.on('exit', (code: number | null, signal: NodeJS.Signals | null) => {\n\t\t\tif (failureHandled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailureHandled = true;\n\t\t\tif (child === nextChild) {\n\t\t\t\tchild = null;\n\t\t\t}\n\t\t\tif (stopping) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (autoRestartEnabled) {\n\t\t\t\tvoid scheduleRestart();\n\t\t\t} else {\n\t\t\t\trejectBeforeHealth(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t`MCP Portal subprocess exited before health check completed (code=${String(code)} signal=${String(signal)}).`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tchild: nextChild,\n\t\t\tearlyFailure,\n\t\t\tenableAutoRestart: () => {\n\t\t\t\tautoRestartEnabled = true;\n\t\t\t},\n\t\t};\n\t};\n\n\tconst spawnChildAndWaitForHealth = async (): Promise<void> => {\n\t\tconst spawnedChild = spawnChild();\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\twaitForHealth({\n\t\t\t\t\tfetchFn,\n\t\t\t\t\thost: props.host,\n\t\t\t\t\tintervalMs: healthPollIntervalMs,\n\t\t\t\t\tport: props.port,\n\t\t\t\t\ttimeoutMs: healthTimeoutMs,\n\t\t\t\t}),\n\t\t\t\tspawnedChild.earlyFailure,\n\t\t\t]);\n\t\t} catch (error) {\n\t\t\tif (child === spawnedChild.child) {\n\t\t\t\tchild = null;\n\t\t\t\tif (!spawnedChild.child.killed) {\n\t\t\t\t\tspawnedChild.child.kill('SIGTERM');\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tspawnedChild.enableAutoRestart();\n\t\trestartCount = 0;\n\t\tprops.logger.info('[mcp-portal] subprocess is healthy.');\n\t};\n\n\tconst scheduleRestart = async (): Promise<void> => {\n\t\trestartCount += 1;\n\t\tif (restartCount > maxRestarts) {\n\t\t\tprops.logger.error('[mcp-portal] subprocess restart limit exhausted.');\n\t\t\tprops.onFatal?.('backoff-exhausted');\n\t\t\treturn;\n\t\t}\n\t\tconst backoffIndex = Math.min(restartCount - 1, backoffSteps.length - 1);\n\t\tconst backoffMs = backoffSteps[backoffIndex] ?? backoffSteps[backoffSteps.length - 1] ?? 5_000;\n\t\tprops.logger.warn(`[mcp-portal] subprocess exited; restarting in ${String(backoffMs)}ms.`);\n\t\tawait delay(backoffMs);\n\t\tif (stopping) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tawait spawnChildAndWaitForHealth();\n\t\t} catch (error) {\n\t\t\tprops.logger.error(`[mcp-portal] subprocess restart failed: ${errorMessage(error)}`);\n\t\t\tif (!stopping) {\n\t\t\t\tawait scheduleRestart();\n\t\t\t}\n\t\t}\n\t};\n\n\treturn {\n\t\tisAlive: () => child !== null && !child.killed,\n\t\tstart: async () => {\n\t\t\tstopping = false;\n\t\t\tawait spawnChildAndWaitForHealth();\n\t\t},\n\t\tstop: async () => {\n\t\t\tstopping = true;\n\t\t\tconst activeChild = child;\n\t\t\tchild = null;\n\t\t\tif (activeChild === null || activeChild.killed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactiveChild.kill('SIGTERM');\n\t\t\tconst exited = await waitForExit(activeChild, stopGraceMs);\n\t\t\tif (!exited && !activeChild.killed) {\n\t\t\t\tactiveChild.kill('SIGKILL');\n\t\t\t}\n\t\t},\n\t};\n}\n","import { join } from 'node:path';\n\nimport {\n\tloadMcpConfig,\n\ttype McpConfig,\n\ttype McpPortalConfig,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\n\nimport { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { createHmacKeyRegistry } from './hmac-key-registry.js';\nimport type { OpenClawPortalPluginApi } from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport {\n\tcreatePortalPluginRuntimeState,\n\ttype PortalPluginRuntimeState,\n} from './portal-plugin-runtime-state.js';\nimport {\n\tcreatePortalSubprocessSupervisor,\n\ttype PortalSubprocessSupervisor,\n} from './portal-subprocess-supervisor.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\nconst pluginId = 'mcp-portal';\nconst onePasswordCliEnvNames = [\n\t'OP_SERVICE_ACCOUNT_TOKEN',\n\t'OP_ACCOUNT',\n\t'OP_CONNECT_HOST',\n\t'OP_CONNECT_TOKEN',\n] as const;\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 messageFromUnknown(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction addEnvironmentSecretName(names: Set<string>, secret: SecretValue): void {\n\tif (secret.source === 'environment') {\n\t\tnames.add(secret.name);\n\t}\n}\n\nfunction secretUsesOnePassword(secret: SecretValue): boolean {\n\treturn secret.source === '1password';\n}\n\nfunction collectMcpConfigEnvironmentSecretNames(config: McpConfig): ReadonlySet<string> {\n\tconst names = new Set<string>();\n\tfor (const provider of Object.values(config.providers)) {\n\t\tconst transport = provider.transport;\n\t\tconst secrets =\n\t\t\ttransport.kind === 'stdio' ? Object.values(transport.env) : Object.values(transport.headers);\n\t\tfor (const secret of secrets) {\n\t\t\taddEnvironmentSecretName(names, secret);\n\t\t}\n\t}\n\treturn names;\n}\n\nfunction collectMcpPortalConfigEnvironmentSecretNames(\n\tconfig: McpPortalConfig,\n): ReadonlySet<string> {\n\tconst names = new Set<string>();\n\taddEnvironmentSecretName(names, config.server.accessHeader.secret);\n\tfor (const agent of Object.values(config.agents)) {\n\t\tif (agent.hmacKey !== undefined) {\n\t\t\taddEnvironmentSecretName(names, agent.hmacKey);\n\t\t}\n\t}\n\treturn names;\n}\n\nfunction mcpConfigUsesOnePassword(config: McpConfig): boolean {\n\treturn Object.values(config.providers).some((provider) => {\n\t\tconst transport = provider.transport;\n\t\tconst secrets =\n\t\t\ttransport.kind === 'stdio' ? Object.values(transport.env) : Object.values(transport.headers);\n\t\treturn secrets.some(secretUsesOnePassword);\n\t});\n}\n\nfunction mcpPortalConfigUsesOnePassword(config: McpPortalConfig): boolean {\n\treturn (\n\t\tsecretUsesOnePassword(config.server.accessHeader.secret) ||\n\t\tObject.values(config.agents).some(\n\t\t\t(agent) => agent.hmacKey !== undefined && secretUsesOnePassword(agent.hmacKey),\n\t\t)\n\t);\n}\n\nfunction resolveRequiredPortalEnv(props: {\n\treadonly env: NodeJS.ProcessEnv;\n\treadonly names: ReadonlySet<string>;\n}): Readonly<Record<string, string>> {\n\tconst resolvedEnv: Record<string, string> = {};\n\tfor (const name of [...props.names].toSorted()) {\n\t\tconst value = props.env[name];\n\t\tif (value === undefined || value.length === 0) {\n\t\t\tthrow new Error(`Missing environment secret ${name} for MCP Portal subprocess.`);\n\t\t}\n\t\tresolvedEnv[name] = value;\n\t}\n\treturn resolvedEnv;\n}\n\nexport function createPortalSubprocessConfigEnv(props: {\n\treadonly env?: NodeJS.ProcessEnv;\n\treadonly mcpConfig: McpConfig;\n\treadonly mcpPortalConfig: McpPortalConfig;\n}): Readonly<Record<string, string>> {\n\tconst env = props.env ?? process.env;\n\tconst requiredNames = new Set<string>([\n\t\t...collectMcpConfigEnvironmentSecretNames(props.mcpConfig),\n\t\t...collectMcpPortalConfigEnvironmentSecretNames(props.mcpPortalConfig),\n\t]);\n\tconst portalEnv: Record<string, string> = {\n\t\t...resolveRequiredPortalEnv({ env, names: requiredNames }),\n\t};\n\tif (\n\t\tmcpConfigUsesOnePassword(props.mcpConfig) ||\n\t\tmcpPortalConfigUsesOnePassword(props.mcpPortalConfig)\n\t) {\n\t\tfor (const name of onePasswordCliEnvNames) {\n\t\t\tconst value = env[name];\n\t\t\tif (value !== undefined && value.length > 0) {\n\t\t\t\tportalEnv[name] = value;\n\t\t\t}\n\t\t}\n\t}\n\treturn portalEnv;\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tconst pluginConfig = parsePortalConfig(api.pluginConfig ?? {});\n\tif (pluginConfig.configDir !== undefined) {\n\t\treturn pluginConfig.configDir;\n\t}\n\tconst topLevelMcpConfigDir = getObjectProperty(getObjectProperty(api.config, 'mcp'), 'configDir');\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(getObjectProperty(firstZone, 'mcp'), 'configDir');\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error('MCP Portal plugin requires configDir in plugin config or zone mcp config.');\n}\n\nfunction tcpPoolConfigFromApi(api: OpenClawPortalPluginApi): TcpPoolConfig | null {\n\tconst tcpPool = getObjectProperty(api.config, 'tcpPool');\n\tconst basePort = getObjectProperty(tcpPool, 'basePort');\n\tconst size = getObjectProperty(tcpPool, 'size');\n\treturn typeof basePort === 'number' && typeof size === 'number' ? { basePort, size } : null;\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.registerService)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerService API.');\n\t}\n\tif (!hasFunction(api.on) && !hasFunction(api.registerPromptHook)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw prompt hook registration 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: 'Stops the MCP Portal subprocess supervised by the agent-vm plugin.',\n\t\tid: 'mcp-portal-subprocess',\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 registerPortalService(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly configDir: string;\n\treadonly runtimeState: PortalPluginRuntimeState;\n}): { readonly getSupervisor: () => PortalSubprocessSupervisor | null } {\n\tconst portalConfig = parsePortalConfig(props.api.pluginConfig ?? {});\n\tlet supervisor: PortalSubprocessSupervisor | null = null;\n\n\tprops.api.registerService?.({\n\t\tid: 'mcp-portal-subprocess',\n\t\tstart: async () => {\n\t\t\tconst mcpPortalConfig = await props.runtimeState.loadPortalConfig();\n\t\t\tconst mcpConfig = await loadMcpConfig(join(props.configDir, 'mcp.config.jsonc'));\n\t\t\tvalidatePortalPortAgainstTcpPool({\n\t\t\t\tport: mcpPortalConfig.server.port,\n\t\t\t\ttcpPool: tcpPoolConfigFromApi(props.api),\n\t\t\t});\n\t\t\tconst keyRegistry = createHmacKeyRegistry({\n\t\t\t\tagentIds: Object.keys(mcpPortalConfig.agents).toSorted(),\n\t\t\t});\n\t\t\tprops.runtimeState.setKeyRegistry(keyRegistry);\n\t\t\tsupervisor = createPortalSubprocessSupervisor({\n\t\t\t\tbinPath: portalConfig.binPath,\n\t\t\t\tconfigDir: props.configDir,\n\t\t\t\thost: mcpPortalConfig.server.host,\n\t\t\t\thmacEnv: keyRegistry.serializeForEnv(),\n\t\t\t\tlogger: createLoggerAdapter(props.api),\n\t\t\t\tonFatal: (reason) => {\n\t\t\t\t\tprops.runtimeState.markPortalUnavailable(reason);\n\t\t\t\t\tprops.api.logger?.error?.(`[mcp-portal] subprocess supervisor fatal: ${reason}`);\n\t\t\t\t},\n\t\t\t\tport: mcpPortalConfig.server.port,\n\t\t\t\tportalEnv: createPortalSubprocessConfigEnv({ mcpConfig, mcpPortalConfig }),\n\t\t\t});\n\t\t\tawait supervisor.start();\n\t\t\tprops.runtimeState.markPortalAvailable();\n\t\t},\n\t\tstop: async () => {\n\t\t\tawait supervisor?.stop();\n\t\t},\n\t});\n\n\treturn { getSupervisor: () => supervisor };\n}\n\nexport function registerMcpPortalPlugin(api: OpenClawPortalPluginApi): void {\n\tif (api.registrationMode !== undefined && api.registrationMode !== 'full') {\n\t\treturn;\n\t}\n\tvalidatePortalPluginApi(api);\n\tconst configDir = resolveConfigDir(api);\n\tconst runtimeState = createPortalPluginRuntimeState({ configDir });\n\tconst registeredService = registerPortalService({ api, configDir, runtimeState });\n\n\tapi.on?.(\n\t\t'before_tool_call',\n\t\tcreateBeforeToolCallHandler({ logger: createLoggerAdapter(api), runtimeState }),\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, () => registeredService.getSupervisor()?.stop());\n\tvoid runtimeState.loadPortalConfig().catch((error: unknown) => {\n\t\tapi.logger?.error?.(\n\t\t\t`[mcp-portal] failed to initialize portal config: ${messageFromUnknown(error)}`,\n\t\t);\n\t});\n}\n\nconst pluginEntry = {\n\tdescription: 'Supervises the MCP Portal subprocess 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 message: string;\n\treadonly namespace: string;\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? [\n\t\t\t\t\t`Discovery diagnostics: ${props.diagnostics\n\t\t\t\t\t\t.map((entry) => `${entry.namespace}: ${entry.message}`)\n\t\t\t\t\t\t.join('; ')}`,\n\t\t\t\t]\n\t\t\t: [];\n\n\treturn [\n\t\t'MCP Portal is available as an MCP server.',\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';\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 './hmac-key-registry.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-subprocess-supervisor.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.69",
|
|
4
4
|
"description": "OpenClaw plugin that supervises per-agent MCP Portal endpoints over configured upstream MCP servers.",
|
|
5
5
|
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"zod": "^4.4.3",
|
|
33
|
-
"@agent-vm/config-contracts": "0.0.
|
|
34
|
-
"@agent-vm/mcp-portal": "0.0.
|
|
33
|
+
"@agent-vm/config-contracts": "0.0.69",
|
|
34
|
+
"@agent-vm/mcp-portal": "0.0.69"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"openclaw": "^2026.5.7",
|