Refactor pipeline policies, MCP registry, and unified config/runtime

This commit is contained in:
2026-02-23 13:56:45 -05:00
parent 889087daa1
commit 9b4216dda9
22 changed files with 1441 additions and 587 deletions

View File

@@ -1,17 +1,18 @@
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import type { CodexOptions } from "@openai/codex-sdk";
import { getConfig, type AppConfig } from "./config.js";
import { normalizeSharedMcpConfigFile } from "./mcp/converters.js";
import {
createDefaultMcpRegistry,
createMcpHandlerShell,
listMcpHandlers,
registerMcpHandler,
resolveServerWithHandler,
type McpHandlerBusinessLogic,
type McpHandlerBusinessLogicInput,
type McpHandlerInput,
type McpHandlerResult,
type McpHandlerShellOptions,
type McpHandlerUtils,
McpRegistry,
type McpServerHandler,
} from "./mcp/handlers.js";
import type {
@@ -24,16 +25,15 @@ function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function readConfigFile(pathFromEnv: string | undefined): {
function readConfigFile(configPath: string): {
config?: SharedMcpConfigFile;
sourcePath?: string;
} {
const explicitPath = pathFromEnv?.trim();
const candidatePath = explicitPath || "./mcp.config.json";
const candidatePath = configPath.trim() || "./mcp.config.json";
const resolvedPath = resolve(process.cwd(), candidatePath);
if (!existsSync(resolvedPath)) {
if (explicitPath) {
if (candidatePath !== "./mcp.config.json") {
throw new Error(`MCP config file not found: ${resolvedPath}`);
}
return {};
@@ -45,11 +45,29 @@ function readConfigFile(pathFromEnv: string | undefined): {
throw new Error(`MCP config file must contain a JSON object: ${resolvedPath}`);
}
return { config: parsed as SharedMcpConfigFile, sourcePath: resolvedPath };
return {
config: normalizeSharedMcpConfigFile(parsed as SharedMcpConfigFile),
sourcePath: resolvedPath,
};
}
export function loadMcpConfigFromEnv(context: McpLoadContext = {}): LoadedMcpConfig {
const { config, sourcePath } = readConfigFile(process.env.MCP_CONFIG_PATH);
const defaultMcpRegistry = createDefaultMcpRegistry();
export function getDefaultMcpRegistry(): McpRegistry {
return defaultMcpRegistry;
}
export function loadMcpConfigFromEnv(
context: McpLoadContext = {},
options?: {
config?: Readonly<AppConfig>;
registry?: McpRegistry;
},
): LoadedMcpConfig {
const runtimeConfig = options?.config ?? getConfig();
const registry = options?.registry ?? defaultMcpRegistry;
const { config, sourcePath } = readConfigFile(runtimeConfig.mcp.configPath);
if (!config) {
return {};
}
@@ -59,7 +77,7 @@ export function loadMcpConfigFromEnv(context: McpLoadContext = {}): LoadedMcpCon
const resolvedHandlers: Record<string, string> = {};
for (const [serverName, server] of Object.entries(config.servers ?? {})) {
const resolved = resolveServerWithHandler({
const resolved = registry.resolveServerWithHandler({
serverName,
server,
context,
@@ -102,7 +120,15 @@ export function loadMcpConfigFromEnv(context: McpLoadContext = {}): LoadedMcpCon
};
}
export { createMcpHandlerShell, listMcpHandlers, registerMcpHandler };
export function registerMcpHandler(handler: McpServerHandler): void {
defaultMcpRegistry.register(handler);
}
export function listMcpHandlers(): McpServerHandler[] {
return defaultMcpRegistry.listHandlers();
}
export { createDefaultMcpRegistry, createMcpHandlerShell, McpRegistry };
export type {
LoadedMcpConfig,
McpHandlerBusinessLogic,