@agimon-ai/po-mcp 0.0.0-alpha.113 → 0.0.0-alpha.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{directTools--0HFuomq.mjs → directTools-WOd8O_8I.mjs} +3 -9
- package/dist/directTools-WOd8O_8I.mjs.map +1 -0
- package/dist/{directTools-uCNQi0Oe.cjs → directTools-hv4kxZeY.cjs} +4 -22
- package/dist/{directTools--0HFuomq.mjs.map → directTools-hv4kxZeY.cjs.map} +1 -1
- package/dist/extensions/native.mjs.map +1 -1
- package/dist/extensions/server.cjs +116 -654
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +10 -548
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{mcpCatalog-D_nh-K5U.cjs → mcpCatalog-D6eVhMcK.cjs} +29 -1
- package/dist/mcpCatalog-D6eVhMcK.cjs.map +1 -0
- package/dist/{mcpCatalog-D85z2043.mjs → mcpCatalog-yaVP_T1c.mjs} +12 -2
- package/dist/mcpCatalog-yaVP_T1c.mjs.map +1 -0
- package/dist/mcpServerConfig-CmCGFfAk.mjs +1020 -0
- package/dist/mcpServerConfig-CmCGFfAk.mjs.map +1 -0
- package/dist/mcpServerConfig-CxTNEdZ9.cjs +1283 -0
- package/dist/mcpServerConfig-CxTNEdZ9.cjs.map +1 -0
- package/dist/remoteServers.cjs +89 -5
- package/dist/remoteServers.cjs.map +1 -1
- package/dist/remoteServers.d.mts +46 -2
- package/dist/remoteServers.d.mts.map +1 -1
- package/dist/remoteServers.mjs +86 -3
- package/dist/remoteServers.mjs.map +1 -1
- package/package.json +9 -9
- package/dist/directTools-uCNQi0Oe.cjs.map +0 -1
- package/dist/mcpCatalog-D85z2043.mjs.map +0 -1
- package/dist/mcpCatalog-D_nh-K5U.cjs.map +0 -1
- package/dist/mcpSecrets-CgyPlKaV.mjs +0 -451
- package/dist/mcpSecrets-CgyPlKaV.mjs.map +0 -1
- package/dist/mcpSecrets-DXxp-c21.cjs +0 -540
- package/dist/mcpSecrets-DXxp-c21.cjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as pluginPathMcpScope, f as projectedSourceMcpScope, l as isProxyWrapper, p as repositoryMcpScope, s as PROXY_SERVER_ALIASES } from "./mcpCatalog-yaVP_T1c.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import fs, { readFile } from "node:fs/promises";
|
|
4
4
|
import path, { join } from "node:path";
|
|
@@ -20,9 +20,6 @@ var __exportAll = (all, no_symbols) => {
|
|
|
20
20
|
};
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region src/services/configSources/index.ts
|
|
23
|
-
/** Wrapper entry used by non-Po clients to expose `mcp-config.yaml` as one MCP. */
|
|
24
|
-
const PROXY_SERVER_NAME = "mcp-proxy";
|
|
25
|
-
const PROXY_SERVER_ALIASES = /* @__PURE__ */ new Set([PROXY_SERVER_NAME, "agiflow-proxy"]);
|
|
26
23
|
const PRIVATE_FILE_MODE = 384;
|
|
27
24
|
const PRIVATE_DIRECTORY_MODE = 448;
|
|
28
25
|
const DEFAULT_UPSTREAM_CONFIG = "mcp-config.yaml";
|
|
@@ -55,9 +52,6 @@ function serverDefinitions(config) {
|
|
|
55
52
|
function isEnabledDefinition(definition) {
|
|
56
53
|
return !isObject(definition) || definition.disabled !== true;
|
|
57
54
|
}
|
|
58
|
-
function isProxyWrapper(name) {
|
|
59
|
-
return PROXY_SERVER_ALIASES.has(name);
|
|
60
|
-
}
|
|
61
55
|
/**
|
|
62
56
|
* Resolves the upstream config referenced by the repository proxy wrapper.
|
|
63
57
|
*
|
|
@@ -509,6 +503,6 @@ const DIRECT_TOOLS_ENV = "MCP_DIRECT_TOOLS";
|
|
|
509
503
|
/** Explicit "no MCP tools", distinct from an unset variable meaning "no limit". */
|
|
510
504
|
const NO_DIRECT_TOOLS = "__none__";
|
|
511
505
|
//#endregion
|
|
512
|
-
export { McpRuntimeOwner as a, mcpRuntime_exports as c,
|
|
506
|
+
export { McpRuntimeOwner as a, mcpRuntime_exports as c, __exportAll as d, sessionConfigEnvironment as i, readCachedCatalog as l, NO_DIRECT_TOOLS as n, definitionsCachePath as o, readSessionConfig as r, hubCallbackSink as s, DIRECT_TOOLS_ENV as t, buildMcpConfigGroups as u };
|
|
513
507
|
|
|
514
|
-
//# sourceMappingURL=directTools
|
|
508
|
+
//# sourceMappingURL=directTools-WOd8O_8I.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directTools-WOd8O_8I.mjs","names":["parseYaml","stringifyYaml"],"sources":["../src/services/configSources/index.ts","../src/services/mcpRuntime/index.ts","../src/services/sessionConfig/index.ts","../src/schemas/directTools.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { normalizeAgentPluginMcpSource } from '@agimon-ai/po-config/agentPluginMcp';\nimport type { PoMcpNativeProjectionSource } from '@agimon-ai/po-core/mcpProjection';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport type { McpConfigGroups, McpConfigGroupsInput, McpConfigSource, McpServerOrigin } from '../../types/mcpConfig';\nimport { pluginPathMcpScope, projectedSourceMcpScope, repositoryMcpScope } from '../mcpScope';\nimport { isProxyWrapper, PROXY_SERVER_ALIASES } from '../proxyWrapper';\n\n// The name check lives in `proxyWrapper` so the edge-safe server config can use it without this file's Node imports.\nexport { isProxyWrapper, PROXY_SERVER_NAME } from '../proxyWrapper';\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst DEFAULT_UPSTREAM_CONFIG = 'mcp-config.yaml';\nconst CONFIG_ARGUMENT = '--config';\n\ntype JsonObject = Record<string, unknown>;\n\ninterface FilteredLayer {\n source: McpConfigSource;\n kept: string[];\n dropped: string[];\n}\n\ninterface ConfigDocument {\n config: JsonObject;\n contents: string;\n}\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isYamlPath(filePath: string): boolean {\n const extension = path.extname(filePath).toLowerCase();\n return extension === '.yaml' || extension === '.yml';\n}\n\nasync function readConfigDocument(filePath: string): Promise<ConfigDocument | undefined> {\n try {\n const contents = await fs.readFile(filePath, 'utf8');\n const parsed: unknown = isYamlPath(filePath) ? parseYaml(contents) : JSON.parse(contents);\n return isObject(parsed) ? { config: parsed, contents } : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readConfigObject(filePath: string): Promise<JsonObject | undefined> {\n return (await readConfigDocument(filePath))?.config;\n}\n\nfunction serverDefinitions(config: JsonObject | undefined): Record<string, unknown> {\n return isObject(config?.mcpServers) ? config.mcpServers : {};\n}\n\nfunction isEnabledDefinition(definition: unknown): boolean {\n return !isObject(definition) || definition.disabled !== true;\n}\n\n/**\n * Resolves the upstream config referenced by the repository proxy wrapper.\n *\n * The wrapper remains useful to Claude, Codex, and other external clients. Po\n * embeds the same client/runtime code, so it reads this path and connects each\n * declared server itself instead of starting the wrapper as a nested MCP.\n */\nasync function resolveSharedConfigPathFrom(\n repoRoot: string,\n repositoryConfigPath: string,\n): Promise<string | undefined> {\n const servers = serverDefinitions(await readConfigObject(repositoryConfigPath));\n const proxy = [...PROXY_SERVER_ALIASES]\n .map((name) => servers[name])\n .find((definition): definition is JsonObject => isObject(definition));\n const rawArgs: unknown = proxy?.args;\n const args = Array.isArray(rawArgs) ? (rawArgs as unknown[]) : [];\n const configArgumentIndex = args.indexOf(CONFIG_ARGUMENT);\n const declared = args[configArgumentIndex + 1];\n const candidate =\n configArgumentIndex >= 0 && typeof declared === 'string'\n ? path.resolve(repoRoot, declared)\n : path.join(repoRoot, DEFAULT_UPSTREAM_CONFIG);\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveSharedConfigPath(repoRoot: string): Promise<string | undefined> {\n return resolveSharedConfigPathFrom(repoRoot, path.join(repoRoot, '.mcp.json'));\n}\n\n/** Empty and absent allowlists both mean \"keep everything\". */\nfunction isAllowed(name: string, allowed: string[] | undefined): boolean {\n return !allowed || allowed.length === 0 || allowed.includes(name);\n}\n\nfunction stagedPath(filePath: string, contents: string, stagingDirectory: string): string {\n // The filtered bytes are part of the identity because two live sessions can\n // select different domains. Sharing a path would let the later one rewrite the\n // configuration underneath the first one's deferred startup.\n const digest = createHash('sha256').update(filePath).update('\\0').update(contents).digest('hex').slice(0, 16);\n const extension = isYamlPath(filePath) ? '.yaml' : '.json';\n return path.join(stagingDirectory, `mcp-${digest}${extension}`);\n}\n\nfunction serializeConfig(filePath: string, config: JsonObject): string {\n return isYamlPath(filePath) ? stringifyYaml(config) : `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nasync function layerCacheKey(\n filePath: string,\n format: McpConfigSource['format'],\n originalContents: string,\n effectiveContents: string,\n sourceIdentity?: string,\n): Promise<string> {\n return createHash('sha256')\n .update(format)\n .update('\\0')\n .update(await fs.realpath(filePath))\n .update('\\0')\n .update(sourceIdentity ?? 'unprojected')\n .update('\\0')\n .update(originalContents)\n .update('\\0')\n .update(effectiveContents)\n .digest('hex');\n}\n\n/**\n * Rewrites one config layer with disallowed servers removed.\n *\n * Proxy wrapper entries are stripped from `.mcp.json` layers because Po reaches\n * their upstream config directly. Entries are removed rather than marked disabled,\n * so a filtered stdio server is never spawned at all.\n */\nasync function filterLayer(\n filePath: string,\n allowed: string[] | undefined,\n stagingDirectory: string,\n options: { stripProxyWrappers: boolean; sourceIdentity?: string },\n): Promise<FilteredLayer | undefined> {\n const document = await readConfigDocument(filePath);\n if (!document) return undefined;\n const { config, contents: originalContents } = document;\n const servers = serverDefinitions(config);\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n\n for (const [name, definition] of Object.entries(servers)) {\n const shouldDrop = (options.stripProxyWrappers && isProxyWrapper(name)) || !isAllowed(name, allowed);\n if (shouldDrop) dropped.push(name);\n else kept[name] = definition;\n }\n\n const keptNames = Object.entries(kept)\n .filter(([, definition]) => isEnabledDefinition(definition))\n .map(([name]) => name);\n if (dropped.length === 0) {\n return {\n source: {\n path: filePath,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, originalContents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n }\n\n await fs.mkdir(stagingDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const contents = serializeConfig(filePath, { ...config, mcpServers: kept });\n const target = stagedPath(filePath, contents, stagingDirectory);\n await fs.writeFile(target, contents, { mode: PRIVATE_FILE_MODE });\n return {\n source: {\n path: target,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, contents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n}\n\nasync function digestMatches(source: PoMcpNativeProjectionSource): Promise<boolean> {\n try {\n const digest = createHash('sha256')\n .update(await fs.readFile(source.configPath))\n .digest('hex');\n return digest === source.contentDigest;\n } catch {\n return false;\n }\n}\n\nfunction emptyGroups(diagnostics: string[] = []): McpConfigGroups {\n return {\n shared: { configSources: [], configPaths: [], serverNames: [] },\n sessionLocal: { configSources: [], configPaths: [], serverNames: [] },\n droppedServers: [],\n diagnostics,\n serverScopes: {},\n };\n}\n\n/**\n * Resolves every config layer for this session and applies its domain allowlist.\n *\n * All returned layers go into one embedded `@agimon-ai/po-mcp-proxy` client container.\n * The package is used as a library only: its wrapper MCP never becomes a Po MCP\n * server, so status, enable/disable, resources, and OAuth stay attached to each\n * actual downstream server.\n */\nexport async function buildMcpConfigGroups(input: McpConfigGroupsInput): Promise<\n McpConfigGroups & {\n /** Internal only. Paths and revisions must not be forwarded as browser ownership claims. */\n serverOrigins?: Record<string, McpServerOrigin>;\n }\n> {\n if (input.enabled === false) return emptyGroups();\n\n const projectedSources = input.sources;\n const repositoryScope = await repositoryMcpScope(input.repoRoot);\n const legacyLayers = projectedSources\n ? []\n : [\n { path: path.join(input.repoRoot, '.mcp.json'), scope: repositoryScope },\n ...(input.pluginConfigPaths ?? []).map((candidate) => {\n const resolved = path.resolve(input.repoRoot, candidate);\n return { path: resolved, scope: pluginPathMcpScope(resolved) };\n }),\n ];\n // Walked in container order, sessionLocal then shared, so the layer that wins a name owns its credential.\n const serverScopes: Record<string, string> = {};\n const serverOrigins: Record<string, McpServerOrigin> = {};\n const claim = async (\n names: readonly string[],\n scope: string,\n owner: McpServerOrigin['owner'],\n filePath: string,\n sourceId?: string,\n ) => {\n const definitions = serverDefinitions(await readConfigObject(filePath));\n for (const name of names) {\n serverScopes[name] = scope;\n serverOrigins[name] = {\n owner,\n path: filePath,\n revision: createHash('sha256')\n .update(JSON.stringify(definitions[name]) ?? 'undefined')\n .digest('hex'),\n ...(sourceId === undefined ? {} : { sourceId }),\n };\n }\n };\n\n const configSources: McpConfigSource[] = [];\n const serverNames: string[] = [];\n const droppedServers: string[] = [];\n const diagnostics: string[] = [];\n for (const layer of legacyLayers) {\n const filtered = await filterLayer(layer.path, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n });\n if (!filtered) continue;\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n layer.scope,\n layer.path === path.join(input.repoRoot, '.mcp.json') ? 'repository' : 'plugin',\n layer.path,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n for (const source of projectedSources ?? []) {\n if (source.format === 'agent-plugin-v1') {\n const normalized = normalizeAgentPluginMcpSource(source, {\n stagingDirectory: input.stagingDirectory,\n allowedServers: input.allowlist?.servers,\n });\n if (normalized.configSource) configSources.push(normalized.configSource);\n serverNames.push(...normalized.serverNames);\n await claim(\n normalized.serverNames,\n await projectedSourceMcpScope(source, input.repoRoot),\n 'plugin',\n normalized.configSource?.path ?? source.configPath,\n source.sourceId,\n );\n droppedServers.push(...normalized.droppedServers);\n diagnostics.push(...normalized.diagnostics);\n continue;\n }\n\n if (!(await digestMatches(source))) {\n diagnostics.push(\n `Native MCP source \"${source.sourceId}\" was disabled: the file is missing or its content digest changed.`,\n );\n continue;\n }\n const filtered = await filterLayer(source.configPath, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n sourceIdentity: `${source.sourceId}:${source.contentDigest}`,\n });\n if (!filtered) {\n diagnostics.push(`Native MCP source \"${source.sourceId}\" was disabled: the config could not be parsed.`);\n continue;\n }\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n await projectedSourceMcpScope(source, input.repoRoot),\n source.owner === 'user' ? 'user' : source.owner === 'repository' ? 'repository' : 'plugin',\n source.configPath,\n source.sourceId,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n const repositorySource = projectedSources?.find(\n (source): source is PoMcpNativeProjectionSource => source.format === 'native' && source.owner === 'repository',\n );\n const upstreamPath = projectedSources\n ? repositorySource && (await digestMatches(repositorySource))\n ? await resolveSharedConfigPathFrom(input.repoRoot, repositorySource.configPath)\n : undefined\n : await resolveSharedConfigPath(input.repoRoot);\n const upstream = upstreamPath\n ? await filterLayer(upstreamPath, input.allowlist?.proxy, input.stagingDirectory, { stripProxyWrappers: true })\n : undefined;\n if (upstream) {\n droppedServers.push(...upstream.dropped);\n // The repository's mcp-config.yaml belongs to the repository layer.\n await claim(upstream.kept, repositoryScope, 'upstream', upstreamPath!);\n }\n\n return {\n shared: {\n configSources: upstream ? [upstream.source] : [],\n configPaths: upstream ? [upstream.source.path] : [],\n serverNames: upstream ? upstream.kept : [],\n },\n // A later layer overriding an earlier one contributes the same name twice.\n sessionLocal: {\n configSources,\n configPaths: configSources.map((source) => source.path),\n serverNames: [...new Set(serverNames)],\n },\n droppedServers: [...new Set(droppedServers)],\n diagnostics,\n serverScopes,\n serverOrigins,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { PoOAuthRedirect } from '@agimon-ai/po-core/packageApi';\nimport type {\n ConfigSource,\n McpClientManagerAuthOptions,\n McpOutputSchemaWarning,\n McpSecretTarget,\n McpServerStateChange,\n McpToolInfo,\n OAuthCallbackSink,\n SharedServices,\n TokenStore,\n} from '@agimon-ai/po-mcp-proxy';\nimport mcpProxyPackage from '@agimon-ai/po-mcp-proxy/package.json' with { type: 'json' };\n\nimport type { McpConfigSource } from '../../types/mcpConfig';\nimport type { CachedCatalog } from '../../types/mcpRuntime';\n\n/**\n * Presents the hub's redirect surface as the proxy's callback collaborator.\n *\n * `listen` binds nothing: the hub already serves the address this advertises,\n * so opening a loopback port would only create one nobody redirects to.\n */\nexport function hubCallbackSink(redirect: PoOAuthRedirect): OAuthCallbackSink {\n return {\n redirectUri: () => redirect.redirectUri,\n getPort: () => undefined,\n listen: (preferredPort) => Promise.resolve(preferredPort),\n reserve: (state, timeoutMs) => redirect.reserve(state, timeoutMs),\n waitForCallback: (state, timeoutMs) => redirect.wait(state, timeoutMs),\n cancel: (state) => redirect.cancel(state),\n };\n}\n\nexport interface McpRuntimeOptions {\n /** Ordered config layers. Later layers override earlier ones. */\n configSources: McpConfigSource[];\n workspaceRoot?: string;\n /** Only an explicit session-only server add may start without file sources. */\n allowEmpty?: boolean;\n /** Exact session directory, independent of the checkout used for configuration. */\n executionCwd?: string;\n environment?: Readonly<Record<string, string | undefined>>;\n /**\n * Required: without one the proxy would fall back to its own file store under\n * `~/.mcp-proxy`, and Po keeps credentials only in the vault or in memory.\n */\n tokenStore: TokenStore;\n /**\n * Where OAuth redirects are received. Omitted, the proxy binds its own\n * loopback listener, which only a browser on this machine can reach.\n */\n callbackServer?: OAuthCallbackSink;\n /** Resolves `${vault:NAME}` references at connect time. Without it, every reference fails its connection. */\n resolveSecret?: (target: McpSecretTarget) => Promise<string | undefined>;\n resolveUrlCredentials?: McpClientManagerAuthOptions['resolveUrlCredentials'];\n onAuthorizationUrl?: (url: URL, serverName: string) => void;\n onServerStateChange?: (change: McpServerStateChange) => void;\n onOutputSchemaWarning?: (warning: McpOutputSchemaWarning) => void;\n}\n\nexport interface McpRuntimeHandle {\n generation: number;\n services: SharedServices;\n /** Resolves once the first connection pass settles. Never rejects. */\n connectionsSettled: Promise<void>;\n}\n\nconst MCP_APP_CLIENT_CAPABILITIES = {\n extensions: { 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html;profile=mcp-app', 'text/html+skybridge'] } },\n};\n\ninterface DefinitionsCacheFile {\n oneMcpVersion?: string;\n servers?: Record<string, { serverName: string; tools?: McpToolInfo[] }>;\n}\n\n/**\n * Definitions cache path shared by Po's synchronous warm reader and mcp-proxy.\n *\n * Generated staging paths are deliberately absent: projected source content must\n * invalidate a reused path, while identical portable content must survive a new\n * private staging directory. Stable source origins are carried inside each cache\n * key; format and merge behavior remain part of the ordered identity.\n */\nexport function definitionsCachePath(configSources: readonly McpConfigSource[]): string {\n if (configSources.length === 0) throw new Error('definitionsCachePath requires at least one config source');\n const digest = createHash('sha256')\n .update(\n JSON.stringify(\n configSources.map((source) => ({\n cacheKey: source.cacheKey,\n format: source.format,\n optional: source.optional ?? false,\n mergeStrategy: source.mergeStrategy ?? 'remote-priority',\n })),\n ),\n )\n .update('\\0')\n .update(mcpProxyPackage.version)\n .update('\\0')\n .update(JSON.stringify(MCP_APP_CLIENT_CAPABILITIES))\n .digest('hex');\n return join(homedir(), '.mcp-proxy', `po-${digest}.definitions-cache.json`);\n}\n\n/**\n * Reads the catalog the previous run left behind.\n *\n * Callers await the cache before registering tools. A miss is normal on a first\n * run and resolves to an empty catalog rather than an error.\n *\n * The file path is content-addressed from the current ordered layers, and its proxy\n * version is checked before any schema is registered. Servers filtered out of the\n * current configuration are also excluded later by `McpCatalog.seed`.\n */\nexport async function readCachedCatalog(\n configSources: readonly McpConfigSource[],\n cachePathFor: (sources: readonly McpConfigSource[]) => string = definitionsCachePath,\n): Promise<CachedCatalog> {\n if (configSources.length === 0) return { servers: [] };\n try {\n const cachePath = cachePathFor(configSources);\n const cache = JSON.parse(await readFile(cachePath, 'utf8')) as Partial<DefinitionsCacheFile>;\n if (cache.oneMcpVersion !== mcpProxyPackage.version) return { servers: [] };\n const servers = Object.values(cache.servers ?? {}).map((server) => ({\n name: server.serverName,\n tools: server.tools ?? [],\n }));\n return { servers };\n } catch {\n return { servers: [] };\n }\n}\n\nfunction toProxyConfigSource(source: McpConfigSource): ConfigSource {\n return {\n path: source.path,\n format: source.format,\n ...(source.optional === undefined ? {} : { optional: source.optional }),\n ...(source.mergeStrategy === undefined ? {} : { mergeStrategy: source.mergeStrategy }),\n };\n}\n\n/**\n * Owns the one live mcp-proxy container for this extension.\n *\n * Pi reloads extensions in process, so a connect that lands after a session restart\n * or a `/domains` switch would otherwise fold tools into a dead context. Every start\n * takes the next generation; anything an older generation produces is dropped and its\n * container disposed.\n */\nexport class McpRuntimeOwner {\n private generation = 0;\n private active: SharedServices | undefined;\n private unsubscribe: (() => void) | undefined;\n\n get currentGeneration(): number {\n return this.generation;\n }\n\n /** The live container, or undefined before the first start and after dispose. */\n getServices(): SharedServices | undefined {\n return this.active;\n }\n\n /**\n * Whether a container a caller captured earlier is still the live one.\n *\n * An async continuation that started under one container has to check this\n * before writing its result, or a `/domains` switch would fold stale tools into\n * the new session.\n */\n isCurrent(services: SharedServices | undefined): boolean {\n return services !== undefined && services === this.active;\n }\n\n /**\n * Starts a container for the current configuration, replacing any predecessor.\n *\n * Returns undefined when a newer generation started while this one was building,\n * which is the signal for the caller to abandon its half-finished work.\n */\n async start(options: McpRuntimeOptions): Promise<McpRuntimeHandle | undefined> {\n if (!options.tokenStore) throw new Error('The MCP runtime needs a token store.');\n const generation = ++this.generation;\n // Retired before the replacement is built so two containers never hold the same\n // stdio children open at once.\n await this.retire();\n if (options.configSources.length === 0 && !options.allowEmpty) return undefined;\n\n // The proxy container pulls in transports, OAuth, schema conversion, and\n // server implementations. Cached tool registration needs none of those, so\n // load the runtime only after session_start has yielded control to Pi.\n const { createProxyContainer } = await import('@agimon-ai/po-mcp-proxy');\n const cachePath = options.configSources.length > 0 ? definitionsCachePath(options.configSources) : undefined;\n const containerOptions = {\n configSources: options.configSources.map(toProxyConfigSource),\n workspaceRoot: options.workspaceRoot,\n executionCwd: options.executionCwd,\n environment: options.environment,\n definitionsCachePath: cachePath,\n // Never blocking: an unreachable server must not delay Pi's first prompt.\n startupMode: 'background' as const,\n clientCapabilities: MCP_APP_CLIENT_CAPABILITIES,\n outputSchemaValidation: {\n mode: 'warn' as const,\n onWarning: (warning: McpOutputSchemaWarning) => {\n if (generation === this.generation) options.onOutputSchemaWarning?.(warning);\n },\n },\n auth: {\n tokenStore: options.tokenStore,\n onAuthorizationUrl: options.onAuthorizationUrl,\n ...(options.callbackServer ? { callbackServer: options.callbackServer } : {}),\n ...(options.resolveSecret ? { resolveSecret: options.resolveSecret } : {}),\n ...(options.resolveUrlCredentials ? { resolveUrlCredentials: options.resolveUrlCredentials } : {}),\n },\n };\n const services = await createProxyContainer(containerOptions);\n\n if (generation !== this.generation) {\n await services.dispose();\n return undefined;\n }\n\n this.active = services;\n const forward = options.onServerStateChange;\n if (forward) {\n this.unsubscribe = services.clientManager.onServerStateChange((change) => {\n if (generation === this.generation) forward(change);\n });\n }\n\n return { generation, services, connectionsSettled: services.connectionsSettled };\n }\n\n /** Tears the container down and invalidates every generation still in flight. */\n async dispose(): Promise<void> {\n ++this.generation;\n await this.retire();\n }\n\n private async retire(): Promise<void> {\n this.unsubscribe?.();\n this.unsubscribe = undefined;\n const services = this.active;\n this.active = undefined;\n // A failed teardown must not leave the owner believing a dead container is live.\n if (services) await services.dispose();\n }\n}\n","import path from 'node:path';\n\nimport { PO_MCP_SESSION_ENV_VAR, poMcpSessionEnvironment, readPoMcpSessionConfig } from '@agimon-ai/po-core/mcpSession';\n\nimport type { McpAllowlist, McpSessionConfig } from '../../types/mcpConfig';\n\nfunction asStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const strings = value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);\n return strings.length > 0 ? strings : undefined;\n}\n\nfunction readAllowlist(value: unknown): McpAllowlist | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const { servers, proxy } = value as { servers?: unknown; proxy?: unknown };\n const allowlist: McpAllowlist = {};\n const allowedServers = asStringArray(servers);\n const allowedProxy = asStringArray(proxy);\n if (allowedServers) allowlist.servers = allowedServers;\n if (allowedProxy) allowlist.proxy = allowedProxy;\n return allowlist.servers || allowlist.proxy ? allowlist : undefined;\n}\n\n/**\n * Resolves what this session should connect to.\n *\n * Every field falls back to a working default so the extension is usable outside\n * po: a bare Pi session in a repository still gets that repository's\n * `.mcp.json` with no allowlist. A malformed value is treated as absent rather\n * than fatal, because losing MCP is better than losing the session.\n */\nexport function readSessionConfig(\n env: Readonly<Record<string, string | undefined>>,\n defaultRepoRoot: string,\n defaultStagingDirectory: string = path.join(defaultRepoRoot, '.po', 'mcp'),\n): McpSessionConfig {\n const fallback: McpSessionConfig = {\n repoRoot: defaultRepoRoot,\n stagingDirectory: defaultStagingDirectory,\n };\n\n const strict = readPoMcpSessionConfig(env);\n if (strict) {\n const { allowlist, pluginConfigPaths, ...required } = strict;\n const strictAllowlist = readAllowlist(allowlist);\n return {\n ...required,\n ...(pluginConfigPaths?.length ? { pluginConfigPaths: [...pluginConfigPaths] } : {}),\n ...(strictAllowlist ? { allowlist: strictAllowlist } : {}),\n };\n }\n\n const raw = env[PO_MCP_SESSION_ENV_VAR];\n if (!raw) return fallback;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return fallback;\n }\n if (typeof parsed !== 'object' || parsed === null) return fallback;\n\n const { repoRoot, generatedConfigPath, pluginConfigPaths, allowlist, stagingDirectory } = parsed as Record<\n string,\n unknown\n >;\n const resolvedRoot = typeof repoRoot === 'string' && repoRoot ? repoRoot : fallback.repoRoot;\n const generatedConfig =\n typeof generatedConfigPath === 'string' && generatedConfigPath ? generatedConfigPath : undefined;\n const plugins = asStringArray(pluginConfigPaths);\n const resolvedAllowlist = readAllowlist(allowlist);\n const staging =\n typeof stagingDirectory === 'string' && stagingDirectory ? stagingDirectory : fallback.stagingDirectory;\n\n return {\n repoRoot: resolvedRoot,\n stagingDirectory: staging,\n ...(generatedConfig ? { generatedConfigPath: generatedConfig } : {}),\n ...(plugins ? { pluginConfigPaths: plugins } : {}),\n ...(resolvedAllowlist ? { allowlist: resolvedAllowlist } : {}),\n };\n}\n\n/** Serializes the configuration for the Pi child process po launches. */\nexport function sessionConfigEnvironment(config: McpSessionConfig): Record<string, string> {\n return poMcpSessionEnvironment(config);\n}\n","/** Environment variable carrying a child agent's MCP tool selection. */\nexport const DIRECT_TOOLS_ENV = 'MCP_DIRECT_TOOLS';\n\n/** Explicit \"no MCP tools\", distinct from an unset variable meaning \"no limit\". */\nexport const NO_DIRECT_TOOLS = '__none__';\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_mcpCatalog = require("./mcpCatalog-
|
|
2
|
+
const require_mcpCatalog = require("./mcpCatalog-D6eVhMcK.cjs");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_fs_promises = require("node:fs/promises");
|
|
5
5
|
node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises, 1);
|
|
@@ -12,9 +12,6 @@ let _agimon_ai_po_mcp_proxy_package_json = require("@agimon-ai/po-mcp-proxy/pack
|
|
|
12
12
|
_agimon_ai_po_mcp_proxy_package_json = require_rolldown_runtime.__toESM(_agimon_ai_po_mcp_proxy_package_json, 1);
|
|
13
13
|
let _agimon_ai_po_core_mcpSession = require("@agimon-ai/po-core/mcpSession");
|
|
14
14
|
//#region src/services/configSources/index.ts
|
|
15
|
-
/** Wrapper entry used by non-Po clients to expose `mcp-config.yaml` as one MCP. */
|
|
16
|
-
const PROXY_SERVER_NAME = "mcp-proxy";
|
|
17
|
-
const PROXY_SERVER_ALIASES = /* @__PURE__ */ new Set([PROXY_SERVER_NAME, "agiflow-proxy"]);
|
|
18
15
|
const PRIVATE_FILE_MODE = 384;
|
|
19
16
|
const PRIVATE_DIRECTORY_MODE = 448;
|
|
20
17
|
const DEFAULT_UPSTREAM_CONFIG = "mcp-config.yaml";
|
|
@@ -47,9 +44,6 @@ function serverDefinitions(config) {
|
|
|
47
44
|
function isEnabledDefinition(definition) {
|
|
48
45
|
return !isObject(definition) || definition.disabled !== true;
|
|
49
46
|
}
|
|
50
|
-
function isProxyWrapper(name) {
|
|
51
|
-
return PROXY_SERVER_ALIASES.has(name);
|
|
52
|
-
}
|
|
53
47
|
/**
|
|
54
48
|
* Resolves the upstream config referenced by the repository proxy wrapper.
|
|
55
49
|
*
|
|
@@ -59,7 +53,7 @@ function isProxyWrapper(name) {
|
|
|
59
53
|
*/
|
|
60
54
|
async function resolveSharedConfigPathFrom(repoRoot, repositoryConfigPath) {
|
|
61
55
|
const servers = serverDefinitions(await readConfigObject(repositoryConfigPath));
|
|
62
|
-
const rawArgs = [...PROXY_SERVER_ALIASES].map((name) => servers[name]).find((definition) => isObject(definition))?.args;
|
|
56
|
+
const rawArgs = [...require_mcpCatalog.PROXY_SERVER_ALIASES].map((name) => servers[name]).find((definition) => isObject(definition))?.args;
|
|
63
57
|
const args = Array.isArray(rawArgs) ? rawArgs : [];
|
|
64
58
|
const configArgumentIndex = args.indexOf(CONFIG_ARGUMENT);
|
|
65
59
|
const declared = args[configArgumentIndex + 1];
|
|
@@ -103,7 +97,7 @@ async function filterLayer(filePath, allowed, stagingDirectory, options) {
|
|
|
103
97
|
const servers = serverDefinitions(config);
|
|
104
98
|
const kept = {};
|
|
105
99
|
const dropped = [];
|
|
106
|
-
for (const [name, definition] of Object.entries(servers)) if (options.stripProxyWrappers && isProxyWrapper(name) || !isAllowed(name, allowed)) dropped.push(name);
|
|
100
|
+
for (const [name, definition] of Object.entries(servers)) if (options.stripProxyWrappers && require_mcpCatalog.isProxyWrapper(name) || !isAllowed(name, allowed)) dropped.push(name);
|
|
107
101
|
else kept[name] = definition;
|
|
108
102
|
const keptNames = Object.entries(kept).filter(([, definition]) => isEnabledDefinition(definition)).map(([name]) => name);
|
|
109
103
|
if (dropped.length === 0) return {
|
|
@@ -519,12 +513,6 @@ Object.defineProperty(exports, "NO_DIRECT_TOOLS", {
|
|
|
519
513
|
return NO_DIRECT_TOOLS;
|
|
520
514
|
}
|
|
521
515
|
});
|
|
522
|
-
Object.defineProperty(exports, "PROXY_SERVER_NAME", {
|
|
523
|
-
enumerable: true,
|
|
524
|
-
get: function() {
|
|
525
|
-
return PROXY_SERVER_NAME;
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
516
|
Object.defineProperty(exports, "buildMcpConfigGroups", {
|
|
529
517
|
enumerable: true,
|
|
530
518
|
get: function() {
|
|
@@ -543,12 +531,6 @@ Object.defineProperty(exports, "hubCallbackSink", {
|
|
|
543
531
|
return hubCallbackSink;
|
|
544
532
|
}
|
|
545
533
|
});
|
|
546
|
-
Object.defineProperty(exports, "isProxyWrapper", {
|
|
547
|
-
enumerable: true,
|
|
548
|
-
get: function() {
|
|
549
|
-
return isProxyWrapper;
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
534
|
Object.defineProperty(exports, "mcpRuntime_exports", {
|
|
553
535
|
enumerable: true,
|
|
554
536
|
get: function() {
|
|
@@ -574,4 +556,4 @@ Object.defineProperty(exports, "sessionConfigEnvironment", {
|
|
|
574
556
|
}
|
|
575
557
|
});
|
|
576
558
|
|
|
577
|
-
//# sourceMappingURL=directTools-
|
|
559
|
+
//# sourceMappingURL=directTools-hv4kxZeY.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directTools--0HFuomq.mjs","names":["parseYaml","stringifyYaml"],"sources":["../src/services/configSources/index.ts","../src/services/mcpRuntime/index.ts","../src/services/sessionConfig/index.ts","../src/schemas/directTools.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { normalizeAgentPluginMcpSource } from '@agimon-ai/po-config/agentPluginMcp';\nimport type { PoMcpNativeProjectionSource } from '@agimon-ai/po-core/mcpProjection';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport type { McpConfigGroups, McpConfigGroupsInput, McpConfigSource, McpServerOrigin } from '../../types/mcpConfig';\nimport { pluginPathMcpScope, projectedSourceMcpScope, repositoryMcpScope } from '../mcpScope';\n\n/** Wrapper entry used by non-Po clients to expose `mcp-config.yaml` as one MCP. */\nexport const PROXY_SERVER_NAME = 'mcp-proxy';\n\nconst PROXY_SERVER_ALIASES = new Set([PROXY_SERVER_NAME, 'agiflow-proxy']);\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst DEFAULT_UPSTREAM_CONFIG = 'mcp-config.yaml';\nconst CONFIG_ARGUMENT = '--config';\n\ntype JsonObject = Record<string, unknown>;\n\ninterface FilteredLayer {\n source: McpConfigSource;\n kept: string[];\n dropped: string[];\n}\n\ninterface ConfigDocument {\n config: JsonObject;\n contents: string;\n}\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isYamlPath(filePath: string): boolean {\n const extension = path.extname(filePath).toLowerCase();\n return extension === '.yaml' || extension === '.yml';\n}\n\nasync function readConfigDocument(filePath: string): Promise<ConfigDocument | undefined> {\n try {\n const contents = await fs.readFile(filePath, 'utf8');\n const parsed: unknown = isYamlPath(filePath) ? parseYaml(contents) : JSON.parse(contents);\n return isObject(parsed) ? { config: parsed, contents } : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readConfigObject(filePath: string): Promise<JsonObject | undefined> {\n return (await readConfigDocument(filePath))?.config;\n}\n\nfunction serverDefinitions(config: JsonObject | undefined): Record<string, unknown> {\n return isObject(config?.mcpServers) ? config.mcpServers : {};\n}\n\nfunction isEnabledDefinition(definition: unknown): boolean {\n return !isObject(definition) || definition.disabled !== true;\n}\n\nexport function isProxyWrapper(name: string): boolean {\n return PROXY_SERVER_ALIASES.has(name);\n}\n\n/**\n * Resolves the upstream config referenced by the repository proxy wrapper.\n *\n * The wrapper remains useful to Claude, Codex, and other external clients. Po\n * embeds the same client/runtime code, so it reads this path and connects each\n * declared server itself instead of starting the wrapper as a nested MCP.\n */\nasync function resolveSharedConfigPathFrom(\n repoRoot: string,\n repositoryConfigPath: string,\n): Promise<string | undefined> {\n const servers = serverDefinitions(await readConfigObject(repositoryConfigPath));\n const proxy = [...PROXY_SERVER_ALIASES]\n .map((name) => servers[name])\n .find((definition): definition is JsonObject => isObject(definition));\n const rawArgs: unknown = proxy?.args;\n const args = Array.isArray(rawArgs) ? (rawArgs as unknown[]) : [];\n const configArgumentIndex = args.indexOf(CONFIG_ARGUMENT);\n const declared = args[configArgumentIndex + 1];\n const candidate =\n configArgumentIndex >= 0 && typeof declared === 'string'\n ? path.resolve(repoRoot, declared)\n : path.join(repoRoot, DEFAULT_UPSTREAM_CONFIG);\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveSharedConfigPath(repoRoot: string): Promise<string | undefined> {\n return resolveSharedConfigPathFrom(repoRoot, path.join(repoRoot, '.mcp.json'));\n}\n\n/** Empty and absent allowlists both mean \"keep everything\". */\nfunction isAllowed(name: string, allowed: string[] | undefined): boolean {\n return !allowed || allowed.length === 0 || allowed.includes(name);\n}\n\nfunction stagedPath(filePath: string, contents: string, stagingDirectory: string): string {\n // The filtered bytes are part of the identity because two live sessions can\n // select different domains. Sharing a path would let the later one rewrite the\n // configuration underneath the first one's deferred startup.\n const digest = createHash('sha256').update(filePath).update('\\0').update(contents).digest('hex').slice(0, 16);\n const extension = isYamlPath(filePath) ? '.yaml' : '.json';\n return path.join(stagingDirectory, `mcp-${digest}${extension}`);\n}\n\nfunction serializeConfig(filePath: string, config: JsonObject): string {\n return isYamlPath(filePath) ? stringifyYaml(config) : `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nasync function layerCacheKey(\n filePath: string,\n format: McpConfigSource['format'],\n originalContents: string,\n effectiveContents: string,\n sourceIdentity?: string,\n): Promise<string> {\n return createHash('sha256')\n .update(format)\n .update('\\0')\n .update(await fs.realpath(filePath))\n .update('\\0')\n .update(sourceIdentity ?? 'unprojected')\n .update('\\0')\n .update(originalContents)\n .update('\\0')\n .update(effectiveContents)\n .digest('hex');\n}\n\n/**\n * Rewrites one config layer with disallowed servers removed.\n *\n * Proxy wrapper entries are stripped from `.mcp.json` layers because Po reaches\n * their upstream config directly. Entries are removed rather than marked disabled,\n * so a filtered stdio server is never spawned at all.\n */\nasync function filterLayer(\n filePath: string,\n allowed: string[] | undefined,\n stagingDirectory: string,\n options: { stripProxyWrappers: boolean; sourceIdentity?: string },\n): Promise<FilteredLayer | undefined> {\n const document = await readConfigDocument(filePath);\n if (!document) return undefined;\n const { config, contents: originalContents } = document;\n const servers = serverDefinitions(config);\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n\n for (const [name, definition] of Object.entries(servers)) {\n const shouldDrop = (options.stripProxyWrappers && isProxyWrapper(name)) || !isAllowed(name, allowed);\n if (shouldDrop) dropped.push(name);\n else kept[name] = definition;\n }\n\n const keptNames = Object.entries(kept)\n .filter(([, definition]) => isEnabledDefinition(definition))\n .map(([name]) => name);\n if (dropped.length === 0) {\n return {\n source: {\n path: filePath,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, originalContents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n }\n\n await fs.mkdir(stagingDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const contents = serializeConfig(filePath, { ...config, mcpServers: kept });\n const target = stagedPath(filePath, contents, stagingDirectory);\n await fs.writeFile(target, contents, { mode: PRIVATE_FILE_MODE });\n return {\n source: {\n path: target,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, contents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n}\n\nasync function digestMatches(source: PoMcpNativeProjectionSource): Promise<boolean> {\n try {\n const digest = createHash('sha256')\n .update(await fs.readFile(source.configPath))\n .digest('hex');\n return digest === source.contentDigest;\n } catch {\n return false;\n }\n}\n\nfunction emptyGroups(diagnostics: string[] = []): McpConfigGroups {\n return {\n shared: { configSources: [], configPaths: [], serverNames: [] },\n sessionLocal: { configSources: [], configPaths: [], serverNames: [] },\n droppedServers: [],\n diagnostics,\n serverScopes: {},\n };\n}\n\n/**\n * Resolves every config layer for this session and applies its domain allowlist.\n *\n * All returned layers go into one embedded `@agimon-ai/po-mcp-proxy` client container.\n * The package is used as a library only: its wrapper MCP never becomes a Po MCP\n * server, so status, enable/disable, resources, and OAuth stay attached to each\n * actual downstream server.\n */\nexport async function buildMcpConfigGroups(input: McpConfigGroupsInput): Promise<\n McpConfigGroups & {\n /** Internal only. Paths and revisions must not be forwarded as browser ownership claims. */\n serverOrigins?: Record<string, McpServerOrigin>;\n }\n> {\n if (input.enabled === false) return emptyGroups();\n\n const projectedSources = input.sources;\n const repositoryScope = await repositoryMcpScope(input.repoRoot);\n const legacyLayers = projectedSources\n ? []\n : [\n { path: path.join(input.repoRoot, '.mcp.json'), scope: repositoryScope },\n ...(input.pluginConfigPaths ?? []).map((candidate) => {\n const resolved = path.resolve(input.repoRoot, candidate);\n return { path: resolved, scope: pluginPathMcpScope(resolved) };\n }),\n ];\n // Walked in container order, sessionLocal then shared, so the layer that wins a name owns its credential.\n const serverScopes: Record<string, string> = {};\n const serverOrigins: Record<string, McpServerOrigin> = {};\n const claim = async (\n names: readonly string[],\n scope: string,\n owner: McpServerOrigin['owner'],\n filePath: string,\n sourceId?: string,\n ) => {\n const definitions = serverDefinitions(await readConfigObject(filePath));\n for (const name of names) {\n serverScopes[name] = scope;\n serverOrigins[name] = {\n owner,\n path: filePath,\n revision: createHash('sha256')\n .update(JSON.stringify(definitions[name]) ?? 'undefined')\n .digest('hex'),\n ...(sourceId === undefined ? {} : { sourceId }),\n };\n }\n };\n\n const configSources: McpConfigSource[] = [];\n const serverNames: string[] = [];\n const droppedServers: string[] = [];\n const diagnostics: string[] = [];\n for (const layer of legacyLayers) {\n const filtered = await filterLayer(layer.path, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n });\n if (!filtered) continue;\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n layer.scope,\n layer.path === path.join(input.repoRoot, '.mcp.json') ? 'repository' : 'plugin',\n layer.path,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n for (const source of projectedSources ?? []) {\n if (source.format === 'agent-plugin-v1') {\n const normalized = normalizeAgentPluginMcpSource(source, {\n stagingDirectory: input.stagingDirectory,\n allowedServers: input.allowlist?.servers,\n });\n if (normalized.configSource) configSources.push(normalized.configSource);\n serverNames.push(...normalized.serverNames);\n await claim(\n normalized.serverNames,\n await projectedSourceMcpScope(source, input.repoRoot),\n 'plugin',\n normalized.configSource?.path ?? source.configPath,\n source.sourceId,\n );\n droppedServers.push(...normalized.droppedServers);\n diagnostics.push(...normalized.diagnostics);\n continue;\n }\n\n if (!(await digestMatches(source))) {\n diagnostics.push(\n `Native MCP source \"${source.sourceId}\" was disabled: the file is missing or its content digest changed.`,\n );\n continue;\n }\n const filtered = await filterLayer(source.configPath, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n sourceIdentity: `${source.sourceId}:${source.contentDigest}`,\n });\n if (!filtered) {\n diagnostics.push(`Native MCP source \"${source.sourceId}\" was disabled: the config could not be parsed.`);\n continue;\n }\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n await projectedSourceMcpScope(source, input.repoRoot),\n source.owner === 'user' ? 'user' : source.owner === 'repository' ? 'repository' : 'plugin',\n source.configPath,\n source.sourceId,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n const repositorySource = projectedSources?.find(\n (source): source is PoMcpNativeProjectionSource => source.format === 'native' && source.owner === 'repository',\n );\n const upstreamPath = projectedSources\n ? repositorySource && (await digestMatches(repositorySource))\n ? await resolveSharedConfigPathFrom(input.repoRoot, repositorySource.configPath)\n : undefined\n : await resolveSharedConfigPath(input.repoRoot);\n const upstream = upstreamPath\n ? await filterLayer(upstreamPath, input.allowlist?.proxy, input.stagingDirectory, { stripProxyWrappers: true })\n : undefined;\n if (upstream) {\n droppedServers.push(...upstream.dropped);\n // The repository's mcp-config.yaml belongs to the repository layer.\n await claim(upstream.kept, repositoryScope, 'upstream', upstreamPath!);\n }\n\n return {\n shared: {\n configSources: upstream ? [upstream.source] : [],\n configPaths: upstream ? [upstream.source.path] : [],\n serverNames: upstream ? upstream.kept : [],\n },\n // A later layer overriding an earlier one contributes the same name twice.\n sessionLocal: {\n configSources,\n configPaths: configSources.map((source) => source.path),\n serverNames: [...new Set(serverNames)],\n },\n droppedServers: [...new Set(droppedServers)],\n diagnostics,\n serverScopes,\n serverOrigins,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { PoOAuthRedirect } from '@agimon-ai/po-core/packageApi';\nimport type {\n ConfigSource,\n McpClientManagerAuthOptions,\n McpOutputSchemaWarning,\n McpSecretTarget,\n McpServerStateChange,\n McpToolInfo,\n OAuthCallbackSink,\n SharedServices,\n TokenStore,\n} from '@agimon-ai/po-mcp-proxy';\nimport mcpProxyPackage from '@agimon-ai/po-mcp-proxy/package.json' with { type: 'json' };\n\nimport type { McpConfigSource } from '../../types/mcpConfig';\nimport type { CachedCatalog } from '../../types/mcpRuntime';\n\n/**\n * Presents the hub's redirect surface as the proxy's callback collaborator.\n *\n * `listen` binds nothing: the hub already serves the address this advertises,\n * so opening a loopback port would only create one nobody redirects to.\n */\nexport function hubCallbackSink(redirect: PoOAuthRedirect): OAuthCallbackSink {\n return {\n redirectUri: () => redirect.redirectUri,\n getPort: () => undefined,\n listen: (preferredPort) => Promise.resolve(preferredPort),\n reserve: (state, timeoutMs) => redirect.reserve(state, timeoutMs),\n waitForCallback: (state, timeoutMs) => redirect.wait(state, timeoutMs),\n cancel: (state) => redirect.cancel(state),\n };\n}\n\nexport interface McpRuntimeOptions {\n /** Ordered config layers. Later layers override earlier ones. */\n configSources: McpConfigSource[];\n workspaceRoot?: string;\n /** Only an explicit session-only server add may start without file sources. */\n allowEmpty?: boolean;\n /** Exact session directory, independent of the checkout used for configuration. */\n executionCwd?: string;\n environment?: Readonly<Record<string, string | undefined>>;\n /**\n * Required: without one the proxy would fall back to its own file store under\n * `~/.mcp-proxy`, and Po keeps credentials only in the vault or in memory.\n */\n tokenStore: TokenStore;\n /**\n * Where OAuth redirects are received. Omitted, the proxy binds its own\n * loopback listener, which only a browser on this machine can reach.\n */\n callbackServer?: OAuthCallbackSink;\n /** Resolves `${vault:NAME}` references at connect time. Without it, every reference fails its connection. */\n resolveSecret?: (target: McpSecretTarget) => Promise<string | undefined>;\n resolveUrlCredentials?: McpClientManagerAuthOptions['resolveUrlCredentials'];\n onAuthorizationUrl?: (url: URL, serverName: string) => void;\n onServerStateChange?: (change: McpServerStateChange) => void;\n onOutputSchemaWarning?: (warning: McpOutputSchemaWarning) => void;\n}\n\nexport interface McpRuntimeHandle {\n generation: number;\n services: SharedServices;\n /** Resolves once the first connection pass settles. Never rejects. */\n connectionsSettled: Promise<void>;\n}\n\nconst MCP_APP_CLIENT_CAPABILITIES = {\n extensions: { 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html;profile=mcp-app', 'text/html+skybridge'] } },\n};\n\ninterface DefinitionsCacheFile {\n oneMcpVersion?: string;\n servers?: Record<string, { serverName: string; tools?: McpToolInfo[] }>;\n}\n\n/**\n * Definitions cache path shared by Po's synchronous warm reader and mcp-proxy.\n *\n * Generated staging paths are deliberately absent: projected source content must\n * invalidate a reused path, while identical portable content must survive a new\n * private staging directory. Stable source origins are carried inside each cache\n * key; format and merge behavior remain part of the ordered identity.\n */\nexport function definitionsCachePath(configSources: readonly McpConfigSource[]): string {\n if (configSources.length === 0) throw new Error('definitionsCachePath requires at least one config source');\n const digest = createHash('sha256')\n .update(\n JSON.stringify(\n configSources.map((source) => ({\n cacheKey: source.cacheKey,\n format: source.format,\n optional: source.optional ?? false,\n mergeStrategy: source.mergeStrategy ?? 'remote-priority',\n })),\n ),\n )\n .update('\\0')\n .update(mcpProxyPackage.version)\n .update('\\0')\n .update(JSON.stringify(MCP_APP_CLIENT_CAPABILITIES))\n .digest('hex');\n return join(homedir(), '.mcp-proxy', `po-${digest}.definitions-cache.json`);\n}\n\n/**\n * Reads the catalog the previous run left behind.\n *\n * Callers await the cache before registering tools. A miss is normal on a first\n * run and resolves to an empty catalog rather than an error.\n *\n * The file path is content-addressed from the current ordered layers, and its proxy\n * version is checked before any schema is registered. Servers filtered out of the\n * current configuration are also excluded later by `McpCatalog.seed`.\n */\nexport async function readCachedCatalog(\n configSources: readonly McpConfigSource[],\n cachePathFor: (sources: readonly McpConfigSource[]) => string = definitionsCachePath,\n): Promise<CachedCatalog> {\n if (configSources.length === 0) return { servers: [] };\n try {\n const cachePath = cachePathFor(configSources);\n const cache = JSON.parse(await readFile(cachePath, 'utf8')) as Partial<DefinitionsCacheFile>;\n if (cache.oneMcpVersion !== mcpProxyPackage.version) return { servers: [] };\n const servers = Object.values(cache.servers ?? {}).map((server) => ({\n name: server.serverName,\n tools: server.tools ?? [],\n }));\n return { servers };\n } catch {\n return { servers: [] };\n }\n}\n\nfunction toProxyConfigSource(source: McpConfigSource): ConfigSource {\n return {\n path: source.path,\n format: source.format,\n ...(source.optional === undefined ? {} : { optional: source.optional }),\n ...(source.mergeStrategy === undefined ? {} : { mergeStrategy: source.mergeStrategy }),\n };\n}\n\n/**\n * Owns the one live mcp-proxy container for this extension.\n *\n * Pi reloads extensions in process, so a connect that lands after a session restart\n * or a `/domains` switch would otherwise fold tools into a dead context. Every start\n * takes the next generation; anything an older generation produces is dropped and its\n * container disposed.\n */\nexport class McpRuntimeOwner {\n private generation = 0;\n private active: SharedServices | undefined;\n private unsubscribe: (() => void) | undefined;\n\n get currentGeneration(): number {\n return this.generation;\n }\n\n /** The live container, or undefined before the first start and after dispose. */\n getServices(): SharedServices | undefined {\n return this.active;\n }\n\n /**\n * Whether a container a caller captured earlier is still the live one.\n *\n * An async continuation that started under one container has to check this\n * before writing its result, or a `/domains` switch would fold stale tools into\n * the new session.\n */\n isCurrent(services: SharedServices | undefined): boolean {\n return services !== undefined && services === this.active;\n }\n\n /**\n * Starts a container for the current configuration, replacing any predecessor.\n *\n * Returns undefined when a newer generation started while this one was building,\n * which is the signal for the caller to abandon its half-finished work.\n */\n async start(options: McpRuntimeOptions): Promise<McpRuntimeHandle | undefined> {\n if (!options.tokenStore) throw new Error('The MCP runtime needs a token store.');\n const generation = ++this.generation;\n // Retired before the replacement is built so two containers never hold the same\n // stdio children open at once.\n await this.retire();\n if (options.configSources.length === 0 && !options.allowEmpty) return undefined;\n\n // The proxy container pulls in transports, OAuth, schema conversion, and\n // server implementations. Cached tool registration needs none of those, so\n // load the runtime only after session_start has yielded control to Pi.\n const { createProxyContainer } = await import('@agimon-ai/po-mcp-proxy');\n const cachePath = options.configSources.length > 0 ? definitionsCachePath(options.configSources) : undefined;\n const containerOptions = {\n configSources: options.configSources.map(toProxyConfigSource),\n workspaceRoot: options.workspaceRoot,\n executionCwd: options.executionCwd,\n environment: options.environment,\n definitionsCachePath: cachePath,\n // Never blocking: an unreachable server must not delay Pi's first prompt.\n startupMode: 'background' as const,\n clientCapabilities: MCP_APP_CLIENT_CAPABILITIES,\n outputSchemaValidation: {\n mode: 'warn' as const,\n onWarning: (warning: McpOutputSchemaWarning) => {\n if (generation === this.generation) options.onOutputSchemaWarning?.(warning);\n },\n },\n auth: {\n tokenStore: options.tokenStore,\n onAuthorizationUrl: options.onAuthorizationUrl,\n ...(options.callbackServer ? { callbackServer: options.callbackServer } : {}),\n ...(options.resolveSecret ? { resolveSecret: options.resolveSecret } : {}),\n ...(options.resolveUrlCredentials ? { resolveUrlCredentials: options.resolveUrlCredentials } : {}),\n },\n };\n const services = await createProxyContainer(containerOptions);\n\n if (generation !== this.generation) {\n await services.dispose();\n return undefined;\n }\n\n this.active = services;\n const forward = options.onServerStateChange;\n if (forward) {\n this.unsubscribe = services.clientManager.onServerStateChange((change) => {\n if (generation === this.generation) forward(change);\n });\n }\n\n return { generation, services, connectionsSettled: services.connectionsSettled };\n }\n\n /** Tears the container down and invalidates every generation still in flight. */\n async dispose(): Promise<void> {\n ++this.generation;\n await this.retire();\n }\n\n private async retire(): Promise<void> {\n this.unsubscribe?.();\n this.unsubscribe = undefined;\n const services = this.active;\n this.active = undefined;\n // A failed teardown must not leave the owner believing a dead container is live.\n if (services) await services.dispose();\n }\n}\n","import path from 'node:path';\n\nimport { PO_MCP_SESSION_ENV_VAR, poMcpSessionEnvironment, readPoMcpSessionConfig } from '@agimon-ai/po-core/mcpSession';\n\nimport type { McpAllowlist, McpSessionConfig } from '../../types/mcpConfig';\n\nfunction asStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const strings = value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);\n return strings.length > 0 ? strings : undefined;\n}\n\nfunction readAllowlist(value: unknown): McpAllowlist | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const { servers, proxy } = value as { servers?: unknown; proxy?: unknown };\n const allowlist: McpAllowlist = {};\n const allowedServers = asStringArray(servers);\n const allowedProxy = asStringArray(proxy);\n if (allowedServers) allowlist.servers = allowedServers;\n if (allowedProxy) allowlist.proxy = allowedProxy;\n return allowlist.servers || allowlist.proxy ? allowlist : undefined;\n}\n\n/**\n * Resolves what this session should connect to.\n *\n * Every field falls back to a working default so the extension is usable outside\n * po: a bare Pi session in a repository still gets that repository's\n * `.mcp.json` with no allowlist. A malformed value is treated as absent rather\n * than fatal, because losing MCP is better than losing the session.\n */\nexport function readSessionConfig(\n env: Readonly<Record<string, string | undefined>>,\n defaultRepoRoot: string,\n defaultStagingDirectory: string = path.join(defaultRepoRoot, '.po', 'mcp'),\n): McpSessionConfig {\n const fallback: McpSessionConfig = {\n repoRoot: defaultRepoRoot,\n stagingDirectory: defaultStagingDirectory,\n };\n\n const strict = readPoMcpSessionConfig(env);\n if (strict) {\n const { allowlist, pluginConfigPaths, ...required } = strict;\n const strictAllowlist = readAllowlist(allowlist);\n return {\n ...required,\n ...(pluginConfigPaths?.length ? { pluginConfigPaths: [...pluginConfigPaths] } : {}),\n ...(strictAllowlist ? { allowlist: strictAllowlist } : {}),\n };\n }\n\n const raw = env[PO_MCP_SESSION_ENV_VAR];\n if (!raw) return fallback;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return fallback;\n }\n if (typeof parsed !== 'object' || parsed === null) return fallback;\n\n const { repoRoot, generatedConfigPath, pluginConfigPaths, allowlist, stagingDirectory } = parsed as Record<\n string,\n unknown\n >;\n const resolvedRoot = typeof repoRoot === 'string' && repoRoot ? repoRoot : fallback.repoRoot;\n const generatedConfig =\n typeof generatedConfigPath === 'string' && generatedConfigPath ? generatedConfigPath : undefined;\n const plugins = asStringArray(pluginConfigPaths);\n const resolvedAllowlist = readAllowlist(allowlist);\n const staging =\n typeof stagingDirectory === 'string' && stagingDirectory ? stagingDirectory : fallback.stagingDirectory;\n\n return {\n repoRoot: resolvedRoot,\n stagingDirectory: staging,\n ...(generatedConfig ? { generatedConfigPath: generatedConfig } : {}),\n ...(plugins ? { pluginConfigPaths: plugins } : {}),\n ...(resolvedAllowlist ? { allowlist: resolvedAllowlist } : {}),\n };\n}\n\n/** Serializes the configuration for the Pi child process po launches. */\nexport function sessionConfigEnvironment(config: McpSessionConfig): Record<string, string> {\n return poMcpSessionEnvironment(config);\n}\n","/** Environment variable carrying a child agent's MCP tool selection. */\nexport const DIRECT_TOOLS_ENV = 'MCP_DIRECT_TOOLS';\n\n/** Explicit \"no MCP tools\", distinct from an unset variable meaning \"no limit\". */\nexport const NO_DIRECT_TOOLS = '__none__';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"directTools-hv4kxZeY.cjs","names":["path","fs","parseYaml","PROXY_SERVER_ALIASES","createHash","stringifyYaml","isProxyWrapper","repositoryMcpScope","pluginPathMcpScope","normalizeAgentPluginMcpSource","projectedSourceMcpScope","createHash","mcpProxyPackage","join","homedir","readFile","path","readPoMcpSessionConfig","PO_MCP_SESSION_ENV_VAR","poMcpSessionEnvironment"],"sources":["../src/services/configSources/index.ts","../src/services/mcpRuntime/index.ts","../src/services/sessionConfig/index.ts","../src/schemas/directTools.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { normalizeAgentPluginMcpSource } from '@agimon-ai/po-config/agentPluginMcp';\nimport type { PoMcpNativeProjectionSource } from '@agimon-ai/po-core/mcpProjection';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport type { McpConfigGroups, McpConfigGroupsInput, McpConfigSource, McpServerOrigin } from '../../types/mcpConfig';\nimport { pluginPathMcpScope, projectedSourceMcpScope, repositoryMcpScope } from '../mcpScope';\nimport { isProxyWrapper, PROXY_SERVER_ALIASES } from '../proxyWrapper';\n\n// The name check lives in `proxyWrapper` so the edge-safe server config can use it without this file's Node imports.\nexport { isProxyWrapper, PROXY_SERVER_NAME } from '../proxyWrapper';\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst DEFAULT_UPSTREAM_CONFIG = 'mcp-config.yaml';\nconst CONFIG_ARGUMENT = '--config';\n\ntype JsonObject = Record<string, unknown>;\n\ninterface FilteredLayer {\n source: McpConfigSource;\n kept: string[];\n dropped: string[];\n}\n\ninterface ConfigDocument {\n config: JsonObject;\n contents: string;\n}\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isYamlPath(filePath: string): boolean {\n const extension = path.extname(filePath).toLowerCase();\n return extension === '.yaml' || extension === '.yml';\n}\n\nasync function readConfigDocument(filePath: string): Promise<ConfigDocument | undefined> {\n try {\n const contents = await fs.readFile(filePath, 'utf8');\n const parsed: unknown = isYamlPath(filePath) ? parseYaml(contents) : JSON.parse(contents);\n return isObject(parsed) ? { config: parsed, contents } : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readConfigObject(filePath: string): Promise<JsonObject | undefined> {\n return (await readConfigDocument(filePath))?.config;\n}\n\nfunction serverDefinitions(config: JsonObject | undefined): Record<string, unknown> {\n return isObject(config?.mcpServers) ? config.mcpServers : {};\n}\n\nfunction isEnabledDefinition(definition: unknown): boolean {\n return !isObject(definition) || definition.disabled !== true;\n}\n\n/**\n * Resolves the upstream config referenced by the repository proxy wrapper.\n *\n * The wrapper remains useful to Claude, Codex, and other external clients. Po\n * embeds the same client/runtime code, so it reads this path and connects each\n * declared server itself instead of starting the wrapper as a nested MCP.\n */\nasync function resolveSharedConfigPathFrom(\n repoRoot: string,\n repositoryConfigPath: string,\n): Promise<string | undefined> {\n const servers = serverDefinitions(await readConfigObject(repositoryConfigPath));\n const proxy = [...PROXY_SERVER_ALIASES]\n .map((name) => servers[name])\n .find((definition): definition is JsonObject => isObject(definition));\n const rawArgs: unknown = proxy?.args;\n const args = Array.isArray(rawArgs) ? (rawArgs as unknown[]) : [];\n const configArgumentIndex = args.indexOf(CONFIG_ARGUMENT);\n const declared = args[configArgumentIndex + 1];\n const candidate =\n configArgumentIndex >= 0 && typeof declared === 'string'\n ? path.resolve(repoRoot, declared)\n : path.join(repoRoot, DEFAULT_UPSTREAM_CONFIG);\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n return undefined;\n }\n}\n\nexport async function resolveSharedConfigPath(repoRoot: string): Promise<string | undefined> {\n return resolveSharedConfigPathFrom(repoRoot, path.join(repoRoot, '.mcp.json'));\n}\n\n/** Empty and absent allowlists both mean \"keep everything\". */\nfunction isAllowed(name: string, allowed: string[] | undefined): boolean {\n return !allowed || allowed.length === 0 || allowed.includes(name);\n}\n\nfunction stagedPath(filePath: string, contents: string, stagingDirectory: string): string {\n // The filtered bytes are part of the identity because two live sessions can\n // select different domains. Sharing a path would let the later one rewrite the\n // configuration underneath the first one's deferred startup.\n const digest = createHash('sha256').update(filePath).update('\\0').update(contents).digest('hex').slice(0, 16);\n const extension = isYamlPath(filePath) ? '.yaml' : '.json';\n return path.join(stagingDirectory, `mcp-${digest}${extension}`);\n}\n\nfunction serializeConfig(filePath: string, config: JsonObject): string {\n return isYamlPath(filePath) ? stringifyYaml(config) : `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nasync function layerCacheKey(\n filePath: string,\n format: McpConfigSource['format'],\n originalContents: string,\n effectiveContents: string,\n sourceIdentity?: string,\n): Promise<string> {\n return createHash('sha256')\n .update(format)\n .update('\\0')\n .update(await fs.realpath(filePath))\n .update('\\0')\n .update(sourceIdentity ?? 'unprojected')\n .update('\\0')\n .update(originalContents)\n .update('\\0')\n .update(effectiveContents)\n .digest('hex');\n}\n\n/**\n * Rewrites one config layer with disallowed servers removed.\n *\n * Proxy wrapper entries are stripped from `.mcp.json` layers because Po reaches\n * their upstream config directly. Entries are removed rather than marked disabled,\n * so a filtered stdio server is never spawned at all.\n */\nasync function filterLayer(\n filePath: string,\n allowed: string[] | undefined,\n stagingDirectory: string,\n options: { stripProxyWrappers: boolean; sourceIdentity?: string },\n): Promise<FilteredLayer | undefined> {\n const document = await readConfigDocument(filePath);\n if (!document) return undefined;\n const { config, contents: originalContents } = document;\n const servers = serverDefinitions(config);\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n\n for (const [name, definition] of Object.entries(servers)) {\n const shouldDrop = (options.stripProxyWrappers && isProxyWrapper(name)) || !isAllowed(name, allowed);\n if (shouldDrop) dropped.push(name);\n else kept[name] = definition;\n }\n\n const keptNames = Object.entries(kept)\n .filter(([, definition]) => isEnabledDefinition(definition))\n .map(([name]) => name);\n if (dropped.length === 0) {\n return {\n source: {\n path: filePath,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, originalContents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n }\n\n await fs.mkdir(stagingDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n const contents = serializeConfig(filePath, { ...config, mcpServers: kept });\n const target = stagedPath(filePath, contents, stagingDirectory);\n await fs.writeFile(target, contents, { mode: PRIVATE_FILE_MODE });\n return {\n source: {\n path: target,\n format: 'claude',\n cacheKey: await layerCacheKey(filePath, 'claude', originalContents, contents, options.sourceIdentity),\n },\n kept: keptNames,\n dropped,\n };\n}\n\nasync function digestMatches(source: PoMcpNativeProjectionSource): Promise<boolean> {\n try {\n const digest = createHash('sha256')\n .update(await fs.readFile(source.configPath))\n .digest('hex');\n return digest === source.contentDigest;\n } catch {\n return false;\n }\n}\n\nfunction emptyGroups(diagnostics: string[] = []): McpConfigGroups {\n return {\n shared: { configSources: [], configPaths: [], serverNames: [] },\n sessionLocal: { configSources: [], configPaths: [], serverNames: [] },\n droppedServers: [],\n diagnostics,\n serverScopes: {},\n };\n}\n\n/**\n * Resolves every config layer for this session and applies its domain allowlist.\n *\n * All returned layers go into one embedded `@agimon-ai/po-mcp-proxy` client container.\n * The package is used as a library only: its wrapper MCP never becomes a Po MCP\n * server, so status, enable/disable, resources, and OAuth stay attached to each\n * actual downstream server.\n */\nexport async function buildMcpConfigGroups(input: McpConfigGroupsInput): Promise<\n McpConfigGroups & {\n /** Internal only. Paths and revisions must not be forwarded as browser ownership claims. */\n serverOrigins?: Record<string, McpServerOrigin>;\n }\n> {\n if (input.enabled === false) return emptyGroups();\n\n const projectedSources = input.sources;\n const repositoryScope = await repositoryMcpScope(input.repoRoot);\n const legacyLayers = projectedSources\n ? []\n : [\n { path: path.join(input.repoRoot, '.mcp.json'), scope: repositoryScope },\n ...(input.pluginConfigPaths ?? []).map((candidate) => {\n const resolved = path.resolve(input.repoRoot, candidate);\n return { path: resolved, scope: pluginPathMcpScope(resolved) };\n }),\n ];\n // Walked in container order, sessionLocal then shared, so the layer that wins a name owns its credential.\n const serverScopes: Record<string, string> = {};\n const serverOrigins: Record<string, McpServerOrigin> = {};\n const claim = async (\n names: readonly string[],\n scope: string,\n owner: McpServerOrigin['owner'],\n filePath: string,\n sourceId?: string,\n ) => {\n const definitions = serverDefinitions(await readConfigObject(filePath));\n for (const name of names) {\n serverScopes[name] = scope;\n serverOrigins[name] = {\n owner,\n path: filePath,\n revision: createHash('sha256')\n .update(JSON.stringify(definitions[name]) ?? 'undefined')\n .digest('hex'),\n ...(sourceId === undefined ? {} : { sourceId }),\n };\n }\n };\n\n const configSources: McpConfigSource[] = [];\n const serverNames: string[] = [];\n const droppedServers: string[] = [];\n const diagnostics: string[] = [];\n for (const layer of legacyLayers) {\n const filtered = await filterLayer(layer.path, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n });\n if (!filtered) continue;\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n layer.scope,\n layer.path === path.join(input.repoRoot, '.mcp.json') ? 'repository' : 'plugin',\n layer.path,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n for (const source of projectedSources ?? []) {\n if (source.format === 'agent-plugin-v1') {\n const normalized = normalizeAgentPluginMcpSource(source, {\n stagingDirectory: input.stagingDirectory,\n allowedServers: input.allowlist?.servers,\n });\n if (normalized.configSource) configSources.push(normalized.configSource);\n serverNames.push(...normalized.serverNames);\n await claim(\n normalized.serverNames,\n await projectedSourceMcpScope(source, input.repoRoot),\n 'plugin',\n normalized.configSource?.path ?? source.configPath,\n source.sourceId,\n );\n droppedServers.push(...normalized.droppedServers);\n diagnostics.push(...normalized.diagnostics);\n continue;\n }\n\n if (!(await digestMatches(source))) {\n diagnostics.push(\n `Native MCP source \"${source.sourceId}\" was disabled: the file is missing or its content digest changed.`,\n );\n continue;\n }\n const filtered = await filterLayer(source.configPath, input.allowlist?.servers, input.stagingDirectory, {\n stripProxyWrappers: true,\n sourceIdentity: `${source.sourceId}:${source.contentDigest}`,\n });\n if (!filtered) {\n diagnostics.push(`Native MCP source \"${source.sourceId}\" was disabled: the config could not be parsed.`);\n continue;\n }\n configSources.push(filtered.source);\n serverNames.push(...filtered.kept);\n await claim(\n filtered.kept,\n await projectedSourceMcpScope(source, input.repoRoot),\n source.owner === 'user' ? 'user' : source.owner === 'repository' ? 'repository' : 'plugin',\n source.configPath,\n source.sourceId,\n );\n droppedServers.push(...filtered.dropped);\n }\n\n const repositorySource = projectedSources?.find(\n (source): source is PoMcpNativeProjectionSource => source.format === 'native' && source.owner === 'repository',\n );\n const upstreamPath = projectedSources\n ? repositorySource && (await digestMatches(repositorySource))\n ? await resolveSharedConfigPathFrom(input.repoRoot, repositorySource.configPath)\n : undefined\n : await resolveSharedConfigPath(input.repoRoot);\n const upstream = upstreamPath\n ? await filterLayer(upstreamPath, input.allowlist?.proxy, input.stagingDirectory, { stripProxyWrappers: true })\n : undefined;\n if (upstream) {\n droppedServers.push(...upstream.dropped);\n // The repository's mcp-config.yaml belongs to the repository layer.\n await claim(upstream.kept, repositoryScope, 'upstream', upstreamPath!);\n }\n\n return {\n shared: {\n configSources: upstream ? [upstream.source] : [],\n configPaths: upstream ? [upstream.source.path] : [],\n serverNames: upstream ? upstream.kept : [],\n },\n // A later layer overriding an earlier one contributes the same name twice.\n sessionLocal: {\n configSources,\n configPaths: configSources.map((source) => source.path),\n serverNames: [...new Set(serverNames)],\n },\n droppedServers: [...new Set(droppedServers)],\n diagnostics,\n serverScopes,\n serverOrigins,\n };\n}\n","import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { PoOAuthRedirect } from '@agimon-ai/po-core/packageApi';\nimport type {\n ConfigSource,\n McpClientManagerAuthOptions,\n McpOutputSchemaWarning,\n McpSecretTarget,\n McpServerStateChange,\n McpToolInfo,\n OAuthCallbackSink,\n SharedServices,\n TokenStore,\n} from '@agimon-ai/po-mcp-proxy';\nimport mcpProxyPackage from '@agimon-ai/po-mcp-proxy/package.json' with { type: 'json' };\n\nimport type { McpConfigSource } from '../../types/mcpConfig';\nimport type { CachedCatalog } from '../../types/mcpRuntime';\n\n/**\n * Presents the hub's redirect surface as the proxy's callback collaborator.\n *\n * `listen` binds nothing: the hub already serves the address this advertises,\n * so opening a loopback port would only create one nobody redirects to.\n */\nexport function hubCallbackSink(redirect: PoOAuthRedirect): OAuthCallbackSink {\n return {\n redirectUri: () => redirect.redirectUri,\n getPort: () => undefined,\n listen: (preferredPort) => Promise.resolve(preferredPort),\n reserve: (state, timeoutMs) => redirect.reserve(state, timeoutMs),\n waitForCallback: (state, timeoutMs) => redirect.wait(state, timeoutMs),\n cancel: (state) => redirect.cancel(state),\n };\n}\n\nexport interface McpRuntimeOptions {\n /** Ordered config layers. Later layers override earlier ones. */\n configSources: McpConfigSource[];\n workspaceRoot?: string;\n /** Only an explicit session-only server add may start without file sources. */\n allowEmpty?: boolean;\n /** Exact session directory, independent of the checkout used for configuration. */\n executionCwd?: string;\n environment?: Readonly<Record<string, string | undefined>>;\n /**\n * Required: without one the proxy would fall back to its own file store under\n * `~/.mcp-proxy`, and Po keeps credentials only in the vault or in memory.\n */\n tokenStore: TokenStore;\n /**\n * Where OAuth redirects are received. Omitted, the proxy binds its own\n * loopback listener, which only a browser on this machine can reach.\n */\n callbackServer?: OAuthCallbackSink;\n /** Resolves `${vault:NAME}` references at connect time. Without it, every reference fails its connection. */\n resolveSecret?: (target: McpSecretTarget) => Promise<string | undefined>;\n resolveUrlCredentials?: McpClientManagerAuthOptions['resolveUrlCredentials'];\n onAuthorizationUrl?: (url: URL, serverName: string) => void;\n onServerStateChange?: (change: McpServerStateChange) => void;\n onOutputSchemaWarning?: (warning: McpOutputSchemaWarning) => void;\n}\n\nexport interface McpRuntimeHandle {\n generation: number;\n services: SharedServices;\n /** Resolves once the first connection pass settles. Never rejects. */\n connectionsSettled: Promise<void>;\n}\n\nconst MCP_APP_CLIENT_CAPABILITIES = {\n extensions: { 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html;profile=mcp-app', 'text/html+skybridge'] } },\n};\n\ninterface DefinitionsCacheFile {\n oneMcpVersion?: string;\n servers?: Record<string, { serverName: string; tools?: McpToolInfo[] }>;\n}\n\n/**\n * Definitions cache path shared by Po's synchronous warm reader and mcp-proxy.\n *\n * Generated staging paths are deliberately absent: projected source content must\n * invalidate a reused path, while identical portable content must survive a new\n * private staging directory. Stable source origins are carried inside each cache\n * key; format and merge behavior remain part of the ordered identity.\n */\nexport function definitionsCachePath(configSources: readonly McpConfigSource[]): string {\n if (configSources.length === 0) throw new Error('definitionsCachePath requires at least one config source');\n const digest = createHash('sha256')\n .update(\n JSON.stringify(\n configSources.map((source) => ({\n cacheKey: source.cacheKey,\n format: source.format,\n optional: source.optional ?? false,\n mergeStrategy: source.mergeStrategy ?? 'remote-priority',\n })),\n ),\n )\n .update('\\0')\n .update(mcpProxyPackage.version)\n .update('\\0')\n .update(JSON.stringify(MCP_APP_CLIENT_CAPABILITIES))\n .digest('hex');\n return join(homedir(), '.mcp-proxy', `po-${digest}.definitions-cache.json`);\n}\n\n/**\n * Reads the catalog the previous run left behind.\n *\n * Callers await the cache before registering tools. A miss is normal on a first\n * run and resolves to an empty catalog rather than an error.\n *\n * The file path is content-addressed from the current ordered layers, and its proxy\n * version is checked before any schema is registered. Servers filtered out of the\n * current configuration are also excluded later by `McpCatalog.seed`.\n */\nexport async function readCachedCatalog(\n configSources: readonly McpConfigSource[],\n cachePathFor: (sources: readonly McpConfigSource[]) => string = definitionsCachePath,\n): Promise<CachedCatalog> {\n if (configSources.length === 0) return { servers: [] };\n try {\n const cachePath = cachePathFor(configSources);\n const cache = JSON.parse(await readFile(cachePath, 'utf8')) as Partial<DefinitionsCacheFile>;\n if (cache.oneMcpVersion !== mcpProxyPackage.version) return { servers: [] };\n const servers = Object.values(cache.servers ?? {}).map((server) => ({\n name: server.serverName,\n tools: server.tools ?? [],\n }));\n return { servers };\n } catch {\n return { servers: [] };\n }\n}\n\nfunction toProxyConfigSource(source: McpConfigSource): ConfigSource {\n return {\n path: source.path,\n format: source.format,\n ...(source.optional === undefined ? {} : { optional: source.optional }),\n ...(source.mergeStrategy === undefined ? {} : { mergeStrategy: source.mergeStrategy }),\n };\n}\n\n/**\n * Owns the one live mcp-proxy container for this extension.\n *\n * Pi reloads extensions in process, so a connect that lands after a session restart\n * or a `/domains` switch would otherwise fold tools into a dead context. Every start\n * takes the next generation; anything an older generation produces is dropped and its\n * container disposed.\n */\nexport class McpRuntimeOwner {\n private generation = 0;\n private active: SharedServices | undefined;\n private unsubscribe: (() => void) | undefined;\n\n get currentGeneration(): number {\n return this.generation;\n }\n\n /** The live container, or undefined before the first start and after dispose. */\n getServices(): SharedServices | undefined {\n return this.active;\n }\n\n /**\n * Whether a container a caller captured earlier is still the live one.\n *\n * An async continuation that started under one container has to check this\n * before writing its result, or a `/domains` switch would fold stale tools into\n * the new session.\n */\n isCurrent(services: SharedServices | undefined): boolean {\n return services !== undefined && services === this.active;\n }\n\n /**\n * Starts a container for the current configuration, replacing any predecessor.\n *\n * Returns undefined when a newer generation started while this one was building,\n * which is the signal for the caller to abandon its half-finished work.\n */\n async start(options: McpRuntimeOptions): Promise<McpRuntimeHandle | undefined> {\n if (!options.tokenStore) throw new Error('The MCP runtime needs a token store.');\n const generation = ++this.generation;\n // Retired before the replacement is built so two containers never hold the same\n // stdio children open at once.\n await this.retire();\n if (options.configSources.length === 0 && !options.allowEmpty) return undefined;\n\n // The proxy container pulls in transports, OAuth, schema conversion, and\n // server implementations. Cached tool registration needs none of those, so\n // load the runtime only after session_start has yielded control to Pi.\n const { createProxyContainer } = await import('@agimon-ai/po-mcp-proxy');\n const cachePath = options.configSources.length > 0 ? definitionsCachePath(options.configSources) : undefined;\n const containerOptions = {\n configSources: options.configSources.map(toProxyConfigSource),\n workspaceRoot: options.workspaceRoot,\n executionCwd: options.executionCwd,\n environment: options.environment,\n definitionsCachePath: cachePath,\n // Never blocking: an unreachable server must not delay Pi's first prompt.\n startupMode: 'background' as const,\n clientCapabilities: MCP_APP_CLIENT_CAPABILITIES,\n outputSchemaValidation: {\n mode: 'warn' as const,\n onWarning: (warning: McpOutputSchemaWarning) => {\n if (generation === this.generation) options.onOutputSchemaWarning?.(warning);\n },\n },\n auth: {\n tokenStore: options.tokenStore,\n onAuthorizationUrl: options.onAuthorizationUrl,\n ...(options.callbackServer ? { callbackServer: options.callbackServer } : {}),\n ...(options.resolveSecret ? { resolveSecret: options.resolveSecret } : {}),\n ...(options.resolveUrlCredentials ? { resolveUrlCredentials: options.resolveUrlCredentials } : {}),\n },\n };\n const services = await createProxyContainer(containerOptions);\n\n if (generation !== this.generation) {\n await services.dispose();\n return undefined;\n }\n\n this.active = services;\n const forward = options.onServerStateChange;\n if (forward) {\n this.unsubscribe = services.clientManager.onServerStateChange((change) => {\n if (generation === this.generation) forward(change);\n });\n }\n\n return { generation, services, connectionsSettled: services.connectionsSettled };\n }\n\n /** Tears the container down and invalidates every generation still in flight. */\n async dispose(): Promise<void> {\n ++this.generation;\n await this.retire();\n }\n\n private async retire(): Promise<void> {\n this.unsubscribe?.();\n this.unsubscribe = undefined;\n const services = this.active;\n this.active = undefined;\n // A failed teardown must not leave the owner believing a dead container is live.\n if (services) await services.dispose();\n }\n}\n","import path from 'node:path';\n\nimport { PO_MCP_SESSION_ENV_VAR, poMcpSessionEnvironment, readPoMcpSessionConfig } from '@agimon-ai/po-core/mcpSession';\n\nimport type { McpAllowlist, McpSessionConfig } from '../../types/mcpConfig';\n\nfunction asStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const strings = value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);\n return strings.length > 0 ? strings : undefined;\n}\n\nfunction readAllowlist(value: unknown): McpAllowlist | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const { servers, proxy } = value as { servers?: unknown; proxy?: unknown };\n const allowlist: McpAllowlist = {};\n const allowedServers = asStringArray(servers);\n const allowedProxy = asStringArray(proxy);\n if (allowedServers) allowlist.servers = allowedServers;\n if (allowedProxy) allowlist.proxy = allowedProxy;\n return allowlist.servers || allowlist.proxy ? allowlist : undefined;\n}\n\n/**\n * Resolves what this session should connect to.\n *\n * Every field falls back to a working default so the extension is usable outside\n * po: a bare Pi session in a repository still gets that repository's\n * `.mcp.json` with no allowlist. A malformed value is treated as absent rather\n * than fatal, because losing MCP is better than losing the session.\n */\nexport function readSessionConfig(\n env: Readonly<Record<string, string | undefined>>,\n defaultRepoRoot: string,\n defaultStagingDirectory: string = path.join(defaultRepoRoot, '.po', 'mcp'),\n): McpSessionConfig {\n const fallback: McpSessionConfig = {\n repoRoot: defaultRepoRoot,\n stagingDirectory: defaultStagingDirectory,\n };\n\n const strict = readPoMcpSessionConfig(env);\n if (strict) {\n const { allowlist, pluginConfigPaths, ...required } = strict;\n const strictAllowlist = readAllowlist(allowlist);\n return {\n ...required,\n ...(pluginConfigPaths?.length ? { pluginConfigPaths: [...pluginConfigPaths] } : {}),\n ...(strictAllowlist ? { allowlist: strictAllowlist } : {}),\n };\n }\n\n const raw = env[PO_MCP_SESSION_ENV_VAR];\n if (!raw) return fallback;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return fallback;\n }\n if (typeof parsed !== 'object' || parsed === null) return fallback;\n\n const { repoRoot, generatedConfigPath, pluginConfigPaths, allowlist, stagingDirectory } = parsed as Record<\n string,\n unknown\n >;\n const resolvedRoot = typeof repoRoot === 'string' && repoRoot ? repoRoot : fallback.repoRoot;\n const generatedConfig =\n typeof generatedConfigPath === 'string' && generatedConfigPath ? generatedConfigPath : undefined;\n const plugins = asStringArray(pluginConfigPaths);\n const resolvedAllowlist = readAllowlist(allowlist);\n const staging =\n typeof stagingDirectory === 'string' && stagingDirectory ? stagingDirectory : fallback.stagingDirectory;\n\n return {\n repoRoot: resolvedRoot,\n stagingDirectory: staging,\n ...(generatedConfig ? { generatedConfigPath: generatedConfig } : {}),\n ...(plugins ? { pluginConfigPaths: plugins } : {}),\n ...(resolvedAllowlist ? { allowlist: resolvedAllowlist } : {}),\n };\n}\n\n/** Serializes the configuration for the Pi child process po launches. */\nexport function sessionConfigEnvironment(config: McpSessionConfig): Record<string, string> {\n return poMcpSessionEnvironment(config);\n}\n","/** Environment variable carrying a child agent's MCP tool selection. */\nexport const DIRECT_TOOLS_ENV = 'MCP_DIRECT_TOOLS';\n\n/** Explicit \"no MCP tools\", distinct from an unset variable meaning \"no limit\". */\nexport const NO_DIRECT_TOOLS = '__none__';\n"],"mappings":"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"}
|