@agent-vm/openclaw-mcp-portal-plugin 0.0.67 → 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 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
@@ -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;;;UCtHnC,aAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;AAAA;AAAA,iBAoDM,gCAAA,CAAiC,KAAA;EAAA,SACvC,IAAA;EAAA,SACA,OAAA,EAAS,aAAA;AAAA;AAAA,iBA2BH,uBAAA,CAAwB,GAAA,EAAK,uBAAA;AAAA,iBAiF7B,uBAAA,CAAwB,GAAA,EAAK,uBAAA;AAAA,cAuCvC,WAAA;;;;mBAKuB,uBAAA;AAAA;;;UC/NZ,0BAAA;EAAA,SACP,QAAA;AAAA;AAAA,UAGO,eAAA;EAAA,SACP,QAAA;EAAA,SACA,MAAA,GAAS,OAAA,aAAoB,MAAA;EAAA,SAC7B,eAAA,QAAuB,QAAA,CAAS,MAAA;AAAA;AAAA,iBAG1B,qBAAA,CAAsB,KAAA,EAAO,0BAAA,GAA6B,eAAA;;;UCVzD,wBAAA;EAAA,SACP,SAAA;EAAA,SACA,0BAAA;EAAA,SACA,cAAA,QAAsB,eAAA;EAAA,SACtB,gBAAA,QAAwB,OAAA,CAAQ,eAAA;EAAA,SAChC,mBAAA;EAAA,SACA,qBAAA,GAAwB,MAAA;EAAA,SACxB,cAAA,GAAiB,QAAA,EAAU,eAAA;AAAA;AAAA,iBAGrB,8BAAA,CAA+B,KAAA;EAAA,SACrC,SAAA;EAAA,SACA,gBAAA,IAAoB,IAAA,aAAiB,OAAA,CAAQ,eAAA;AAAA,IACnD,wBAAA;;;UCVa,mCAAA;EAAA,SACP,YAAA,EAAc,wBAAA;AAAA;AAAA,iBAGR,8BAAA,CACf,KAAA,EAAO,mCAAA,IAEP,KAAA,EAAO,8BAAA,EACP,OAAA,EAAS,yBAAA,KACL,OAAA,CAAQ,wBAAA;;;UCAI,gCAAA;EAAA,SACP,MAAA;IAAA,SACC,IAAA,IAAQ,OAAA;EAAA;EAAA,SAET,YAAA,EAAc,wBAAA;AAAA;AAAA,iBAsDR,2BAAA,CACf,KAAA,EAAO,gCAAA,IAEP,KAAA,EAAO,2BAAA,EACP,OAAA,EAAS,yBAAA,KACL,OAAA,CAAQ,4BAAA;;;cC/EA,oBAAA;AAAA,cAEA,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;KAOzB,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,iBAEhC,iBAAA,CAAkB,KAAA,YAAiB,kBAAA;;;UCVlC,sBAAA;EAAA,SACP,KAAA,GAAQ,OAAA;EAAA,SACR,IAAA,GAAO,OAAA;EAAA,SACP,IAAA,GAAO,OAAA;AAAA;AAAA,KAGL,6BAAA,IACX,OAAA,UACA,IAAA,qBACA,OAAA,EAAS,YAAA,KACL,YAAA;AAAA,UAEY,qCAAA;EAAA,SACP,YAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA,UAAiB,KAAA;EAAA,SACjB,oBAAA;EAAA,SACA,eAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA;EAAA,SAClB,MAAA,EAAQ,sBAAA;EAAA,SACR,WAAA;EAAA,SACA,OAAA,IAAW,MAAA;EAAA,SACX,IAAA;EAAA,SACA,OAAA,GAAU,6BAAA;EAAA,SACV,WAAA;AAAA;AAAA,UAGO,0BAAA;EAAA,SACP,OAAA;EAAA,SACA,KAAA,QAAa,OAAA;EAAA,SACb,IAAA,QAAY,OAAA;AAAA;AAAA,iBAwHN,gCAAA,CACf,KAAA,EAAO,qCAAA,GACL,0BAAA;;;UCxJc,iBAAA;EAAA,SACP,SAAA,EAAW,MAAA;EAAA,SACX,EAAA;EAAA,SACA,SAAA;EAAA,SACA,QAAA;AAAA;AAAA,iBAgBM,wBAAA,CAAyB,OAAA;AAAA,iBAIzB,2BAAA,CAA4B,UAAA;AAAA,iBAS5B,uBAAA,CACf,OAAA,EAAS,wBAAA,EACT,IAAA;EAAA,SAAiB,SAAA;EAAA,SAA4B,QAAA;AAAA;AAAA,iBAa9B,6BAAA,CACf,OAAA,EAAS,wBAAA,EACT,IAAA;EAAA,SAAiB,SAAA;EAAA,SAA4B,QAAA;AAAA;;;UCvD7B,4BAAA;EAAA,SACP,SAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGO,sBAAA;EAAA,SACP,OAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGM,yBAAA,CAA0B,KAAA;EAAA,SAChC,WAAA,YAAuB,sBAAA;EAAA,SACvB,UAAA,WAAqB,4BAAA;AAAA;;;iBCVf,mBAAA,CAAoB,IAAA,UAAc,YAAA;;;cCWrC,uCAAA"}
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 { loadMcpPortalConfig, mcpPortalCallRequiresApproval, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
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.67",
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.67",
34
- "@agent-vm/mcp-portal": "0.0.67"
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",