@agent-vm/openclaw-mcp-portal-plugin 0.0.72 → 0.0.74

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-plugin-api.ts","../src/plugin-registration.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/before-tool-call-handler.ts","../src/portal-config.ts","../src/portal-tool-policy.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-plugin-api.ts","../src/plugin-registration.ts","../src/portal-plugin-runtime-state.ts","../src/before-prompt-build-handler.ts","../src/before-tool-call-handler.ts","../src/portal-config.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
@@ -381,9 +381,20 @@ function registerNativePortalTools(props) {
381
381
  optional: true
382
382
  });
383
383
  }
384
+ function shouldRegisterPortalRuntimeHooks(api) {
385
+ return api.registrationMode === void 0 || api.registrationMode === "full";
386
+ }
387
+ function formatRegistrationMode(api) {
388
+ return api.registrationMode ?? "full";
389
+ }
384
390
  function registerMcpPortalPlugin(api) {
385
- if (api.registrationMode !== void 0 && api.registrationMode !== "full") return;
386
- validatePortalPluginApi(api);
391
+ const logger = createLoggerAdapter(api);
392
+ const registerRuntimeHooks = shouldRegisterPortalRuntimeHooks(api);
393
+ if (registerRuntimeHooks) validatePortalPluginApi(api);
394
+ else if (!hasFunction(api.registerTool)) {
395
+ logger.warn(`[mcp-portal] skipped native portal tool registration for registrationMode='${formatRegistrationMode(api)}' because OpenClaw did not expose registerTool.`);
396
+ return;
397
+ }
387
398
  const configDir = resolveConfigDir(api);
388
399
  const runtimeState = createPortalPluginRuntimeState({ configDir });
389
400
  let corePromise;
@@ -399,8 +410,12 @@ function registerMcpPortalPlugin(api) {
399
410
  getCore,
400
411
  runtimeState
401
412
  });
413
+ if (!registerRuntimeHooks) {
414
+ logger.info(`[mcp-portal] registered native portal tools for registrationMode='${formatRegistrationMode(api)}'.`);
415
+ return;
416
+ }
402
417
  api.on?.("before_tool_call", createBeforeToolCallHandler({
403
- logger: createLoggerAdapter(api),
418
+ logger,
404
419
  runtimeState
405
420
  }), { priority: 80 });
406
421
  api.on?.("before_prompt_build", createBeforePromptBuildHandler({ runtimeState }), { priority: 80 });
@@ -411,6 +426,7 @@ function registerMcpPortalPlugin(api) {
411
426
  registerPortalRuntimeCleanup(api, async () => {
412
427
  await (await corePromise?.catch(() => void 0))?.close();
413
428
  });
429
+ logger.info("[mcp-portal] registered native portal tools and runtime hooks.");
414
430
  }
415
431
  const pluginEntry = {
416
432
  description: "Registers native OpenClaw MCP Portal tools and wires per-agent approval hooks.",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isObjectRecord","isObjectRecord"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/effective-config-manifest.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/plugin-registration.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"sourcesContent":["import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\n\nimport type {\n\tOpenClawBeforePromptBuildEvent,\n\tOpenClawPluginHookContext,\n\tOpenClawPromptHookResult,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\nexport interface CreateBeforePromptBuildHandlerProps {\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nexport function createBeforePromptBuildHandler(\n\tprops: CreateBeforePromptBuildHandlerProps,\n): (\n\tevent: OpenClawBeforePromptBuildEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawPromptHookResult | undefined> {\n\treturn async (_event, context) => {\n\t\tconst agentId = context.agentId;\n\t\tif (agentId === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tif (!profile.promptContext.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst namespaces = profile.enabledNamespaces\n\t\t\t.toSorted()\n\t\t\t.slice(0, profile.promptContext.maxNamespaces);\n\t\tconst namespaceText =\n\t\t\tnamespaces.length === 0\n\t\t\t\t? ' (none in your profile)'\n\t\t\t\t: namespaces.map((name) => ` ${name}`).join('\\n');\n\t\treturn {\n\t\t\tappendSystemContext: [\n\t\t\t\t'MCP Portal namespaces available to this agent:',\n\t\t\t\tnamespaceText,\n\t\t\t\t'Use mcp_portal_search to find tools by intent, then mcp_portal_describe before mcp_portal_call.',\n\t\t\t].join('\\n'),\n\t\t};\n\t};\n}\n","import {\n\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\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';\n\nimport type {\n\tOpenClawBeforeToolCallEvent,\n\tOpenClawBeforeToolCallResult,\n\tOpenClawPluginHookContext,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\nimport {\n\tprofileAllowsPortalCall,\n\tprofileRequiresPortalApproval,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nexport interface CreateBeforeToolCallHandlerProps {\n\treadonly logger?: {\n\t\treadonly warn?: (message: string) => void;\n\t};\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCallRequest(value: unknown): PortalCallRequest | null {\n\tif (!isObjectRecord(value)) {\n\t\treturn null;\n\t}\n\tconst id = value.id;\n\tconst namespace = value.namespace;\n\tconst toolName = value.toolName;\n\tconst argumentsValue = value.arguments;\n\tif (\n\t\ttypeof id !== 'string' ||\n\t\ttypeof namespace !== 'string' ||\n\t\ttypeof toolName !== 'string' ||\n\t\t!isObjectRecord(argumentsValue)\n\t) {\n\t\treturn null;\n\t}\n\treturn { arguments: argumentsValue, id, namespace, toolName };\n}\n\nfunction parseCallRequests(params: Record<string, unknown>): readonly PortalCallRequest[] | null {\n\tconst calls = params.calls;\n\tif (!Array.isArray(calls)) {\n\t\treturn null;\n\t}\n\tconst parsedCalls: PortalCallRequest[] = [];\n\tfor (const call of calls) {\n\t\tconst parsedCall = parseCallRequest(call);\n\t\tif (parsedCall === null) {\n\t\t\treturn null;\n\t\t}\n\t\tparsedCalls.push(parsedCall);\n\t}\n\treturn parsedCalls;\n}\n\nexport function createBeforeToolCallHandler(\n\tprops: CreateBeforeToolCallHandlerProps,\n): (\n\tevent: OpenClawBeforeToolCallEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawBeforeToolCallResult | undefined> {\n\treturn async (event, context) => {\n\t\tif (event.toolName !== 'mcp_portal_call') {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (context.agentId === undefined) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: missing OpenClaw agent context for ${event.toolName}.`,\n\t\t\t};\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = context.agentId;\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn { block: true, blockReason: `mcp-portal: agent \"${agentId}\" is not configured.` };\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tconst calls = parseCallRequests(event.params);\n\t\tif (calls === null || calls.length === 0) {\n\t\t\treturn { block: true, blockReason: 'mcp-portal: malformed portal call batch.' };\n\t\t}\n\n\t\tfor (const call of calls) {\n\t\t\tif (!profileAllowsPortalCall(profile, call)) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\tblockReason: `policy: ${agentId}/${call.namespace}/${call.toolName} not enabled`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst approvalCalls = calls.filter((call) => profileRequiresPortalApproval(profile, call));\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst toolNames = approvalCalls\n\t\t\t.map((call) => `${call.namespace}.${call.toolName}`)\n\t\t\t.toSorted()\n\t\t\t.join(', ');\n\t\treturn {\n\t\t\trequireApproval: {\n\t\t\t\tdescription: `Allow MCP Portal batch for agent ${agentId}: ${toolNames}.`,\n\t\t\t\tpluginId: 'mcp-portal',\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttimeoutBehavior: 'deny',\n\t\t\t\ttimeoutMs: 60_000,\n\t\t\t\ttitle: `MCP Portal batch: ${toolNames}`,\n\t\t\t},\n\t\t};\n\t};\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst effectiveConfigManifestFileName = 'mcp-portal-effective-manifest.json';\n\nexport interface EffectiveConfigPaths {\n\treadonly mcpConfigPath: string;\n\treadonly portalConfigPath: string;\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isSafeManifestFileName(value: string): boolean {\n\treturn value.length > 0 && !value.includes('/') && !value.includes('\\\\');\n}\n\nfunction parseEffectiveConfigManifest(value: unknown): {\n\treadonly mcpConfigFile: string;\n\treadonly portalConfigFile: string;\n} {\n\tif (!isObjectRecord(value)) {\n\t\tthrow new Error('MCP Portal effective config manifest must be an object.');\n\t}\n\tif (value.schemaVersion !== 1) {\n\t\tthrow new Error('MCP Portal effective config manifest must use schemaVersion 1.');\n\t}\n\tif (typeof value.mcpConfigFile !== 'string' || !isSafeManifestFileName(value.mcpConfigFile)) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe mcpConfigFile.');\n\t}\n\tif (\n\t\ttypeof value.portalConfigFile !== 'string' ||\n\t\t!isSafeManifestFileName(value.portalConfigFile)\n\t) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe portalConfigFile.');\n\t}\n\treturn {\n\t\tmcpConfigFile: value.mcpConfigFile,\n\t\tportalConfigFile: value.portalConfigFile,\n\t};\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn (\n\t\tisObjectRecord(error) &&\n\t\ttypeof error.code === 'string' &&\n\t\t(error.code === 'ENOENT' || error.code === 'ENOTDIR')\n\t);\n}\n\nexport async function resolveEffectiveConfigPaths(\n\tconfigDir: string,\n): Promise<EffectiveConfigPaths> {\n\tconst manifestPath = join(configDir, effectiveConfigManifestFileName);\n\tlet manifestText: string;\n\ttry {\n\t\tmanifestText = await readFile(manifestPath, 'utf8');\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) {\n\t\t\treturn {\n\t\t\t\tmcpConfigPath: join(configDir, 'mcp.config.jsonc'),\n\t\t\t\tportalConfigPath: join(configDir, 'mcp-portal.config.jsonc'),\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\tconst manifest = parseEffectiveConfigManifest(JSON.parse(manifestText));\n\treturn {\n\t\tmcpConfigPath: join(configDir, manifest.mcpConfigFile),\n\t\tportalConfigPath: join(configDir, manifest.portalConfigFile),\n\t};\n}\n","import { z } from 'zod';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tconfigDir: z.string().min(1),\n\t})\n\t.strict();\n\nexport type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;\n\nexport function parsePortalConfig(value: unknown): PortalPluginConfig {\n\treturn portalPluginConfigSchema.parse(value ?? {});\n}\n","import { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly configDir: string;\n\treadonly getLoadedPortalConfig: () => McpPortalConfig | null;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet loadedPortalConfig: McpPortalConfig | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = resolveEffectiveConfigPaths(props.configDir)\n\t\t\t.then((effectiveConfigPaths) => loadPortalConfigFile(effectiveConfigPaths.portalConfigPath))\n\t\t\t.then((portalConfig) => {\n\t\t\t\tloadedPortalConfig = portalConfig;\n\t\t\t\treturn portalConfig;\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\t\tportalConfigPromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn portalConfigPromise;\n\t}\n\n\treturn {\n\t\tconfigDir: props.configDir,\n\t\tgetLoadedPortalConfig: () => loadedPortalConfig,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tloadPortalConfig,\n\t\tmarkPortalAvailable: () => {\n\t\t\tportalUnavailableReason = null;\n\t\t},\n\t\tmarkPortalUnavailable: (reason) => {\n\t\t\tportalUnavailableReason = reason;\n\t\t},\n\t};\n}\n","import {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\ttype McpPortalConfig,\n\tresolveMcpPortalProfile,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport {\n\tcreatePortalCore,\n\tcreateUpstreamMcpClientRuntime,\n\tlistPortalCoreToolDescriptors,\n\tresolveUpstreamServers,\n\ttype PortalCore,\n\ttype PortalCoreEvent,\n\ttype PortalCoreToolDescriptor,\n\ttype PortalToolSelector,\n} from '@agent-vm/mcp-portal/core';\n\nimport { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\nimport type {\n\tOpenClawPortalPluginApi,\n\tOpenClawPluginToolContext,\n\tOpenClawToolRegistration,\n\tOpenClawToolUpdateCallback,\n} from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport { createPortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\ninterface PortalPluginEntry {\n\treadonly description: string;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly register: (api: OpenClawPortalPluginApi) => void;\n}\n\ninterface TcpPoolConfig {\n\treadonly basePort: number;\n\treadonly size: number;\n}\n\ninterface ProfilePolicyMaps {\n\treadonly cacheTtlMs: number;\n\treadonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;\n\treadonly enabledToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n\treadonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n}\n\nconst pluginId = 'mcp-portal';\n\nfunction hasFunction(value: unknown): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === 'function';\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isUnknownArray(value: unknown): value is readonly unknown[] {\n\treturn Array.isArray(value);\n}\n\nfunction getObjectProperty(value: unknown, property: string): unknown {\n\treturn isObjectRecord(value) ? value[property] : undefined;\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tif (api.pluginConfig !== undefined) {\n\t\treturn parsePortalConfig(api.pluginConfig).configDir;\n\t}\n\t// Managed agent-vm passes pluginConfig. The config fallbacks keep the plugin usable\n\t// in direct OpenClaw test harnesses that load plugin config through the root config.\n\tconst topLevelMcpConfigDir = getObjectProperty(\n\t\tgetObjectProperty(api.config, 'mcpPortal'),\n\t\t'configDir',\n\t);\n\tif (typeof topLevelMcpConfigDir === 'string' && topLevelMcpConfigDir.length > 0) {\n\t\treturn topLevelMcpConfigDir;\n\t}\n\tconst zones = getObjectProperty(api.config, 'zones');\n\tif (isUnknownArray(zones)) {\n\t\tconst firstZone = zones.at(0);\n\t\tconst zoneMcpConfigDir = getObjectProperty(\n\t\t\tgetObjectProperty(firstZone, 'mcpPortal'),\n\t\t\t'configDir',\n\t\t);\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'MCP Portal plugin requires configDir in plugin config or zone mcpPortal config.',\n\t);\n}\n\nexport function validatePortalPortAgainstTcpPool(props: {\n\treadonly port: number;\n\treadonly tcpPool: TcpPoolConfig | null;\n}): void {\n\tif (props.tcpPool === null) {\n\t\treturn;\n\t}\n\tconst firstTcpPoolPort = props.tcpPool.basePort;\n\tconst lastTcpPoolPortExclusive = props.tcpPool.basePort + props.tcpPool.size;\n\tif (props.port >= firstTcpPoolPort && props.port < lastTcpPoolPortExclusive) {\n\t\tthrow new Error(\n\t\t\t`MCP Portal port ${String(props.port)} overlaps the Tool VM TCP pool ` +\n\t\t\t\t`[${String(firstTcpPoolPort)}, ${String(lastTcpPoolPortExclusive)}).`,\n\t\t);\n\t}\n}\n\nfunction createLoggerAdapter(api: OpenClawPortalPluginApi): {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n} {\n\treturn {\n\t\terror: (message) => api.logger?.error?.(message),\n\t\tinfo: (message) => api.logger?.info?.(message),\n\t\twarn: (message) => api.logger?.warn?.(message),\n\t};\n}\n\nexport function validatePortalPluginApi(api: OpenClawPortalPluginApi): void {\n\tif (!hasFunction(api.registerTool)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerTool API.');\n\t}\n\tif (!hasFunction(api.on)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw before_tool_call hook API.');\n\t}\n\tconst hasLifecycleCleanupApi =\n\t\thasFunction(api.lifecycle?.registerRuntimeLifecycle) ||\n\t\thasFunction(api.registerRuntimeLifecycle);\n\tif (hasLifecycleCleanupApi) {\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction registerPortalRuntimeCleanup(\n\tapi: OpenClawPortalPluginApi,\n\tcleanup: () => Promise<void> | void,\n): void {\n\tconst runtimeLifecycle = {\n\t\tcleanup: async () => {\n\t\t\tawait cleanup();\n\t\t},\n\t\tdescription: 'Closes MCP Portal upstream clients owned by the agent-vm plugin.',\n\t\tid: 'mcp-portal-core',\n\t} satisfies Parameters<NonNullable<OpenClawPortalPluginApi['registerRuntimeLifecycle']>>[0];\n\tif (hasFunction(api.lifecycle?.registerRuntimeLifecycle)) {\n\t\tapi.lifecycle.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tif (hasFunction(api.registerRuntimeLifecycle)) {\n\t\tapi.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction selectorsFromNamespaceTools(\n\tnamespaceTools: Readonly<Record<string, readonly string[]>>,\n): readonly PortalToolSelector[] {\n\treturn Object.entries(namespaceTools).flatMap(([namespace, toolNames]) =>\n\t\ttoolNames.map((toolName) => ({ namespace, toolName })),\n\t);\n}\n\nfunction buildProfilePolicyMaps(portalConfig: McpPortalConfig): ProfilePolicyMaps {\n\tconst enabledNamespacesByAgent: Record<string, readonly string[]> = {};\n\tconst enabledToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst hiddenToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst profileTtls: number[] = [];\n\n\tfor (const [agentId, agent] of Object.entries(portalConfig.agents)) {\n\t\tconst profile: ResolvedMcpPortalProfile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tenabledNamespacesByAgent[agentId] = profile.enabledNamespaces;\n\t\tenabledToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.enabledToolsByNamespace);\n\t\thiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);\n\t\tprofileTtls.push(profile.cache.catalogTtlMs);\n\t}\n\n\treturn {\n\t\tcacheTtlMs: profileTtls.length === 0 ? 60_000 : Math.min(...profileTtls),\n\t\tenabledNamespacesByAgent,\n\t\tenabledToolsByAgent,\n\t\thiddenToolsByAgent,\n\t};\n}\n\nasync function resolveManagedPortalSecret(secret: SecretValue): Promise<string> {\n\tif (secret.source !== 'environment') {\n\t\tthrow new Error(\n\t\t\t'MCP Portal managed OpenClaw effective config must use environment secret refs.',\n\t\t);\n\t}\n\tconst value = process.env[secret.name];\n\tif (value === undefined || value.length === 0) {\n\t\tthrow new Error(`Missing environment secret ${secret.name} for MCP Portal native plugin.`);\n\t}\n\treturn value;\n}\n\nasync function createManagedPortalCore(configDir: string): Promise<PortalCore> {\n\tconst effectiveConfigPaths = await resolveEffectiveConfigPaths(configDir);\n\tconst [mcpConfig, portalConfig] = await Promise.all([\n\t\tloadMcpConfig(effectiveConfigPaths.mcpConfigPath),\n\t\tloadMcpPortalConfig(effectiveConfigPaths.portalConfigPath),\n\t]);\n\tconst upstreamServers = await resolveUpstreamServers({\n\t\tconfig: mcpConfig,\n\t\tresolveSecret: resolveManagedPortalSecret,\n\t});\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\n\treturn createPortalCore({\n\t\taccessPolicy: {\n\t\t\tdefaultPolicy: 'deny-all',\n\t\t\tenabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,\n\t\t\tenabledToolsByAgent: profilePolicyMaps.enabledToolsByAgent,\n\t\t\thiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent,\n\t\t},\n\t\tapprovalTrustBoundary: 'openclaw-before-tool-call-hook',\n\t\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: {\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tcloseAgentScope: upstreamRuntime.closeAgentScope,\n\t\t\tcloseSession: upstreamRuntime.closeSession,\n\t\t\tlistTools: upstreamRuntime.listTools,\n\t\t},\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n}\n\nfunction portalUpdateFromCoreEvent(event: PortalCoreEvent): Record<string, unknown> | null {\n\tif (event.kind === 'progress') {\n\t\treturn {\n\t\t\tmessage: event.message ?? 'MCP Portal progress',\n\t\t\t...(event.progress !== undefined ? { progress: event.progress } : {}),\n\t\t\trequestId: event.requestId,\n\t\t\t...(event.total !== undefined ? { total: event.total } : {}),\n\t\t\ttype: 'mcp_portal_progress',\n\t\t};\n\t}\n\tif (event.kind === 'partial_content') {\n\t\treturn {\n\t\t\tcontent: event.content,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_partial_content',\n\t\t};\n\t}\n\tif (event.kind === 'upstream_notification') {\n\t\treturn {\n\t\t\tmethod: event.method,\n\t\t\tparams: event.params,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_upstream_notification',\n\t\t};\n\t}\n\treturn null;\n}\n\nasync function forwardCoreEvent(\n\tevent: PortalCoreEvent,\n\tlogger: ReturnType<typeof createLoggerAdapter>,\n\tonUpdate: OpenClawToolUpdateCallback | undefined,\n): Promise<void> {\n\tconst update = portalUpdateFromCoreEvent(event);\n\tif (update !== null) {\n\t\ttry {\n\t\t\tawait onUpdate?.(update);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tlogger.warn(`[mcp-portal] OpenClaw onUpdate delivery failed: ${message}`);\n\t\t}\n\t}\n}\n\nfunction createNativeTool(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly descriptor: PortalCoreToolDescriptor;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly logger: ReturnType<typeof createLoggerAdapter>;\n}): OpenClawToolRegistration {\n\treturn {\n\t\tdescription: props.descriptor.description,\n\t\texecute: async (_toolCallId, params, signal, onUpdate) => {\n\t\t\tif (props.context.agentId === undefined || props.context.agentId.length === 0) {\n\t\t\t\tthrow new Error('mcp-portal: OpenClaw did not provide a trusted agentId.');\n\t\t\t}\n\t\t\tconst core = await props.getCore();\n\t\t\tconst scope = core.createAgentScope({\n\t\t\t\tagentId: props.context.agentId,\n\t\t\t\tagentScopeId: props.context.agentId,\n\t\t\t\t...(props.context.sessionId ? { sessionId: props.context.sessionId } : {}),\n\t\t\t\t...(props.context.sessionKey ? { sessionKey: props.context.sessionKey } : {}),\n\t\t\t\tsource: 'openclaw-trusted',\n\t\t\t});\n\t\t\tconst result = await core.collectPortalCoreResult(\n\t\t\t\tcore.callStream({\n\t\t\t\t\tinput: params,\n\t\t\t\t\tscope,\n\t\t\t\t\t...(signal !== undefined ? { signal } : {}),\n\t\t\t\t\ttoolName: props.descriptor.name,\n\t\t\t\t}),\n\t\t\t\t{ onEvent: (event) => forwardCoreEvent(event, props.logger, onUpdate) },\n\t\t\t);\n\t\t\treturn { content: JSON.stringify(result), details: result };\n\t\t},\n\t\tlabel: props.descriptor.name,\n\t\tname: props.descriptor.name,\n\t\tparameters: props.descriptor.inputSchema,\n\t};\n}\n\nfunction descriptorsForOpenClawContext(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly portalConfig: McpPortalConfig | null;\n}): readonly PortalCoreToolDescriptor[] {\n\tif (props.portalConfig === null || props.context.agentId === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst agent = props.portalConfig.agents[props.context.agentId];\n\tif (agent === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst profile = resolveMcpPortalProfile(props.portalConfig, agent.profile);\n\treturn listPortalCoreToolDescriptors(profile.enabledNamespaces);\n}\n\nfunction registerNativePortalTools(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly runtimeState: ReturnType<typeof createPortalPluginRuntimeState>;\n}): void {\n\tconst descriptorNames = listPortalCoreToolDescriptors().map((descriptor) => descriptor.name);\n\tconst logger = createLoggerAdapter(props.api);\n\tprops.api.registerTool?.(\n\t\t(context) => {\n\t\t\tconst descriptors = descriptorsForOpenClawContext({\n\t\t\t\tcontext,\n\t\t\t\tportalConfig: props.runtimeState.getLoadedPortalConfig(),\n\t\t\t});\n\t\t\treturn descriptors.map((descriptor) =>\n\t\t\t\tcreateNativeTool({ context, descriptor, getCore: props.getCore, logger }),\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tnames: descriptorNames,\n\t\t\toptional: true,\n\t\t},\n\t);\n}\n\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\tlet corePromise: Promise<PortalCore> | undefined;\n\tconst getCore = (): Promise<PortalCore> => {\n\t\tcorePromise ??= createManagedPortalCore(configDir).catch((error: unknown) => {\n\t\t\tcorePromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t\treturn corePromise;\n\t};\n\tregisterNativePortalTools({ api, getCore, runtimeState });\n\n\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, async () => {\n\t\tconst core = await corePromise?.catch(() => undefined);\n\t\tawait core?.close();\n\t});\n}\n\nconst pluginEntry = {\n\tdescription: 'Registers native OpenClaw MCP Portal tools and wires per-agent approval hooks.',\n\tid: pluginId,\n\tname: 'MCP Portal',\n\tregister: registerMcpPortalPlugin,\n} satisfies PortalPluginEntry;\n\nexport default pluginEntry;\n","export interface PortalPromptNamespaceSummary {\n\treadonly namespace: string;\n\treadonly toolCount: number;\n}\n\nexport interface PortalPromptDiagnostic {\n\treadonly 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 native OpenClaw tools.',\n\t\t'Use mcp_portal_list with requests[], mcp_portal_search with requests[],',\n\t\t'mcp_portal_describe with requests[], and mcp_portal_call with calls[].',\n\t\t'Responses are { ok, results, errors, diagnostics }; results is keyed by each request/call id and each value is discriminated by ok: true or ok: false.',\n\t\t'Call upstream tools by namespace + toolName inside calls[].',\n\t\t'Call mcp_portal_describe before mcp_portal_call unless you already saw the full schema for that tool in this portal session.',\n\t\t'Gateway owns MCP auth.',\n\t\t`Namespaces: ${namespaceList}`,\n\t\t...diagnostics,\n\t].join('\\n');\n}\n","import { redactCredentialText } from '@agent-vm/mcp-portal/core';\n\nexport function redactPortalSecrets(text: string, secretValues: readonly string[] = []): string {\n\treturn secretValues\n\t\t.filter((secretValue) => secretValue.length > 0)\n\t\t.reduce(\n\t\t\t(current, secretValue) => current.split(secretValue).join('[REDACTED]'),\n\t\t\tredactCredentialText(text),\n\t\t);\n}\n","export * from './openclaw-plugin-api.js';\nexport * from './plugin-registration.js';\nexport * from './before-prompt-build-handler.js';\nexport * from './before-tool-call-handler.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-tool-policy.js';\nexport * from './portal-prompt-context.js';\nexport * from './redaction.js';\nexport { default } from './plugin-registration.js';\n\nexport const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = '@agent-vm/openclaw-mcp-portal-plugin';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["isObjectRecord","isObjectRecord"],"sources":["../src/before-prompt-build-handler.ts","../src/portal-tool-policy.ts","../src/before-tool-call-handler.ts","../src/effective-config-manifest.ts","../src/portal-config.ts","../src/portal-plugin-runtime-state.ts","../src/plugin-registration.ts","../src/portal-prompt-context.ts","../src/redaction.ts","../src/index.ts"],"sourcesContent":["import { resolveMcpPortalProfile } from '@agent-vm/config-contracts';\n\nimport type {\n\tOpenClawBeforePromptBuildEvent,\n\tOpenClawPluginHookContext,\n\tOpenClawPromptHookResult,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\nexport interface CreateBeforePromptBuildHandlerProps {\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nexport function createBeforePromptBuildHandler(\n\tprops: CreateBeforePromptBuildHandlerProps,\n): (\n\tevent: OpenClawBeforePromptBuildEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawPromptHookResult | undefined> {\n\treturn async (_event, context) => {\n\t\tconst agentId = context.agentId;\n\t\tif (agentId === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tif (!profile.promptContext.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst namespaces = profile.enabledNamespaces\n\t\t\t.toSorted()\n\t\t\t.slice(0, profile.promptContext.maxNamespaces);\n\t\tconst namespaceText =\n\t\t\tnamespaces.length === 0\n\t\t\t\t? ' (none in your profile)'\n\t\t\t\t: namespaces.map((name) => ` ${name}`).join('\\n');\n\t\treturn {\n\t\t\tappendSystemContext: [\n\t\t\t\t'MCP Portal namespaces available to this agent:',\n\t\t\t\tnamespaceText,\n\t\t\t\t'Use mcp_portal_search to find tools by intent, then mcp_portal_describe before mcp_portal_call.',\n\t\t\t].join('\\n'),\n\t\t};\n\t};\n}\n","import {\n\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\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';\n\nimport type {\n\tOpenClawBeforeToolCallEvent,\n\tOpenClawBeforeToolCallResult,\n\tOpenClawPluginHookContext,\n} from './openclaw-plugin-api.js';\nimport type { PortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\nimport {\n\tprofileAllowsPortalCall,\n\tprofileRequiresPortalApproval,\n\ttype PortalCallRequest,\n} from './portal-tool-policy.js';\n\nexport interface CreateBeforeToolCallHandlerProps {\n\treadonly logger?: {\n\t\treadonly warn?: (message: string) => void;\n\t};\n\treadonly runtimeState: PortalPluginRuntimeState;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCallRequest(value: unknown): PortalCallRequest | null {\n\tif (!isObjectRecord(value)) {\n\t\treturn null;\n\t}\n\tconst id = value.id;\n\tconst namespace = value.namespace;\n\tconst toolName = value.toolName;\n\tconst argumentsValue = value.arguments;\n\tif (\n\t\ttypeof id !== 'string' ||\n\t\ttypeof namespace !== 'string' ||\n\t\ttypeof toolName !== 'string' ||\n\t\t!isObjectRecord(argumentsValue)\n\t) {\n\t\treturn null;\n\t}\n\treturn { arguments: argumentsValue, id, namespace, toolName };\n}\n\nfunction parseCallRequests(params: Record<string, unknown>): readonly PortalCallRequest[] | null {\n\tconst calls = params.calls;\n\tif (!Array.isArray(calls)) {\n\t\treturn null;\n\t}\n\tconst parsedCalls: PortalCallRequest[] = [];\n\tfor (const call of calls) {\n\t\tconst parsedCall = parseCallRequest(call);\n\t\tif (parsedCall === null) {\n\t\t\treturn null;\n\t\t}\n\t\tparsedCalls.push(parsedCall);\n\t}\n\treturn parsedCalls;\n}\n\nexport function createBeforeToolCallHandler(\n\tprops: CreateBeforeToolCallHandlerProps,\n): (\n\tevent: OpenClawBeforeToolCallEvent,\n\tcontext: OpenClawPluginHookContext,\n) => Promise<OpenClawBeforeToolCallResult | undefined> {\n\treturn async (event, context) => {\n\t\tif (event.toolName !== 'mcp_portal_call') {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (context.agentId === undefined) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\tblockReason: `mcp-portal: missing OpenClaw agent context for ${event.toolName}.`,\n\t\t\t};\n\t\t}\n\t\tconst portalConfig = await props.runtimeState.loadPortalConfig();\n\t\tconst agentId = context.agentId;\n\t\tconst agent = portalConfig.agents[agentId];\n\t\tif (agent === undefined) {\n\t\t\treturn { block: true, blockReason: `mcp-portal: agent \"${agentId}\" is not configured.` };\n\t\t}\n\t\tconst profile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tconst calls = parseCallRequests(event.params);\n\t\tif (calls === null || calls.length === 0) {\n\t\t\treturn { block: true, blockReason: 'mcp-portal: malformed portal call batch.' };\n\t\t}\n\n\t\tfor (const call of calls) {\n\t\t\tif (!profileAllowsPortalCall(profile, call)) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\tblockReason: `policy: ${agentId}/${call.namespace}/${call.toolName} not enabled`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst approvalCalls = calls.filter((call) => profileRequiresPortalApproval(profile, call));\n\t\tif (approvalCalls.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst toolNames = approvalCalls\n\t\t\t.map((call) => `${call.namespace}.${call.toolName}`)\n\t\t\t.toSorted()\n\t\t\t.join(', ');\n\t\treturn {\n\t\t\trequireApproval: {\n\t\t\t\tdescription: `Allow MCP Portal batch for agent ${agentId}: ${toolNames}.`,\n\t\t\t\tpluginId: 'mcp-portal',\n\t\t\t\tseverity: 'warning',\n\t\t\t\ttimeoutBehavior: 'deny',\n\t\t\t\ttimeoutMs: 60_000,\n\t\t\t\ttitle: `MCP Portal batch: ${toolNames}`,\n\t\t\t},\n\t\t};\n\t};\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst effectiveConfigManifestFileName = 'mcp-portal-effective-manifest.json';\n\nexport interface EffectiveConfigPaths {\n\treadonly mcpConfigPath: string;\n\treadonly portalConfigPath: string;\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isSafeManifestFileName(value: string): boolean {\n\treturn value.length > 0 && !value.includes('/') && !value.includes('\\\\');\n}\n\nfunction parseEffectiveConfigManifest(value: unknown): {\n\treadonly mcpConfigFile: string;\n\treadonly portalConfigFile: string;\n} {\n\tif (!isObjectRecord(value)) {\n\t\tthrow new Error('MCP Portal effective config manifest must be an object.');\n\t}\n\tif (value.schemaVersion !== 1) {\n\t\tthrow new Error('MCP Portal effective config manifest must use schemaVersion 1.');\n\t}\n\tif (typeof value.mcpConfigFile !== 'string' || !isSafeManifestFileName(value.mcpConfigFile)) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe mcpConfigFile.');\n\t}\n\tif (\n\t\ttypeof value.portalConfigFile !== 'string' ||\n\t\t!isSafeManifestFileName(value.portalConfigFile)\n\t) {\n\t\tthrow new Error('MCP Portal effective config manifest must contain a safe portalConfigFile.');\n\t}\n\treturn {\n\t\tmcpConfigFile: value.mcpConfigFile,\n\t\tportalConfigFile: value.portalConfigFile,\n\t};\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn (\n\t\tisObjectRecord(error) &&\n\t\ttypeof error.code === 'string' &&\n\t\t(error.code === 'ENOENT' || error.code === 'ENOTDIR')\n\t);\n}\n\nexport async function resolveEffectiveConfigPaths(\n\tconfigDir: string,\n): Promise<EffectiveConfigPaths> {\n\tconst manifestPath = join(configDir, effectiveConfigManifestFileName);\n\tlet manifestText: string;\n\ttry {\n\t\tmanifestText = await readFile(manifestPath, 'utf8');\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) {\n\t\t\treturn {\n\t\t\t\tmcpConfigPath: join(configDir, 'mcp.config.jsonc'),\n\t\t\t\tportalConfigPath: join(configDir, 'mcp-portal.config.jsonc'),\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\tconst manifest = parseEffectiveConfigManifest(JSON.parse(manifestText));\n\treturn {\n\t\tmcpConfigPath: join(configDir, manifest.mcpConfigFile),\n\t\tportalConfigPath: join(configDir, manifest.portalConfigFile),\n\t};\n}\n","import { z } from 'zod';\n\nexport const portalPluginConfigSchema = z\n\t.object({\n\t\tconfigDir: z.string().min(1),\n\t})\n\t.strict();\n\nexport type PortalPluginConfig = z.infer<typeof portalPluginConfigSchema>;\n\nexport function parsePortalConfig(value: unknown): PortalPluginConfig {\n\treturn portalPluginConfigSchema.parse(value ?? {});\n}\n","import { loadMcpPortalConfig, type McpPortalConfig } from '@agent-vm/config-contracts';\n\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\n\nexport interface PortalPluginRuntimeState {\n\treadonly configDir: string;\n\treadonly getLoadedPortalConfig: () => McpPortalConfig | null;\n\treadonly getPortalUnavailableReason: () => string | null;\n\treadonly loadPortalConfig: () => Promise<McpPortalConfig>;\n\treadonly markPortalAvailable: () => void;\n\treadonly markPortalUnavailable: (reason: string) => void;\n}\n\nexport function createPortalPluginRuntimeState(props: {\n\treadonly configDir: string;\n\treadonly loadPortalConfig?: (path: string) => Promise<McpPortalConfig>;\n}): PortalPluginRuntimeState {\n\tlet loadedPortalConfig: McpPortalConfig | null = null;\n\tlet portalConfigPromise: Promise<McpPortalConfig> | null = null;\n\tlet portalUnavailableReason: string | null = null;\n\tconst loadPortalConfigFile = props.loadPortalConfig ?? loadMcpPortalConfig;\n\n\tfunction loadPortalConfig(): Promise<McpPortalConfig> {\n\t\tif (portalConfigPromise !== null) {\n\t\t\treturn portalConfigPromise;\n\t\t}\n\t\tconst nextPromise = resolveEffectiveConfigPaths(props.configDir)\n\t\t\t.then((effectiveConfigPaths) => loadPortalConfigFile(effectiveConfigPaths.portalConfigPath))\n\t\t\t.then((portalConfig) => {\n\t\t\t\tloadedPortalConfig = portalConfig;\n\t\t\t\treturn portalConfig;\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (portalConfigPromise === nextPromise) {\n\t\t\t\t\tportalConfigPromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tportalConfigPromise = nextPromise;\n\t\treturn portalConfigPromise;\n\t}\n\n\treturn {\n\t\tconfigDir: props.configDir,\n\t\tgetLoadedPortalConfig: () => loadedPortalConfig,\n\t\tgetPortalUnavailableReason: () => portalUnavailableReason,\n\t\tloadPortalConfig,\n\t\tmarkPortalAvailable: () => {\n\t\t\tportalUnavailableReason = null;\n\t\t},\n\t\tmarkPortalUnavailable: (reason) => {\n\t\t\tportalUnavailableReason = reason;\n\t\t},\n\t};\n}\n","import {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\ttype McpPortalConfig,\n\tresolveMcpPortalProfile,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport {\n\tcreatePortalCore,\n\tcreateUpstreamMcpClientRuntime,\n\tlistPortalCoreToolDescriptors,\n\tresolveUpstreamServers,\n\ttype PortalCore,\n\ttype PortalCoreEvent,\n\ttype PortalCoreToolDescriptor,\n\ttype PortalToolSelector,\n} from '@agent-vm/mcp-portal/core';\n\nimport { createBeforePromptBuildHandler } from './before-prompt-build-handler.js';\nimport { createBeforeToolCallHandler } from './before-tool-call-handler.js';\nimport { resolveEffectiveConfigPaths } from './effective-config-manifest.js';\nimport type {\n\tOpenClawPortalPluginApi,\n\tOpenClawPluginToolContext,\n\tOpenClawToolRegistration,\n\tOpenClawToolUpdateCallback,\n} from './openclaw-plugin-api.js';\nimport { parsePortalConfig } from './portal-config.js';\nimport { createPortalPluginRuntimeState } from './portal-plugin-runtime-state.js';\n\ninterface PortalPluginEntry {\n\treadonly description: string;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly register: (api: OpenClawPortalPluginApi) => void;\n}\n\ninterface TcpPoolConfig {\n\treadonly basePort: number;\n\treadonly size: number;\n}\n\ninterface ProfilePolicyMaps {\n\treadonly cacheTtlMs: number;\n\treadonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;\n\treadonly enabledToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n\treadonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;\n}\n\nconst pluginId = 'mcp-portal';\n\nfunction hasFunction(value: unknown): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === 'function';\n}\n\nfunction isObjectRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isUnknownArray(value: unknown): value is readonly unknown[] {\n\treturn Array.isArray(value);\n}\n\nfunction getObjectProperty(value: unknown, property: string): unknown {\n\treturn isObjectRecord(value) ? value[property] : undefined;\n}\n\nfunction resolveConfigDir(api: OpenClawPortalPluginApi): string {\n\tif (api.pluginConfig !== undefined) {\n\t\treturn parsePortalConfig(api.pluginConfig).configDir;\n\t}\n\t// Managed agent-vm passes pluginConfig. The config fallbacks keep the plugin usable\n\t// in direct OpenClaw test harnesses that load plugin config through the root config.\n\tconst topLevelMcpConfigDir = getObjectProperty(\n\t\tgetObjectProperty(api.config, 'mcpPortal'),\n\t\t'configDir',\n\t);\n\tif (typeof topLevelMcpConfigDir === 'string' && topLevelMcpConfigDir.length > 0) {\n\t\treturn topLevelMcpConfigDir;\n\t}\n\tconst zones = getObjectProperty(api.config, 'zones');\n\tif (isUnknownArray(zones)) {\n\t\tconst firstZone = zones.at(0);\n\t\tconst zoneMcpConfigDir = getObjectProperty(\n\t\t\tgetObjectProperty(firstZone, 'mcpPortal'),\n\t\t\t'configDir',\n\t\t);\n\t\tif (typeof zoneMcpConfigDir === 'string' && zoneMcpConfigDir.length > 0) {\n\t\t\treturn zoneMcpConfigDir;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'MCP Portal plugin requires configDir in plugin config or zone mcpPortal config.',\n\t);\n}\n\nexport function validatePortalPortAgainstTcpPool(props: {\n\treadonly port: number;\n\treadonly tcpPool: TcpPoolConfig | null;\n}): void {\n\tif (props.tcpPool === null) {\n\t\treturn;\n\t}\n\tconst firstTcpPoolPort = props.tcpPool.basePort;\n\tconst lastTcpPoolPortExclusive = props.tcpPool.basePort + props.tcpPool.size;\n\tif (props.port >= firstTcpPoolPort && props.port < lastTcpPoolPortExclusive) {\n\t\tthrow new Error(\n\t\t\t`MCP Portal port ${String(props.port)} overlaps the Tool VM TCP pool ` +\n\t\t\t\t`[${String(firstTcpPoolPort)}, ${String(lastTcpPoolPortExclusive)}).`,\n\t\t);\n\t}\n}\n\nfunction createLoggerAdapter(api: OpenClawPortalPluginApi): {\n\treadonly error: (message: string) => void;\n\treadonly info: (message: string) => void;\n\treadonly warn: (message: string) => void;\n} {\n\treturn {\n\t\terror: (message) => api.logger?.error?.(message),\n\t\tinfo: (message) => api.logger?.info?.(message),\n\t\twarn: (message) => api.logger?.warn?.(message),\n\t};\n}\n\nexport function validatePortalPluginApi(api: OpenClawPortalPluginApi): void {\n\tif (!hasFunction(api.registerTool)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw registerTool API.');\n\t}\n\tif (!hasFunction(api.on)) {\n\t\tthrow new Error('MCP Portal plugin requires OpenClaw before_tool_call hook API.');\n\t}\n\tconst hasLifecycleCleanupApi =\n\t\thasFunction(api.lifecycle?.registerRuntimeLifecycle) ||\n\t\thasFunction(api.registerRuntimeLifecycle);\n\tif (hasLifecycleCleanupApi) {\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction registerPortalRuntimeCleanup(\n\tapi: OpenClawPortalPluginApi,\n\tcleanup: () => Promise<void> | void,\n): void {\n\tconst runtimeLifecycle = {\n\t\tcleanup: async () => {\n\t\t\tawait cleanup();\n\t\t},\n\t\tdescription: 'Closes MCP Portal upstream clients owned by the agent-vm plugin.',\n\t\tid: 'mcp-portal-core',\n\t} satisfies Parameters<NonNullable<OpenClawPortalPluginApi['registerRuntimeLifecycle']>>[0];\n\tif (hasFunction(api.lifecycle?.registerRuntimeLifecycle)) {\n\t\tapi.lifecycle.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tif (hasFunction(api.registerRuntimeLifecycle)) {\n\t\tapi.registerRuntimeLifecycle(runtimeLifecycle);\n\t\treturn;\n\t}\n\tthrow new Error('MCP Portal plugin requires an OpenClaw lifecycle cleanup API.');\n}\n\nfunction selectorsFromNamespaceTools(\n\tnamespaceTools: Readonly<Record<string, readonly string[]>>,\n): readonly PortalToolSelector[] {\n\treturn Object.entries(namespaceTools).flatMap(([namespace, toolNames]) =>\n\t\ttoolNames.map((toolName) => ({ namespace, toolName })),\n\t);\n}\n\nfunction buildProfilePolicyMaps(portalConfig: McpPortalConfig): ProfilePolicyMaps {\n\tconst enabledNamespacesByAgent: Record<string, readonly string[]> = {};\n\tconst enabledToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst hiddenToolsByAgent: Record<string, readonly PortalToolSelector[]> = {};\n\tconst profileTtls: number[] = [];\n\n\tfor (const [agentId, agent] of Object.entries(portalConfig.agents)) {\n\t\tconst profile: ResolvedMcpPortalProfile = resolveMcpPortalProfile(portalConfig, agent.profile);\n\t\tenabledNamespacesByAgent[agentId] = profile.enabledNamespaces;\n\t\tenabledToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.enabledToolsByNamespace);\n\t\thiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);\n\t\tprofileTtls.push(profile.cache.catalogTtlMs);\n\t}\n\n\treturn {\n\t\tcacheTtlMs: profileTtls.length === 0 ? 60_000 : Math.min(...profileTtls),\n\t\tenabledNamespacesByAgent,\n\t\tenabledToolsByAgent,\n\t\thiddenToolsByAgent,\n\t};\n}\n\nasync function resolveManagedPortalSecret(secret: SecretValue): Promise<string> {\n\tif (secret.source !== 'environment') {\n\t\tthrow new Error(\n\t\t\t'MCP Portal managed OpenClaw effective config must use environment secret refs.',\n\t\t);\n\t}\n\tconst value = process.env[secret.name];\n\tif (value === undefined || value.length === 0) {\n\t\tthrow new Error(`Missing environment secret ${secret.name} for MCP Portal native plugin.`);\n\t}\n\treturn value;\n}\n\nasync function createManagedPortalCore(configDir: string): Promise<PortalCore> {\n\tconst effectiveConfigPaths = await resolveEffectiveConfigPaths(configDir);\n\tconst [mcpConfig, portalConfig] = await Promise.all([\n\t\tloadMcpConfig(effectiveConfigPaths.mcpConfigPath),\n\t\tloadMcpPortalConfig(effectiveConfigPaths.portalConfigPath),\n\t]);\n\tconst upstreamServers = await resolveUpstreamServers({\n\t\tconfig: mcpConfig,\n\t\tresolveSecret: resolveManagedPortalSecret,\n\t});\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\n\treturn createPortalCore({\n\t\taccessPolicy: {\n\t\t\tdefaultPolicy: 'deny-all',\n\t\t\tenabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,\n\t\t\tenabledToolsByAgent: profilePolicyMaps.enabledToolsByAgent,\n\t\t\thiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent,\n\t\t},\n\t\tapprovalTrustBoundary: 'openclaw-before-tool-call-hook',\n\t\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: {\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tcloseAgentScope: upstreamRuntime.closeAgentScope,\n\t\t\tcloseSession: upstreamRuntime.closeSession,\n\t\t\tlistTools: upstreamRuntime.listTools,\n\t\t},\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n}\n\nfunction portalUpdateFromCoreEvent(event: PortalCoreEvent): Record<string, unknown> | null {\n\tif (event.kind === 'progress') {\n\t\treturn {\n\t\t\tmessage: event.message ?? 'MCP Portal progress',\n\t\t\t...(event.progress !== undefined ? { progress: event.progress } : {}),\n\t\t\trequestId: event.requestId,\n\t\t\t...(event.total !== undefined ? { total: event.total } : {}),\n\t\t\ttype: 'mcp_portal_progress',\n\t\t};\n\t}\n\tif (event.kind === 'partial_content') {\n\t\treturn {\n\t\t\tcontent: event.content,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_partial_content',\n\t\t};\n\t}\n\tif (event.kind === 'upstream_notification') {\n\t\treturn {\n\t\t\tmethod: event.method,\n\t\t\tparams: event.params,\n\t\t\trequestId: event.requestId,\n\t\t\ttype: 'mcp_portal_upstream_notification',\n\t\t};\n\t}\n\treturn null;\n}\n\nasync function forwardCoreEvent(\n\tevent: PortalCoreEvent,\n\tlogger: ReturnType<typeof createLoggerAdapter>,\n\tonUpdate: OpenClawToolUpdateCallback | undefined,\n): Promise<void> {\n\tconst update = portalUpdateFromCoreEvent(event);\n\tif (update !== null) {\n\t\ttry {\n\t\t\tawait onUpdate?.(update);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tlogger.warn(`[mcp-portal] OpenClaw onUpdate delivery failed: ${message}`);\n\t\t}\n\t}\n}\n\nfunction createNativeTool(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly descriptor: PortalCoreToolDescriptor;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly logger: ReturnType<typeof createLoggerAdapter>;\n}): OpenClawToolRegistration {\n\treturn {\n\t\tdescription: props.descriptor.description,\n\t\texecute: async (_toolCallId, params, signal, onUpdate) => {\n\t\t\tif (props.context.agentId === undefined || props.context.agentId.length === 0) {\n\t\t\t\tthrow new Error('mcp-portal: OpenClaw did not provide a trusted agentId.');\n\t\t\t}\n\t\t\tconst core = await props.getCore();\n\t\t\tconst scope = core.createAgentScope({\n\t\t\t\tagentId: props.context.agentId,\n\t\t\t\tagentScopeId: props.context.agentId,\n\t\t\t\t...(props.context.sessionId ? { sessionId: props.context.sessionId } : {}),\n\t\t\t\t...(props.context.sessionKey ? { sessionKey: props.context.sessionKey } : {}),\n\t\t\t\tsource: 'openclaw-trusted',\n\t\t\t});\n\t\t\tconst result = await core.collectPortalCoreResult(\n\t\t\t\tcore.callStream({\n\t\t\t\t\tinput: params,\n\t\t\t\t\tscope,\n\t\t\t\t\t...(signal !== undefined ? { signal } : {}),\n\t\t\t\t\ttoolName: props.descriptor.name,\n\t\t\t\t}),\n\t\t\t\t{ onEvent: (event) => forwardCoreEvent(event, props.logger, onUpdate) },\n\t\t\t);\n\t\t\treturn { content: JSON.stringify(result), details: result };\n\t\t},\n\t\tlabel: props.descriptor.name,\n\t\tname: props.descriptor.name,\n\t\tparameters: props.descriptor.inputSchema,\n\t};\n}\n\nfunction descriptorsForOpenClawContext(props: {\n\treadonly context: OpenClawPluginToolContext;\n\treadonly portalConfig: McpPortalConfig | null;\n}): readonly PortalCoreToolDescriptor[] {\n\tif (props.portalConfig === null || props.context.agentId === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst agent = props.portalConfig.agents[props.context.agentId];\n\tif (agent === undefined) {\n\t\treturn listPortalCoreToolDescriptors();\n\t}\n\tconst profile = resolveMcpPortalProfile(props.portalConfig, agent.profile);\n\treturn listPortalCoreToolDescriptors(profile.enabledNamespaces);\n}\n\nfunction registerNativePortalTools(props: {\n\treadonly api: OpenClawPortalPluginApi;\n\treadonly getCore: () => Promise<PortalCore>;\n\treadonly runtimeState: ReturnType<typeof createPortalPluginRuntimeState>;\n}): void {\n\tconst descriptorNames = listPortalCoreToolDescriptors().map((descriptor) => descriptor.name);\n\tconst logger = createLoggerAdapter(props.api);\n\tprops.api.registerTool?.(\n\t\t(context) => {\n\t\t\tconst descriptors = descriptorsForOpenClawContext({\n\t\t\t\tcontext,\n\t\t\t\tportalConfig: props.runtimeState.getLoadedPortalConfig(),\n\t\t\t});\n\t\t\treturn descriptors.map((descriptor) =>\n\t\t\t\tcreateNativeTool({ context, descriptor, getCore: props.getCore, logger }),\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tnames: descriptorNames,\n\t\t\toptional: true,\n\t\t},\n\t);\n}\n\nfunction shouldRegisterPortalRuntimeHooks(api: OpenClawPortalPluginApi): boolean {\n\treturn api.registrationMode === undefined || api.registrationMode === 'full';\n}\n\nfunction formatRegistrationMode(api: OpenClawPortalPluginApi): string {\n\treturn api.registrationMode ?? 'full';\n}\n\nexport function registerMcpPortalPlugin(api: OpenClawPortalPluginApi): void {\n\tconst logger = createLoggerAdapter(api);\n\tconst registerRuntimeHooks = shouldRegisterPortalRuntimeHooks(api);\n\tif (registerRuntimeHooks) {\n\t\tvalidatePortalPluginApi(api);\n\t} else if (!hasFunction(api.registerTool)) {\n\t\tlogger.warn(\n\t\t\t`[mcp-portal] skipped native portal tool registration for registrationMode='${formatRegistrationMode(api)}' because OpenClaw did not expose registerTool.`,\n\t\t);\n\t\treturn;\n\t}\n\tconst configDir = resolveConfigDir(api);\n\tconst runtimeState = createPortalPluginRuntimeState({ configDir });\n\tlet corePromise: Promise<PortalCore> | undefined;\n\tconst getCore = (): Promise<PortalCore> => {\n\t\tcorePromise ??= createManagedPortalCore(configDir).catch((error: unknown) => {\n\t\t\tcorePromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t\treturn corePromise;\n\t};\n\tregisterNativePortalTools({ api, getCore, runtimeState });\n\n\tif (!registerRuntimeHooks) {\n\t\tlogger.info(\n\t\t\t`[mcp-portal] registered native portal tools for registrationMode='${formatRegistrationMode(api)}'.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tapi.on?.('before_tool_call', createBeforeToolCallHandler({ logger, runtimeState }), {\n\t\tpriority: 80,\n\t});\n\n\tapi.on?.('before_prompt_build', createBeforePromptBuildHandler({ runtimeState }), {\n\t\tpriority: 80,\n\t});\n\n\tif (!api.on && api.registerPromptHook) {\n\t\tapi.registerPromptHook('before_prompt_build', async (context) => {\n\t\t\tconst handler = createBeforePromptBuildHandler({ runtimeState });\n\t\t\tconst result = await handler({}, context);\n\t\t\tif (result?.appendSystemContext !== undefined) {\n\t\t\t\tcontext.appendPrompt?.(result.appendSystemContext);\n\t\t\t}\n\t\t});\n\t}\n\n\tregisterPortalRuntimeCleanup(api, async () => {\n\t\tconst core = await corePromise?.catch(() => undefined);\n\t\tawait core?.close();\n\t});\n\tlogger.info('[mcp-portal] registered native portal tools and runtime hooks.');\n}\n\nconst pluginEntry = {\n\tdescription: 'Registers native OpenClaw MCP Portal tools and wires per-agent approval hooks.',\n\tid: pluginId,\n\tname: 'MCP Portal',\n\tregister: registerMcpPortalPlugin,\n} satisfies PortalPluginEntry;\n\nexport default pluginEntry;\n","export interface PortalPromptNamespaceSummary {\n\treadonly namespace: string;\n\treadonly toolCount: number;\n}\n\nexport interface PortalPromptDiagnostic {\n\treadonly 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 native OpenClaw tools.',\n\t\t'Use mcp_portal_list with requests[], mcp_portal_search with requests[],',\n\t\t'mcp_portal_describe with requests[], and mcp_portal_call with calls[].',\n\t\t'Responses are { ok, results, errors, diagnostics }; results is keyed by each request/call id and each value is discriminated by ok: true or ok: false.',\n\t\t'Call upstream tools by namespace + toolName inside calls[].',\n\t\t'Call mcp_portal_describe before mcp_portal_call unless you already saw the full schema for that tool in this portal session.',\n\t\t'Gateway owns MCP auth.',\n\t\t`Namespaces: ${namespaceList}`,\n\t\t...diagnostics,\n\t].join('\\n');\n}\n","import { redactCredentialText } from '@agent-vm/mcp-portal/core';\n\nexport function redactPortalSecrets(text: string, secretValues: readonly string[] = []): string {\n\treturn secretValues\n\t\t.filter((secretValue) => secretValue.length > 0)\n\t\t.reduce(\n\t\t\t(current, secretValue) => current.split(secretValue).join('[REDACTED]'),\n\t\t\tredactCredentialText(text),\n\t\t);\n}\n","export * from './openclaw-plugin-api.js';\nexport * from './plugin-registration.js';\nexport * from './before-prompt-build-handler.js';\nexport * from './before-tool-call-handler.js';\nexport * from './portal-config.js';\nexport * from './portal-plugin-runtime-state.js';\nexport * from './portal-tool-policy.js';\nexport * from './portal-prompt-context.js';\nexport * from './redaction.js';\nexport { default } from './plugin-registration.js';\n\nexport const OPENCLAW_MCP_PORTAL_PLUGIN_PACKAGE_NAME = '@agent-vm/openclaw-mcp-portal-plugin';\n"],"mappings":";;;;;;AAaA,SAAgB,+BACf,OAIkD;CAClD,OAAO,OAAO,QAAQ,YAAY;EACjC,MAAM,UAAU,QAAQ;EACxB,IAAI,YAAY,KAAA,GACf;EAED,MAAM,eAAe,MAAM,MAAM,aAAa,kBAAkB;EAChE,MAAM,QAAQ,aAAa,OAAO;EAClC,IAAI,UAAU,KAAA,GACb;EAED,MAAM,UAAU,wBAAwB,cAAc,MAAM,QAAQ;EACpE,IAAI,CAAC,QAAQ,cAAc,SAC1B;EAED,MAAM,aAAa,QAAQ,kBACzB,UAAU,CACV,MAAM,GAAG,QAAQ,cAAc,cAAc;EAK/C,OAAO,EACN,qBAAqB;GACpB;GALD,WAAW,WAAW,IACnB,6BACA,WAAW,KAAK,SAAS,KAAK,OAAO,CAAC,KAAK,KAAK;GAKlD;GACA,CAAC,KAAK,KAAK,EACZ;;;;;AClCH,SAAgB,wBACf,SACA,MACU;CACV,IAAI,CAAC,QAAQ,kBAAkB,SAAS,KAAK,UAAU,EACtD,OAAO;CAER,MAAM,eAAe,QAAQ,wBAAwB,KAAK,cAAc,EAAE;CAC1E,IAAI,aAAa,SAAS,KAAK,CAAC,aAAa,SAAS,KAAK,SAAS,EACnE,OAAO;CAGR,OAAO,EADa,QAAQ,uBAAuB,KAAK,cAAc,EAAE,EACpD,SAAS,KAAK,SAAS;;AAG5C,SAAgB,8BACf,SACA,MACU;CACV,OAAO,8BAA8B,SAAS,KAAK;;;;ACVpD,SAASA,iBAAe,OAAkD;CACzE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,iBAAiB,OAA0C;CACnE,IAAI,CAACA,iBAAe,MAAM,EACzB,OAAO;CAER,MAAM,KAAK,MAAM;CACjB,MAAM,YAAY,MAAM;CACxB,MAAM,WAAW,MAAM;CACvB,MAAM,iBAAiB,MAAM;CAC7B,IACC,OAAO,OAAO,YACd,OAAO,cAAc,YACrB,OAAO,aAAa,YACpB,CAACA,iBAAe,eAAe,EAE/B,OAAO;CAER,OAAO;EAAE,WAAW;EAAgB;EAAI;EAAW;EAAU;;AAG9D,SAAS,kBAAkB,QAAsE;CAChG,MAAM,QAAQ,OAAO;CACrB,IAAI,CAAC,MAAM,QAAQ,MAAM,EACxB,OAAO;CAER,MAAM,cAAmC,EAAE;CAC3C,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,aAAa,iBAAiB,KAAK;EACzC,IAAI,eAAe,MAClB,OAAO;EAER,YAAY,KAAK,WAAW;;CAE7B,OAAO;;AAGR,SAAgB,4BACf,OAIsD;CACtD,OAAO,OAAO,OAAO,YAAY;EAChC,IAAI,MAAM,aAAa,mBACtB;EAED,IAAI,QAAQ,YAAY,KAAA,GACvB,OAAO;GACN,OAAO;GACP,aAAa,kDAAkD,MAAM,SAAS;GAC9E;EAEF,MAAM,eAAe,MAAM,MAAM,aAAa,kBAAkB;EAChE,MAAM,UAAU,QAAQ;EACxB,MAAM,QAAQ,aAAa,OAAO;EAClC,IAAI,UAAU,KAAA,GACb,OAAO;GAAE,OAAO;GAAM,aAAa,sBAAsB,QAAQ;GAAuB;EAEzF,MAAM,UAAU,wBAAwB,cAAc,MAAM,QAAQ;EACpE,MAAM,QAAQ,kBAAkB,MAAM,OAAO;EAC7C,IAAI,UAAU,QAAQ,MAAM,WAAW,GACtC,OAAO;GAAE,OAAO;GAAM,aAAa;GAA4C;EAGhF,KAAK,MAAM,QAAQ,OAClB,IAAI,CAAC,wBAAwB,SAAS,KAAK,EAC1C,OAAO;GACN,OAAO;GACP,aAAa,WAAW,QAAQ,GAAG,KAAK,UAAU,GAAG,KAAK,SAAS;GACnE;EAIH,MAAM,gBAAgB,MAAM,QAAQ,SAAS,8BAA8B,SAAS,KAAK,CAAC;EAC1F,IAAI,cAAc,WAAW,GAC5B;EAGD,MAAM,YAAY,cAChB,KAAK,SAAS,GAAG,KAAK,UAAU,GAAG,KAAK,WAAW,CACnD,UAAU,CACV,KAAK,KAAK;EACZ,OAAO,EACN,iBAAiB;GAChB,aAAa,oCAAoC,QAAQ,IAAI,UAAU;GACvE,UAAU;GACV,UAAU;GACV,iBAAiB;GACjB,WAAW;GACX,OAAO,qBAAqB;GAC5B,EACD;;;;;AChHH,MAAM,kCAAkC;AAOxC,SAASC,iBAAe,OAA4D;CACnF,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,uBAAuB,OAAwB;CACvD,OAAO,MAAM,SAAS,KAAK,CAAC,MAAM,SAAS,IAAI,IAAI,CAAC,MAAM,SAAS,KAAK;;AAGzE,SAAS,6BAA6B,OAGpC;CACD,IAAI,CAACA,iBAAe,MAAM,EACzB,MAAM,IAAI,MAAM,0DAA0D;CAE3E,IAAI,MAAM,kBAAkB,GAC3B,MAAM,IAAI,MAAM,iEAAiE;CAElF,IAAI,OAAO,MAAM,kBAAkB,YAAY,CAAC,uBAAuB,MAAM,cAAc,EAC1F,MAAM,IAAI,MAAM,0EAA0E;CAE3F,IACC,OAAO,MAAM,qBAAqB,YAClC,CAAC,uBAAuB,MAAM,iBAAiB,EAE/C,MAAM,IAAI,MAAM,6EAA6E;CAE9F,OAAO;EACN,eAAe,MAAM;EACrB,kBAAkB,MAAM;EACxB;;AAGF,SAAS,mBAAmB,OAAyB;CACpD,OACCA,iBAAe,MAAM,IACrB,OAAO,MAAM,SAAS,aACrB,MAAM,SAAS,YAAY,MAAM,SAAS;;AAI7C,eAAsB,4BACrB,WACgC;CAChC,MAAM,eAAe,KAAK,WAAW,gCAAgC;CACrE,IAAI;CACJ,IAAI;EACH,eAAe,MAAM,SAAS,cAAc,OAAO;UAC3C,OAAO;EACf,IAAI,mBAAmB,MAAM,EAC5B,OAAO;GACN,eAAe,KAAK,WAAW,mBAAmB;GAClD,kBAAkB,KAAK,WAAW,0BAA0B;GAC5D;EAEF,MAAM;;CAEP,MAAM,WAAW,6BAA6B,KAAK,MAAM,aAAa,CAAC;CACvE,OAAO;EACN,eAAe,KAAK,WAAW,SAAS,cAAc;EACtD,kBAAkB,KAAK,WAAW,SAAS,iBAAiB;EAC5D;;;;ACrEF,MAAa,2BAA2B,EACtC,OAAO,EACP,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE,EAC5B,CAAC,CACD,QAAQ;AAIV,SAAgB,kBAAkB,OAAoC;CACrE,OAAO,yBAAyB,MAAM,SAAS,EAAE,CAAC;;;;ACEnD,SAAgB,+BAA+B,OAGlB;CAC5B,IAAI,qBAA6C;CACjD,IAAI,sBAAuD;CAC3D,IAAI,0BAAyC;CAC7C,MAAM,uBAAuB,MAAM,oBAAoB;CAEvD,SAAS,mBAA6C;EACrD,IAAI,wBAAwB,MAC3B,OAAO;EAER,MAAM,cAAc,4BAA4B,MAAM,UAAU,CAC9D,MAAM,yBAAyB,qBAAqB,qBAAqB,iBAAiB,CAAC,CAC3F,MAAM,iBAAiB;GACvB,qBAAqB;GACrB,OAAO;IACN,CACD,OAAO,UAAmB;GAC1B,IAAI,wBAAwB,aAC3B,sBAAsB;GAEvB,MAAM;IACL;EACH,sBAAsB;EACtB,OAAO;;CAGR,OAAO;EACN,WAAW,MAAM;EACjB,6BAA6B;EAC7B,kCAAkC;EAClC;EACA,2BAA2B;GAC1B,0BAA0B;;EAE3B,wBAAwB,WAAW;GAClC,0BAA0B;;EAE3B;;;;ACHF,MAAM,WAAW;AAEjB,SAAS,YAAY,OAAmE;CACvF,OAAO,OAAO,UAAU;;AAGzB,SAAS,eAAe,OAA4D;CACnF,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,eAAe,OAA6C;CACpE,OAAO,MAAM,QAAQ,MAAM;;AAG5B,SAAS,kBAAkB,OAAgB,UAA2B;CACrE,OAAO,eAAe,MAAM,GAAG,MAAM,YAAY,KAAA;;AAGlD,SAAS,iBAAiB,KAAsC;CAC/D,IAAI,IAAI,iBAAiB,KAAA,GACxB,OAAO,kBAAkB,IAAI,aAAa,CAAC;CAI5C,MAAM,uBAAuB,kBAC5B,kBAAkB,IAAI,QAAQ,YAAY,EAC1C,YACA;CACD,IAAI,OAAO,yBAAyB,YAAY,qBAAqB,SAAS,GAC7E,OAAO;CAER,MAAM,QAAQ,kBAAkB,IAAI,QAAQ,QAAQ;CACpD,IAAI,eAAe,MAAM,EAAE;EAE1B,MAAM,mBAAmB,kBACxB,kBAFiB,MAAM,GAAG,EAEC,EAAE,YAAY,EACzC,YACA;EACD,IAAI,OAAO,qBAAqB,YAAY,iBAAiB,SAAS,GACrE,OAAO;;CAGT,MAAM,IAAI,MACT,kFACA;;AAGF,SAAgB,iCAAiC,OAGxC;CACR,IAAI,MAAM,YAAY,MACrB;CAED,MAAM,mBAAmB,MAAM,QAAQ;CACvC,MAAM,2BAA2B,MAAM,QAAQ,WAAW,MAAM,QAAQ;CACxE,IAAI,MAAM,QAAQ,oBAAoB,MAAM,OAAO,0BAClD,MAAM,IAAI,MACT,mBAAmB,OAAO,MAAM,KAAK,CAAC,kCACjC,OAAO,iBAAiB,CAAC,IAAI,OAAO,yBAAyB,CAAC,IACnE;;AAIH,SAAS,oBAAoB,KAI3B;CACD,OAAO;EACN,QAAQ,YAAY,IAAI,QAAQ,QAAQ,QAAQ;EAChD,OAAO,YAAY,IAAI,QAAQ,OAAO,QAAQ;EAC9C,OAAO,YAAY,IAAI,QAAQ,OAAO,QAAQ;EAC9C;;AAGF,SAAgB,wBAAwB,KAAoC;CAC3E,IAAI,CAAC,YAAY,IAAI,aAAa,EACjC,MAAM,IAAI,MAAM,wDAAwD;CAEzE,IAAI,CAAC,YAAY,IAAI,GAAG,EACvB,MAAM,IAAI,MAAM,iEAAiE;CAKlF,IAFC,YAAY,IAAI,WAAW,yBAAyB,IACpD,YAAY,IAAI,yBAAyB,EAEzC;CAED,MAAM,IAAI,MAAM,gEAAgE;;AAGjF,SAAS,6BACR,KACA,SACO;CACP,MAAM,mBAAmB;EACxB,SAAS,YAAY;GACpB,MAAM,SAAS;;EAEhB,aAAa;EACb,IAAI;EACJ;CACD,IAAI,YAAY,IAAI,WAAW,yBAAyB,EAAE;EACzD,IAAI,UAAU,yBAAyB,iBAAiB;EACxD;;CAED,IAAI,YAAY,IAAI,yBAAyB,EAAE;EAC9C,IAAI,yBAAyB,iBAAiB;EAC9C;;CAED,MAAM,IAAI,MAAM,gEAAgE;;AAGjF,SAAS,4BACR,gBACgC;CAChC,OAAO,OAAO,QAAQ,eAAe,CAAC,SAAS,CAAC,WAAW,eAC1D,UAAU,KAAK,cAAc;EAAE;EAAW;EAAU,EAAE,CACtD;;AAGF,SAAS,uBAAuB,cAAkD;CACjF,MAAM,2BAA8D,EAAE;CACtE,MAAM,sBAAqE,EAAE;CAC7E,MAAM,qBAAoE,EAAE;CAC5E,MAAM,cAAwB,EAAE;CAEhC,KAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,aAAa,OAAO,EAAE;EACnE,MAAM,UAAoC,wBAAwB,cAAc,MAAM,QAAQ;EAC9F,yBAAyB,WAAW,QAAQ;EAC5C,oBAAoB,WAAW,4BAA4B,QAAQ,wBAAwB;EAC3F,mBAAmB,WAAW,4BAA4B,QAAQ,uBAAuB;EACzF,YAAY,KAAK,QAAQ,MAAM,aAAa;;CAG7C,OAAO;EACN,YAAY,YAAY,WAAW,IAAI,MAAS,KAAK,IAAI,GAAG,YAAY;EACxE;EACA;EACA;EACA;;AAGF,eAAe,2BAA2B,QAAsC;CAC/E,IAAI,OAAO,WAAW,eACrB,MAAM,IAAI,MACT,iFACA;CAEF,MAAM,QAAQ,QAAQ,IAAI,OAAO;CACjC,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,GAC3C,MAAM,IAAI,MAAM,8BAA8B,OAAO,KAAK,gCAAgC;CAE3F,OAAO;;AAGR,eAAe,wBAAwB,WAAwC;CAC9E,MAAM,uBAAuB,MAAM,4BAA4B,UAAU;CACzE,MAAM,CAAC,WAAW,gBAAgB,MAAM,QAAQ,IAAI,CACnD,cAAc,qBAAqB,cAAc,EACjD,oBAAoB,qBAAqB,iBAAiB,CAC1D,CAAC;CACF,MAAM,kBAAkB,MAAM,uBAAuB;EACpD,QAAQ;EACR,eAAe;EACf,CAAC;CACF,MAAM,kBAAkB,+BAA+B,EAAE,SAAS,iBAAiB,CAAC;CACpF,MAAM,oBAAoB,uBAAuB,aAAa;CAE9D,OAAO,iBAAiB;EACvB,cAAc;GACb,eAAe;GACf,0BAA0B,kBAAkB;GAC5C,qBAAqB,kBAAkB;GACvC,oBAAoB,kBAAkB;GACtC;EACD,uBAAuB;EACvB,cAAc,kBAAkB;EAChC,SAAS;GACR,kBAAkB,gBAAgB;GAClC,iBAAiB,gBAAgB;GACjC,cAAc,gBAAgB;GAC9B,WAAW,gBAAgB;GAC3B;EACD,oBAAoB,gBAAgB,KAAK,WAAW,OAAO,UAAU;EACrE,CAAC;;AAGH,SAAS,0BAA0B,OAAwD;CAC1F,IAAI,MAAM,SAAS,YAClB,OAAO;EACN,SAAS,MAAM,WAAW;EAC1B,GAAI,MAAM,aAAa,KAAA,IAAY,EAAE,UAAU,MAAM,UAAU,GAAG,EAAE;EACpE,WAAW,MAAM;EACjB,GAAI,MAAM,UAAU,KAAA,IAAY,EAAE,OAAO,MAAM,OAAO,GAAG,EAAE;EAC3D,MAAM;EACN;CAEF,IAAI,MAAM,SAAS,mBAClB,OAAO;EACN,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,MAAM;EACN;CAEF,IAAI,MAAM,SAAS,yBAClB,OAAO;EACN,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,WAAW,MAAM;EACjB,MAAM;EACN;CAEF,OAAO;;AAGR,eAAe,iBACd,OACA,QACA,UACgB;CAChB,MAAM,SAAS,0BAA0B,MAAM;CAC/C,IAAI,WAAW,MACd,IAAI;EACH,MAAM,WAAW,OAAO;UAChB,OAAO;EACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EACtE,OAAO,KAAK,mDAAmD,UAAU;;;AAK5E,SAAS,iBAAiB,OAKG;CAC5B,OAAO;EACN,aAAa,MAAM,WAAW;EAC9B,SAAS,OAAO,aAAa,QAAQ,QAAQ,aAAa;GACzD,IAAI,MAAM,QAAQ,YAAY,KAAA,KAAa,MAAM,QAAQ,QAAQ,WAAW,GAC3E,MAAM,IAAI,MAAM,0DAA0D;GAE3E,MAAM,OAAO,MAAM,MAAM,SAAS;GAClC,MAAM,QAAQ,KAAK,iBAAiB;IACnC,SAAS,MAAM,QAAQ;IACvB,cAAc,MAAM,QAAQ;IAC5B,GAAI,MAAM,QAAQ,YAAY,EAAE,WAAW,MAAM,QAAQ,WAAW,GAAG,EAAE;IACzE,GAAI,MAAM,QAAQ,aAAa,EAAE,YAAY,MAAM,QAAQ,YAAY,GAAG,EAAE;IAC5E,QAAQ;IACR,CAAC;GACF,MAAM,SAAS,MAAM,KAAK,wBACzB,KAAK,WAAW;IACf,OAAO;IACP;IACA,GAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,GAAG,EAAE;IAC1C,UAAU,MAAM,WAAW;IAC3B,CAAC,EACF,EAAE,UAAU,UAAU,iBAAiB,OAAO,MAAM,QAAQ,SAAS,EAAE,CACvE;GACD,OAAO;IAAE,SAAS,KAAK,UAAU,OAAO;IAAE,SAAS;IAAQ;;EAE5D,OAAO,MAAM,WAAW;EACxB,MAAM,MAAM,WAAW;EACvB,YAAY,MAAM,WAAW;EAC7B;;AAGF,SAAS,8BAA8B,OAGC;CACvC,IAAI,MAAM,iBAAiB,QAAQ,MAAM,QAAQ,YAAY,KAAA,GAC5D,OAAO,+BAA+B;CAEvC,MAAM,QAAQ,MAAM,aAAa,OAAO,MAAM,QAAQ;CACtD,IAAI,UAAU,KAAA,GACb,OAAO,+BAA+B;CAGvC,OAAO,8BADS,wBAAwB,MAAM,cAAc,MAAM,QACtB,CAAC,kBAAkB;;AAGhE,SAAS,0BAA0B,OAI1B;CACR,MAAM,kBAAkB,+BAA+B,CAAC,KAAK,eAAe,WAAW,KAAK;CAC5F,MAAM,SAAS,oBAAoB,MAAM,IAAI;CAC7C,MAAM,IAAI,gBACR,YAAY;EAKZ,OAJoB,8BAA8B;GACjD;GACA,cAAc,MAAM,aAAa,uBAAuB;GACxD,CACiB,CAAC,KAAK,eACvB,iBAAiB;GAAE;GAAS;GAAY,SAAS,MAAM;GAAS;GAAQ,CAAC,CACzE;IAEF;EACC,OAAO;EACP,UAAU;EACV,CACD;;AAGF,SAAS,iCAAiC,KAAuC;CAChF,OAAO,IAAI,qBAAqB,KAAA,KAAa,IAAI,qBAAqB;;AAGvE,SAAS,uBAAuB,KAAsC;CACrE,OAAO,IAAI,oBAAoB;;AAGhC,SAAgB,wBAAwB,KAAoC;CAC3E,MAAM,SAAS,oBAAoB,IAAI;CACvC,MAAM,uBAAuB,iCAAiC,IAAI;CAClE,IAAI,sBACH,wBAAwB,IAAI;MACtB,IAAI,CAAC,YAAY,IAAI,aAAa,EAAE;EAC1C,OAAO,KACN,8EAA8E,uBAAuB,IAAI,CAAC,iDAC1G;EACD;;CAED,MAAM,YAAY,iBAAiB,IAAI;CACvC,MAAM,eAAe,+BAA+B,EAAE,WAAW,CAAC;CAClE,IAAI;CACJ,MAAM,gBAAqC;EAC1C,gBAAgB,wBAAwB,UAAU,CAAC,OAAO,UAAmB;GAC5E,cAAc,KAAA;GACd,MAAM;IACL;EACF,OAAO;;CAER,0BAA0B;EAAE;EAAK;EAAS;EAAc,CAAC;CAEzD,IAAI,CAAC,sBAAsB;EAC1B,OAAO,KACN,qEAAqE,uBAAuB,IAAI,CAAC,IACjG;EACD;;CAGD,IAAI,KAAK,oBAAoB,4BAA4B;EAAE;EAAQ;EAAc,CAAC,EAAE,EACnF,UAAU,IACV,CAAC;CAEF,IAAI,KAAK,uBAAuB,+BAA+B,EAAE,cAAc,CAAC,EAAE,EACjF,UAAU,IACV,CAAC;CAEF,IAAI,CAAC,IAAI,MAAM,IAAI,oBAClB,IAAI,mBAAmB,uBAAuB,OAAO,YAAY;EAEhE,MAAM,SAAS,MADC,+BAA+B,EAAE,cAAc,CACnC,CAAC,EAAE,EAAE,QAAQ;EACzC,IAAI,QAAQ,wBAAwB,KAAA,GACnC,QAAQ,eAAe,OAAO,oBAAoB;GAElD;CAGH,6BAA6B,KAAK,YAAY;EAE7C,OAAM,MADa,aAAa,YAAY,KAAA,EAAU,GAC1C,OAAO;GAClB;CACF,OAAO,KAAK,iEAAiE;;AAG9E,MAAM,cAAc;CACnB,aAAa;CACb,IAAI;CACJ,MAAM;CACN,UAAU;CACV;;;ACjaD,SAAgB,0BAA0B,OAG/B;CACV,MAAM,gBACL,MAAM,WAAW,SAAS,IACvB,MAAM,WAAW,KAAK,UAAU,GAAG,MAAM,UAAU,GAAG,MAAM,UAAU,SAAS,CAAC,KAAK,KAAK,GAC1F;CACJ,MAAM,cACL,MAAM,gBAAgB,KAAA,KAAa,MAAM,YAAY,SAAS,IAC3D,CACA,0BAA0B,MAAM,YAC9B,KAAK,UAAU,GAAG,MAAM,UAAU,IAAI,MAAM,UAAU,CACtD,KAAK,KAAK,GACZ,GACA,EAAE;CAEN,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,GAAG;EACH,CAAC,KAAK,KAAK;;;;ACnCb,SAAgB,oBAAoB,MAAc,eAAkC,EAAE,EAAU;CAC/F,OAAO,aACL,QAAQ,gBAAgB,YAAY,SAAS,EAAE,CAC/C,QACC,SAAS,gBAAgB,QAAQ,MAAM,YAAY,CAAC,KAAK,aAAa,EACvE,qBAAqB,KAAK,CAC1B;;;;ACGH,MAAa,0CAA0C"}
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "mcp-portal",
3
+ "name": "MCP Portal",
4
+ "description": "Native OpenClaw MCP Portal tool adapter over configured upstream MCP servers.",
5
+ "activation": {
6
+ "onStartup": true
7
+ },
8
+ "contracts": {
9
+ "tools": ["mcp_portal_list", "mcp_portal_search", "mcp_portal_describe", "mcp_portal_call"]
10
+ },
11
+ "toolMetadata": {
12
+ "mcp_portal_list": { "optional": true },
13
+ "mcp_portal_search": { "optional": true },
14
+ "mcp_portal_describe": { "optional": true },
15
+ "mcp_portal_call": { "optional": true }
16
+ },
17
+ "configSchema": {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "properties": {
21
+ "configDir": { "type": "string" }
22
+ }
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-vm/openclaw-mcp-portal-plugin",
3
- "version": "0.0.72",
3
+ "version": "0.0.74",
4
4
  "description": "OpenClaw plugin that registers native MCP Portal tools over configured upstream MCP servers.",
5
5
  "homepage": "https://github.com/ShravanSunder/agent-vm#readme",
6
6
  "bugs": {
@@ -14,7 +14,8 @@
14
14
  "directory": "packages/openclaw-mcp-portal-plugin"
15
15
  },
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "openclaw.plugin.json"
18
19
  ],
19
20
  "type": "module",
20
21
  "main": "./dist/index.js",
@@ -30,8 +31,8 @@
30
31
  },
31
32
  "dependencies": {
32
33
  "zod": "^4.4.3",
33
- "@agent-vm/config-contracts": "0.0.72",
34
- "@agent-vm/mcp-portal": "0.0.72"
34
+ "@agent-vm/mcp-portal": "0.0.74",
35
+ "@agent-vm/config-contracts": "0.0.74"
35
36
  },
36
37
  "devDependencies": {
37
38
  "openclaw": "^2026.5.7",