@agent-vm/mcp-portal 0.0.65 → 0.0.66

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.
@@ -49,6 +49,7 @@ declare function startPortalServer(props: StartPortalServerProps): Promise<{
49
49
  readonly close: () => Promise<void>;
50
50
  readonly port: number;
51
51
  }>;
52
+ declare function isPortalServerEntrypoint(importMetaUrl: string, argvEntryPath: string | undefined, realpathFn?: (targetPath: string) => Promise<string>): Promise<boolean>;
52
53
  //#endregion
53
- export { DeferredPort, PortalServerCliArgs, PortalServerLogEvent, PortalServerLogger, StartPortalServerProps, applyAgentOverrides, handlePortalServerError, parsePortalServerCliArgs, startPortalServer };
54
+ export { DeferredPort, PortalServerCliArgs, PortalServerLogEvent, PortalServerLogger, StartPortalServerProps, applyAgentOverrides, handlePortalServerError, isPortalServerEntrypoint, parsePortalServerCliArgs, startPortalServer };
54
55
  //# sourceMappingURL=portal-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"portal-server.d.ts","names":[],"sources":["../../src/bin/portal-server.ts"],"mappings":";;;;KAmCK,mBAAA,UAA6B,KAAA;AAAA,KAEtB,oBAAA;EAAA,SAEA,OAAA;EAAA,SACA,qBAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA;EAAA,SACA,aAAA;EAAA,SACA,eAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,KAAA;EAAA,SACA,KAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,UAGK,kBAAA;EAAA,SACP,GAAA,GAAM,KAAA,EAAO,oBAAA;AAAA;AAAA,UAGN,mBAAA;EAAA,SACP,cAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,sBAAA;EAAA,SACP,IAAA,EAAM,mBAAA;EAAA,SACN,GAAA,EAAK,QAAA,CAAS,MAAA;EAAA,SACd,MAAA,GAAS,kBAAA;EAAA,SACT,aAAA,IAAiB,MAAA,EAAQ,WAAA,KAAgB,OAAA;EAAA,SACzC,OAAA,GAAU,mBAAA;AAAA;AAAA,iBAoBJ,wBAAA,CAAyB,IAAA,sBAA0B,mBAAA;AAAA,iBAuBnD,mBAAA,CACf,MAAA,EAAQ,QAAA,CAAS,MAAA,SAAe,oBAAA,IAChC,SAAA,sBACE,QAAA,CAAS,MAAA,SAAe,oBAAA;AAAA,UAsBV,YAAA;EAAA,SACP,OAAA,EAAS,OAAA;EAAA,SACT,MAAA,GAAS,KAAA,EAAO,KAAA;EAAA,SAChB,OAAA,GAAU,IAAA;AAAA;AAAA,iBAmCJ,uBAAA,CAAwB,KAAA;EAAA,SAC9B,KAAA,EAAO,KAAA;EAAA,SACP,WAAA;EAAA,SACA,aAAA,EAAe,YAAA;EAAA,SACf,MAAA,EAAQ,kBAAA;AAAA;AAAA,iBAiHI,iBAAA,CACrB,KAAA,EAAO,sBAAA,GACL,OAAA;EAAA,SAAmB,KAAA,QAAa,OAAA;EAAA,SAAwB,IAAA;AAAA"}
1
+ {"version":3,"file":"portal-server.d.ts","names":[],"sources":["../../src/bin/portal-server.ts"],"mappings":";;;;KAqCK,mBAAA,UAA6B,KAAA;AAAA,KAEtB,oBAAA;EAAA,SAEA,OAAA;EAAA,SACA,qBAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA;EAAA,SACA,aAAA;EAAA,SACA,eAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,KAAA;EAAA,SACA,KAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,UAGK,kBAAA;EAAA,SACP,GAAA,GAAM,KAAA,EAAO,oBAAA;AAAA;AAAA,UAGN,mBAAA;EAAA,SACP,cAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,sBAAA;EAAA,SACP,IAAA,EAAM,mBAAA;EAAA,SACN,GAAA,EAAK,QAAA,CAAS,MAAA;EAAA,SACd,MAAA,GAAS,kBAAA;EAAA,SACT,aAAA,IAAiB,MAAA,EAAQ,WAAA,KAAgB,OAAA;EAAA,SACzC,OAAA,GAAU,mBAAA;AAAA;AAAA,iBAoBJ,wBAAA,CAAyB,IAAA,sBAA0B,mBAAA;AAAA,iBAuBnD,mBAAA,CACf,MAAA,EAAQ,QAAA,CAAS,MAAA,SAAe,oBAAA,IAChC,SAAA,sBACE,QAAA,CAAS,MAAA,SAAe,oBAAA;AAAA,UAsBV,YAAA;EAAA,SACP,OAAA,EAAS,OAAA;EAAA,SACT,MAAA,GAAS,KAAA,EAAO,KAAA;EAAA,SAChB,OAAA,GAAU,IAAA;AAAA;AAAA,iBAmCJ,uBAAA,CAAwB,KAAA;EAAA,SAC9B,KAAA,EAAO,KAAA;EAAA,SACP,WAAA;EAAA,SACA,aAAA,EAAe,YAAA;EAAA,SACf,MAAA,EAAQ,kBAAA;AAAA;AAAA,iBAiHI,iBAAA,CACrB,KAAA,EAAO,sBAAA,GACL,OAAA;EAAA,SAAmB,KAAA,QAAa,OAAA;EAAA,SAAwB,IAAA;AAAA;AAAA,iBAiHrC,wBAAA,CACrB,aAAA,UACA,aAAA,sBACA,UAAA,IAAa,UAAA,aAAuB,OAAA,WAClC,OAAA"}
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { f as createPortalAgentRuntimeRecords, g as createPortalHttpApp, h as resolveAgentHmacKeys, j as parseHmacKeysFromEnv, l as createPortalSessionManager, m as createPortalHttpAgentResolver, p as createPortalApprovalVerifier, t as createUpstreamMcpClientRuntime } from "../upstream-mcp-client-runtime-DiBCBsDj.js";
3
3
  import { loadMcpConfig, loadMcpPortalConfig, mcpConfigToResolvedProviders, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
4
+ import { realpath } from "node:fs/promises";
4
5
  import { join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { parseArgs, promisify } from "node:util";
6
8
  import { serve } from "@hono/node-server";
7
9
  import { execFile } from "node:child_process";
@@ -267,11 +269,21 @@ async function main() {
267
269
  shutdown();
268
270
  });
269
271
  }
270
- if (import.meta.url === `file://${process.argv[1]}`) main().catch((error) => {
272
+ async function isPortalServerEntrypoint(importMetaUrl, argvEntryPath, realpathFn = realpath) {
273
+ if (argvEntryPath === void 0) return false;
274
+ try {
275
+ const modulePath = fileURLToPath(importMetaUrl);
276
+ const [realModulePath, realArgvEntryPath] = await Promise.all([realpathFn(modulePath), realpathFn(argvEntryPath)]);
277
+ return realModulePath === realArgvEntryPath;
278
+ } catch {
279
+ return false;
280
+ }
281
+ }
282
+ if (await isPortalServerEntrypoint(import.meta.url, process.argv[1])) main().catch((error) => {
271
283
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
272
284
  process.exit(1);
273
285
  });
274
286
  //#endregion
275
- export { applyAgentOverrides, handlePortalServerError, parsePortalServerCliArgs, startPortalServer };
287
+ export { applyAgentOverrides, handlePortalServerError, isPortalServerEntrypoint, parsePortalServerCliArgs, startPortalServer };
276
288
 
277
289
  //# sourceMappingURL=portal-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"portal-server.js","names":[],"sources":["../../src/bin/secret-value-resolver.ts","../../src/bin/portal-server.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport type { SecretValue } from '@agent-vm/config-contracts';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ResolveSecretValueProps {\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly readOnePasswordSecret?: (ref: string) => Promise<string>;\n}\n\nexport async function resolveSecretValue(\n\tsecret: SecretValue,\n\tprops: ResolveSecretValueProps,\n): Promise<string> {\n\tif (secret.source === 'environment') {\n\t\tconst value = props.env[secret.name];\n\t\tif (value === undefined || value.length === 0) {\n\t\t\tthrow new Error(`Missing environment secret ${secret.name}.`);\n\t\t}\n\t\treturn value;\n\t}\n\n\tconst readOnePasswordSecret = props.readOnePasswordSecret ?? readOnePasswordCliSecret;\n\treturn await readOnePasswordSecret(secret.ref);\n}\n\nasync function readOnePasswordCliSecret(ref: string): Promise<string> {\n\tconst { stdout } = await execFileAsync('op', ['read', ref], { encoding: 'utf8' });\n\treturn stdout.trimEnd();\n}\n","#!/usr/bin/env node\nimport { join } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\tmcpConfigToResolvedProviders,\n\tresolveMcpPortalProfile,\n\ttype McpConfig,\n\ttype McpPortalAgentConfig,\n\ttype McpPortalConfig,\n\ttype ResolvedMcpProvider,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport { serve } from '@hono/node-server';\n\nimport { parseHmacKeysFromEnv } from '../auth/hmac-env.js';\nimport { createPortalHttpApp } from '../mcp-server/portal-http-server.js';\nimport {\n\tcreatePortalAgentRuntimeRecords,\n\tcreatePortalApprovalVerifier,\n\tcreatePortalHttpAgentResolver,\n\tresolveAgentHmacKeys,\n} from '../mcp-server/resolve-agent-identity.js';\nimport type { PortalToolSelector } from '../portal-access-policy.js';\nimport { createPortalSessionManager } from '../portal-session.js';\nimport {\n\tcreateUpstreamMcpClientRuntime,\n\ttype NormalizedUpstreamMcpServer,\n} from '../upstream-mcp-client-runtime.js';\nimport { resolveSecretValue } from './secret-value-resolver.js';\n\ntype PortalNodeServer = ReturnType<typeof serve>;\ntype PortalServeFunction = typeof serve;\n\nexport type PortalServerLogEvent =\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly conservativeCallCount: number;\n\t\t\treadonly event: 'conservative_approval_fallback';\n\t\t\treadonly level: 'warn';\n\t\t\treadonly primaryReason: string;\n\t\t\treadonly strictCallCount: number;\n\t\t\treadonly toolRefs: readonly string[];\n\t }\n\t| {\n\t\t\treadonly event: 'server_error';\n\t\t\treadonly level: 'error';\n\t\t\treadonly message: string;\n\t\t\treadonly stack?: string;\n\t };\n\nexport interface PortalServerLogger {\n\treadonly log: (event: PortalServerLogEvent) => void;\n}\n\nexport interface PortalServerCliArgs {\n\treadonly agentOverrides: readonly string[];\n\treadonly configDir: string;\n\treadonly port?: number;\n}\n\nexport interface StartPortalServerProps {\n\treadonly args: PortalServerCliArgs;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly logger?: PortalServerLogger;\n\treadonly resolveSecret?: (secret: SecretValue) => Promise<string>;\n\treadonly serveFn?: PortalServeFunction;\n}\n\ninterface ProfilePolicyMaps {\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\nfunction parsePort(value: string | undefined): number | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst port = Number(value);\n\tif (!Number.isInteger(port) || port < 0 || port > 65_535) {\n\t\tthrow new Error(`Invalid --port value \"${value}\".`);\n\t}\n\treturn port;\n}\n\nexport function parsePortalServerCliArgs(argv: readonly string[]): PortalServerCliArgs {\n\tconst parsed = parseArgs({\n\t\targs: [...argv],\n\t\toptions: {\n\t\t\tagent: { multiple: true, type: 'string' },\n\t\t\t'config-dir': { type: 'string' },\n\t\t\tport: { short: 'p', type: 'string' },\n\t\t},\n\t\tstrict: true,\n\t});\n\tconst configDir = parsed.values['config-dir'];\n\tif (typeof configDir !== 'string' || configDir.length === 0) {\n\t\tthrow new Error('--config-dir <path> is required.');\n\t}\n\tconst rawAgentOverrides = parsed.values.agent;\n\tconst args = {\n\t\tagentOverrides: Array.isArray(rawAgentOverrides) ? rawAgentOverrides : [],\n\t\tconfigDir,\n\t};\n\tconst port = parsePort(parsed.values.port);\n\treturn port === undefined ? args : { ...args, port };\n}\n\nexport function applyAgentOverrides(\n\tagents: Readonly<Record<string, McpPortalAgentConfig>>,\n\toverrides: readonly string[],\n): Readonly<Record<string, McpPortalAgentConfig>> {\n\tconst nextAgents: Record<string, McpPortalAgentConfig> = { ...agents };\n\tfor (const override of overrides) {\n\t\tconst [agentId, profileName, extra] = override.split('=');\n\t\tif (\n\t\t\tagentId === undefined ||\n\t\t\tprofileName === undefined ||\n\t\t\textra !== undefined ||\n\t\t\tagentId.length === 0 ||\n\t\t\tprofileName.length === 0\n\t\t) {\n\t\t\tthrow new Error(`Invalid --agent override \"${override}\". Expected <agentId>=<profile>.`);\n\t\t}\n\t\tconst existingAgent = nextAgents[agentId];\n\t\tif (existingAgent === undefined) {\n\t\t\tthrow new Error(`Cannot override unknown MCP Portal agent \"${agentId}\".`);\n\t\t}\n\t\tnextAgents[agentId] = { ...existingAgent, profile: profileName };\n\t}\n\treturn nextAgents;\n}\n\nexport interface DeferredPort {\n\treadonly promise: Promise<number>;\n\treadonly reject: (error: Error) => void;\n\treadonly resolve: (port: number) => void;\n}\n\nfunction createDeferredPort(): DeferredPort {\n\tlet rejectPort: ((error: Error) => void) | undefined;\n\tlet resolvePort: ((port: number) => void) | undefined;\n\tconst promise = new Promise<number>((resolve, reject) => {\n\t\trejectPort = reject;\n\t\tresolvePort = resolve;\n\t});\n\treturn {\n\t\tpromise,\n\t\treject: (error) => {\n\t\t\tif (rejectPort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port rejector was not initialized.');\n\t\t\t}\n\t\t\trejectPort(error);\n\t\t},\n\t\tresolve: (port) => {\n\t\t\tif (resolvePort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port resolver was not initialized.');\n\t\t\t}\n\t\t\tresolvePort(port);\n\t\t},\n\t};\n}\n\nfunction defaultPortalServerLogger(): PortalServerLogger {\n\treturn {\n\t\tlog: (event) => {\n\t\t\tprocess.stderr.write(`${JSON.stringify(event)}\\n`);\n\t\t},\n\t};\n}\n\nexport function handlePortalServerError(props: {\n\treadonly error: Error;\n\treadonly hasListened: boolean;\n\treadonly listeningPort: DeferredPort;\n\treadonly logger: PortalServerLogger;\n}): void {\n\tprops.logger.log({\n\t\tevent: 'server_error',\n\t\tlevel: 'error',\n\t\tmessage: props.error.message,\n\t\t...(props.error.stack === undefined ? {} : { stack: props.error.stack }),\n\t});\n\tif (!props.hasListened) {\n\t\tprops.listeningPort.reject(props.error);\n\t}\n}\n\nfunction closeNodeServer(server: PortalNodeServer): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tserver.close((error) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\nasync function resolveProviderSecretRecord(\n\tsecrets: Readonly<Record<string, SecretValue>>,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<Readonly<Record<string, string>>> {\n\tconst resolvedEntries = await Promise.all(\n\t\tObject.entries(secrets).map(\n\t\t\tasync ([name, secret]) => [name, await resolveSecret(secret)] as const,\n\t\t),\n\t);\n\treturn Object.fromEntries(resolvedEntries);\n}\n\nasync function resolveUpstreamServer(\n\tprovider: ResolvedMcpProvider,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<NormalizedUpstreamMcpServer> {\n\tif (provider.transport === 'stdio') {\n\t\treturn {\n\t\t\targs: provider.args,\n\t\t\tcommand: provider.command,\n\t\t\t...(provider.cwd === undefined ? {} : { cwd: provider.cwd }),\n\t\t\tenv: await resolveProviderSecretRecord(provider.env, resolveSecret),\n\t\t\tnamespace: provider.namespace,\n\t\t\ttransport: 'stdio',\n\t\t};\n\t}\n\n\treturn {\n\t\theaders: await resolveProviderSecretRecord(provider.headers, resolveSecret),\n\t\tnamespace: provider.namespace,\n\t\ttransport: provider.transport,\n\t\turl: provider.url,\n\t};\n}\n\nasync function resolveUpstreamServers(\n\tmcpConfig: McpConfig,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<readonly NormalizedUpstreamMcpServer[]> {\n\treturn await Promise.all(\n\t\tmcpConfigToResolvedProviders(mcpConfig).map(async (provider) =>\n\t\t\tresolveUpstreamServer(provider, resolveSecret),\n\t\t),\n\t);\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(\n\tportalConfig: McpPortalConfig,\n): ProfilePolicyMaps & { readonly cacheTtlMs: number } {\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\nfunction withAgentOverrides(\n\tportalConfig: McpPortalConfig,\n\tagentOverrides: readonly string[],\n): McpPortalConfig {\n\treturn {\n\t\t...portalConfig,\n\t\tagents: applyAgentOverrides(portalConfig.agents, agentOverrides),\n\t};\n}\n\nexport async function startPortalServer(\n\tprops: StartPortalServerProps,\n): Promise<{ readonly close: () => Promise<void>; readonly port: number }> {\n\tconst logger = props.logger ?? defaultPortalServerLogger();\n\tconst serveFn = props.serveFn ?? serve;\n\tconst resolveSecret =\n\t\tprops.resolveSecret ??\n\t\t((secret: SecretValue) => resolveSecretValue(secret, { env: props.env }));\n\tconst mcpConfig = await loadMcpConfig(join(props.args.configDir, 'mcp.config.jsonc'));\n\tconst portalConfig = withAgentOverrides(\n\t\tawait loadMcpPortalConfig(join(props.args.configDir, 'mcp-portal.config.jsonc')),\n\t\tprops.args.agentOverrides,\n\t);\n\tconst serverAccessSecret = await resolveSecret(portalConfig.server.accessHeader.secret);\n\tconst hmacKeys = await resolveAgentHmacKeys({\n\t\tagents: portalConfig.agents,\n\t\tenvKeys: parseHmacKeysFromEnv(props.env),\n\t\tresolveSecret,\n\t});\n\tconst agentRecords = createPortalAgentRuntimeRecords({ hmacKeys, portalConfig });\n\tconst upstreamServers = await resolveUpstreamServers(mcpConfig, resolveSecret);\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\tconst sessionManager = createPortalSessionManager({\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\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: upstreamRuntime,\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n\tconst verifyApproval = createPortalApprovalVerifier({\n\t\tonConservativeApprovalFallback: (event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tconservativeCallCount: event.conservativeCallCount,\n\t\t\t\tevent: 'conservative_approval_fallback',\n\t\t\t\tlevel: 'warn',\n\t\t\t\tprimaryReason: event.primaryReason,\n\t\t\t\tstrictCallCount: event.strictCallCount,\n\t\t\t\ttoolRefs: event.toolRefs,\n\t\t\t});\n\t\t},\n\t\trecords: agentRecords,\n\t});\n\tconst app = createPortalHttpApp({\n\t\tonSessionClosed: async (identity) => {\n\t\t\tawait sessionManager.invalidateSession(identity);\n\t\t},\n\t\tregisteredAgentIds: Object.keys(portalConfig.agents),\n\t\tresolveAgentIdentity: createPortalHttpAgentResolver(agentRecords),\n\t\tserverAccess: {\n\t\t\texpectedValue: serverAccessSecret,\n\t\t\theaderName: portalConfig.server.accessHeader.name,\n\t\t},\n\t\ttoolRuntime: {\n\t\t\tapproval: (calls, identity, approvalToken) =>\n\t\t\t\tverifyApproval(calls, identity.agentId, approvalToken),\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tgetSession: sessionManager.getSession,\n\t\t},\n\t});\n\tconst listeningPort = createDeferredPort();\n\tlet hasListened = false;\n\tconst server = serveFn(\n\t\t{\n\t\t\tfetch: app.fetch,\n\t\t\thostname: portalConfig.server.host,\n\t\t\tport: props.args.port ?? portalConfig.server.port,\n\t\t},\n\t\t(info) => {\n\t\t\thasListened = true;\n\t\t\tprocess.stdout.write(`listening port=${String(info.port)}\\n`);\n\t\t\tlisteningPort.resolve(info.port);\n\t\t},\n\t);\n\tserver.on('error', (error: Error) => {\n\t\thandlePortalServerError({ error, hasListened, listeningPort, logger });\n\t});\n\tconst port = await listeningPort.promise;\n\n\treturn {\n\t\tclose: async () => {\n\t\t\tawait app.closePortalSessions();\n\t\t\tawait Promise.all(\n\t\t\t\tObject.keys(portalConfig.agents).map((agentId) =>\n\t\t\t\t\tsessionManager.invalidateAgentScope(agentId),\n\t\t\t\t),\n\t\t\t);\n\t\t\tawait closeNodeServer(server);\n\t\t},\n\t\tport,\n\t};\n}\n\nasync function main(): Promise<void> {\n\tconst startedServer = await startPortalServer({\n\t\targs: parsePortalServerCliArgs(process.argv.slice(2)),\n\t\tenv: process.env,\n\t});\n\tconst shutdown = async (): Promise<void> => {\n\t\tawait startedServer.close();\n\t\tprocess.exit(0);\n\t};\n\tprocess.on('SIGINT', () => {\n\t\tvoid shutdown();\n\t});\n\tprocess.on('SIGTERM', () => {\n\t\tvoid shutdown();\n\t});\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n\tvoid main().catch((error: unknown) => {\n\t\tprocess.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n\t\tprocess.exit(1);\n\t});\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"portal-server.js","names":[],"sources":["../../src/bin/secret-value-resolver.ts","../../src/bin/portal-server.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport type { SecretValue } from '@agent-vm/config-contracts';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ResolveSecretValueProps {\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly readOnePasswordSecret?: (ref: string) => Promise<string>;\n}\n\nexport async function resolveSecretValue(\n\tsecret: SecretValue,\n\tprops: ResolveSecretValueProps,\n): Promise<string> {\n\tif (secret.source === 'environment') {\n\t\tconst value = props.env[secret.name];\n\t\tif (value === undefined || value.length === 0) {\n\t\t\tthrow new Error(`Missing environment secret ${secret.name}.`);\n\t\t}\n\t\treturn value;\n\t}\n\n\tconst readOnePasswordSecret = props.readOnePasswordSecret ?? readOnePasswordCliSecret;\n\treturn await readOnePasswordSecret(secret.ref);\n}\n\nasync function readOnePasswordCliSecret(ref: string): Promise<string> {\n\tconst { stdout } = await execFileAsync('op', ['read', ref], { encoding: 'utf8' });\n\treturn stdout.trimEnd();\n}\n","#!/usr/bin/env node\nimport { realpath } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { parseArgs } from 'node:util';\n\nimport {\n\tloadMcpConfig,\n\tloadMcpPortalConfig,\n\tmcpConfigToResolvedProviders,\n\tresolveMcpPortalProfile,\n\ttype McpConfig,\n\ttype McpPortalAgentConfig,\n\ttype McpPortalConfig,\n\ttype ResolvedMcpProvider,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\nimport { serve } from '@hono/node-server';\n\nimport { parseHmacKeysFromEnv } from '../auth/hmac-env.js';\nimport { createPortalHttpApp } from '../mcp-server/portal-http-server.js';\nimport {\n\tcreatePortalAgentRuntimeRecords,\n\tcreatePortalApprovalVerifier,\n\tcreatePortalHttpAgentResolver,\n\tresolveAgentHmacKeys,\n} from '../mcp-server/resolve-agent-identity.js';\nimport type { PortalToolSelector } from '../portal-access-policy.js';\nimport { createPortalSessionManager } from '../portal-session.js';\nimport {\n\tcreateUpstreamMcpClientRuntime,\n\ttype NormalizedUpstreamMcpServer,\n} from '../upstream-mcp-client-runtime.js';\nimport { resolveSecretValue } from './secret-value-resolver.js';\n\ntype PortalNodeServer = ReturnType<typeof serve>;\ntype PortalServeFunction = typeof serve;\n\nexport type PortalServerLogEvent =\n\t| {\n\t\t\treadonly agentId: string;\n\t\t\treadonly conservativeCallCount: number;\n\t\t\treadonly event: 'conservative_approval_fallback';\n\t\t\treadonly level: 'warn';\n\t\t\treadonly primaryReason: string;\n\t\t\treadonly strictCallCount: number;\n\t\t\treadonly toolRefs: readonly string[];\n\t }\n\t| {\n\t\t\treadonly event: 'server_error';\n\t\t\treadonly level: 'error';\n\t\t\treadonly message: string;\n\t\t\treadonly stack?: string;\n\t };\n\nexport interface PortalServerLogger {\n\treadonly log: (event: PortalServerLogEvent) => void;\n}\n\nexport interface PortalServerCliArgs {\n\treadonly agentOverrides: readonly string[];\n\treadonly configDir: string;\n\treadonly port?: number;\n}\n\nexport interface StartPortalServerProps {\n\treadonly args: PortalServerCliArgs;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly logger?: PortalServerLogger;\n\treadonly resolveSecret?: (secret: SecretValue) => Promise<string>;\n\treadonly serveFn?: PortalServeFunction;\n}\n\ninterface ProfilePolicyMaps {\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\nfunction parsePort(value: string | undefined): number | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst port = Number(value);\n\tif (!Number.isInteger(port) || port < 0 || port > 65_535) {\n\t\tthrow new Error(`Invalid --port value \"${value}\".`);\n\t}\n\treturn port;\n}\n\nexport function parsePortalServerCliArgs(argv: readonly string[]): PortalServerCliArgs {\n\tconst parsed = parseArgs({\n\t\targs: [...argv],\n\t\toptions: {\n\t\t\tagent: { multiple: true, type: 'string' },\n\t\t\t'config-dir': { type: 'string' },\n\t\t\tport: { short: 'p', type: 'string' },\n\t\t},\n\t\tstrict: true,\n\t});\n\tconst configDir = parsed.values['config-dir'];\n\tif (typeof configDir !== 'string' || configDir.length === 0) {\n\t\tthrow new Error('--config-dir <path> is required.');\n\t}\n\tconst rawAgentOverrides = parsed.values.agent;\n\tconst args = {\n\t\tagentOverrides: Array.isArray(rawAgentOverrides) ? rawAgentOverrides : [],\n\t\tconfigDir,\n\t};\n\tconst port = parsePort(parsed.values.port);\n\treturn port === undefined ? args : { ...args, port };\n}\n\nexport function applyAgentOverrides(\n\tagents: Readonly<Record<string, McpPortalAgentConfig>>,\n\toverrides: readonly string[],\n): Readonly<Record<string, McpPortalAgentConfig>> {\n\tconst nextAgents: Record<string, McpPortalAgentConfig> = { ...agents };\n\tfor (const override of overrides) {\n\t\tconst [agentId, profileName, extra] = override.split('=');\n\t\tif (\n\t\t\tagentId === undefined ||\n\t\t\tprofileName === undefined ||\n\t\t\textra !== undefined ||\n\t\t\tagentId.length === 0 ||\n\t\t\tprofileName.length === 0\n\t\t) {\n\t\t\tthrow new Error(`Invalid --agent override \"${override}\". Expected <agentId>=<profile>.`);\n\t\t}\n\t\tconst existingAgent = nextAgents[agentId];\n\t\tif (existingAgent === undefined) {\n\t\t\tthrow new Error(`Cannot override unknown MCP Portal agent \"${agentId}\".`);\n\t\t}\n\t\tnextAgents[agentId] = { ...existingAgent, profile: profileName };\n\t}\n\treturn nextAgents;\n}\n\nexport interface DeferredPort {\n\treadonly promise: Promise<number>;\n\treadonly reject: (error: Error) => void;\n\treadonly resolve: (port: number) => void;\n}\n\nfunction createDeferredPort(): DeferredPort {\n\tlet rejectPort: ((error: Error) => void) | undefined;\n\tlet resolvePort: ((port: number) => void) | undefined;\n\tconst promise = new Promise<number>((resolve, reject) => {\n\t\trejectPort = reject;\n\t\tresolvePort = resolve;\n\t});\n\treturn {\n\t\tpromise,\n\t\treject: (error) => {\n\t\t\tif (rejectPort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port rejector was not initialized.');\n\t\t\t}\n\t\t\trejectPort(error);\n\t\t},\n\t\tresolve: (port) => {\n\t\t\tif (resolvePort === undefined) {\n\t\t\t\tthrow new Error('MCP Portal port resolver was not initialized.');\n\t\t\t}\n\t\t\tresolvePort(port);\n\t\t},\n\t};\n}\n\nfunction defaultPortalServerLogger(): PortalServerLogger {\n\treturn {\n\t\tlog: (event) => {\n\t\t\tprocess.stderr.write(`${JSON.stringify(event)}\\n`);\n\t\t},\n\t};\n}\n\nexport function handlePortalServerError(props: {\n\treadonly error: Error;\n\treadonly hasListened: boolean;\n\treadonly listeningPort: DeferredPort;\n\treadonly logger: PortalServerLogger;\n}): void {\n\tprops.logger.log({\n\t\tevent: 'server_error',\n\t\tlevel: 'error',\n\t\tmessage: props.error.message,\n\t\t...(props.error.stack === undefined ? {} : { stack: props.error.stack }),\n\t});\n\tif (!props.hasListened) {\n\t\tprops.listeningPort.reject(props.error);\n\t}\n}\n\nfunction closeNodeServer(server: PortalNodeServer): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tserver.close((error) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\nasync function resolveProviderSecretRecord(\n\tsecrets: Readonly<Record<string, SecretValue>>,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<Readonly<Record<string, string>>> {\n\tconst resolvedEntries = await Promise.all(\n\t\tObject.entries(secrets).map(\n\t\t\tasync ([name, secret]) => [name, await resolveSecret(secret)] as const,\n\t\t),\n\t);\n\treturn Object.fromEntries(resolvedEntries);\n}\n\nasync function resolveUpstreamServer(\n\tprovider: ResolvedMcpProvider,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<NormalizedUpstreamMcpServer> {\n\tif (provider.transport === 'stdio') {\n\t\treturn {\n\t\t\targs: provider.args,\n\t\t\tcommand: provider.command,\n\t\t\t...(provider.cwd === undefined ? {} : { cwd: provider.cwd }),\n\t\t\tenv: await resolveProviderSecretRecord(provider.env, resolveSecret),\n\t\t\tnamespace: provider.namespace,\n\t\t\ttransport: 'stdio',\n\t\t};\n\t}\n\n\treturn {\n\t\theaders: await resolveProviderSecretRecord(provider.headers, resolveSecret),\n\t\tnamespace: provider.namespace,\n\t\ttransport: provider.transport,\n\t\turl: provider.url,\n\t};\n}\n\nasync function resolveUpstreamServers(\n\tmcpConfig: McpConfig,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<readonly NormalizedUpstreamMcpServer[]> {\n\treturn await Promise.all(\n\t\tmcpConfigToResolvedProviders(mcpConfig).map(async (provider) =>\n\t\t\tresolveUpstreamServer(provider, resolveSecret),\n\t\t),\n\t);\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(\n\tportalConfig: McpPortalConfig,\n): ProfilePolicyMaps & { readonly cacheTtlMs: number } {\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\nfunction withAgentOverrides(\n\tportalConfig: McpPortalConfig,\n\tagentOverrides: readonly string[],\n): McpPortalConfig {\n\treturn {\n\t\t...portalConfig,\n\t\tagents: applyAgentOverrides(portalConfig.agents, agentOverrides),\n\t};\n}\n\nexport async function startPortalServer(\n\tprops: StartPortalServerProps,\n): Promise<{ readonly close: () => Promise<void>; readonly port: number }> {\n\tconst logger = props.logger ?? defaultPortalServerLogger();\n\tconst serveFn = props.serveFn ?? serve;\n\tconst resolveSecret =\n\t\tprops.resolveSecret ??\n\t\t((secret: SecretValue) => resolveSecretValue(secret, { env: props.env }));\n\tconst mcpConfig = await loadMcpConfig(join(props.args.configDir, 'mcp.config.jsonc'));\n\tconst portalConfig = withAgentOverrides(\n\t\tawait loadMcpPortalConfig(join(props.args.configDir, 'mcp-portal.config.jsonc')),\n\t\tprops.args.agentOverrides,\n\t);\n\tconst serverAccessSecret = await resolveSecret(portalConfig.server.accessHeader.secret);\n\tconst hmacKeys = await resolveAgentHmacKeys({\n\t\tagents: portalConfig.agents,\n\t\tenvKeys: parseHmacKeysFromEnv(props.env),\n\t\tresolveSecret,\n\t});\n\tconst agentRecords = createPortalAgentRuntimeRecords({ hmacKeys, portalConfig });\n\tconst upstreamServers = await resolveUpstreamServers(mcpConfig, resolveSecret);\n\tconst upstreamRuntime = createUpstreamMcpClientRuntime({ servers: upstreamServers });\n\tconst profilePolicyMaps = buildProfilePolicyMaps(portalConfig);\n\tconst sessionManager = createPortalSessionManager({\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\tcatalogTtlMs: profilePolicyMaps.cacheTtlMs,\n\t\truntime: upstreamRuntime,\n\t\tupstreamNamespaces: upstreamServers.map((server) => server.namespace),\n\t});\n\tconst verifyApproval = createPortalApprovalVerifier({\n\t\tonConservativeApprovalFallback: (event) => {\n\t\t\tlogger.log({\n\t\t\t\tagentId: event.agentId,\n\t\t\t\tconservativeCallCount: event.conservativeCallCount,\n\t\t\t\tevent: 'conservative_approval_fallback',\n\t\t\t\tlevel: 'warn',\n\t\t\t\tprimaryReason: event.primaryReason,\n\t\t\t\tstrictCallCount: event.strictCallCount,\n\t\t\t\ttoolRefs: event.toolRefs,\n\t\t\t});\n\t\t},\n\t\trecords: agentRecords,\n\t});\n\tconst app = createPortalHttpApp({\n\t\tonSessionClosed: async (identity) => {\n\t\t\tawait sessionManager.invalidateSession(identity);\n\t\t},\n\t\tregisteredAgentIds: Object.keys(portalConfig.agents),\n\t\tresolveAgentIdentity: createPortalHttpAgentResolver(agentRecords),\n\t\tserverAccess: {\n\t\t\texpectedValue: serverAccessSecret,\n\t\t\theaderName: portalConfig.server.accessHeader.name,\n\t\t},\n\t\ttoolRuntime: {\n\t\t\tapproval: (calls, identity, approvalToken) =>\n\t\t\t\tverifyApproval(calls, identity.agentId, approvalToken),\n\t\t\tcallUpstreamTool: upstreamRuntime.callTool,\n\t\t\tgetSession: sessionManager.getSession,\n\t\t},\n\t});\n\tconst listeningPort = createDeferredPort();\n\tlet hasListened = false;\n\tconst server = serveFn(\n\t\t{\n\t\t\tfetch: app.fetch,\n\t\t\thostname: portalConfig.server.host,\n\t\t\tport: props.args.port ?? portalConfig.server.port,\n\t\t},\n\t\t(info) => {\n\t\t\thasListened = true;\n\t\t\tprocess.stdout.write(`listening port=${String(info.port)}\\n`);\n\t\t\tlisteningPort.resolve(info.port);\n\t\t},\n\t);\n\tserver.on('error', (error: Error) => {\n\t\thandlePortalServerError({ error, hasListened, listeningPort, logger });\n\t});\n\tconst port = await listeningPort.promise;\n\n\treturn {\n\t\tclose: async () => {\n\t\t\tawait app.closePortalSessions();\n\t\t\tawait Promise.all(\n\t\t\t\tObject.keys(portalConfig.agents).map((agentId) =>\n\t\t\t\t\tsessionManager.invalidateAgentScope(agentId),\n\t\t\t\t),\n\t\t\t);\n\t\t\tawait closeNodeServer(server);\n\t\t},\n\t\tport,\n\t};\n}\n\nasync function main(): Promise<void> {\n\tconst startedServer = await startPortalServer({\n\t\targs: parsePortalServerCliArgs(process.argv.slice(2)),\n\t\tenv: process.env,\n\t});\n\tconst shutdown = async (): Promise<void> => {\n\t\tawait startedServer.close();\n\t\tprocess.exit(0);\n\t};\n\tprocess.on('SIGINT', () => {\n\t\tvoid shutdown();\n\t});\n\tprocess.on('SIGTERM', () => {\n\t\tvoid shutdown();\n\t});\n}\n\nexport async function isPortalServerEntrypoint(\n\timportMetaUrl: string,\n\targvEntryPath: string | undefined,\n\trealpathFn: (targetPath: string) => Promise<string> = realpath,\n): Promise<boolean> {\n\tif (argvEntryPath === undefined) {\n\t\treturn false;\n\t}\n\ttry {\n\t\tconst modulePath = fileURLToPath(importMetaUrl);\n\t\tconst [realModulePath, realArgvEntryPath] = await Promise.all([\n\t\t\trealpathFn(modulePath),\n\t\t\trealpathFn(argvEntryPath),\n\t\t]);\n\t\treturn realModulePath === realArgvEntryPath;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nif (await isPortalServerEntrypoint(import.meta.url, process.argv[1])) {\n\tvoid main().catch((error: unknown) => {\n\t\tprocess.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n\t\tprocess.exit(1);\n\t});\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-vm/mcp-portal",
3
- "version": "0.0.65",
3
+ "version": "0.0.66",
4
4
  "description": "Agent-scoped MCP Portal server and TypeScript helpers for composable upstream MCP tools.",
5
5
  "homepage": "https://github.com/ShravanSunder/agent-vm#readme",
6
6
  "bugs": {
@@ -53,7 +53,7 @@
53
53
  "@modelcontextprotocol/sdk": "^1.29.0",
54
54
  "hono": "^4.12.18",
55
55
  "zod": "^4.4.3",
56
- "@agent-vm/config-contracts": "0.0.65"
56
+ "@agent-vm/config-contracts": "0.0.66"
57
57
  },
58
58
  "devDependencies": {
59
59
  "vitest": "^4.1.5"