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,5 +1,42 @@
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
import type { CodexConfigObject, SharedMcpServer, Transport } from "./types.js";
import type {
CodexConfigObject,
SharedMcpConfigFile,
SharedMcpServer,
Transport,
} from "./types.js";
function mergeHeaders(server: SharedMcpServer): Record<string, string> | undefined {
const merged = {
...(server.http_headers ?? {}),
...(server.headers ?? {}),
};
return Object.keys(merged).length > 0 ? merged : undefined;
}
export function normalizeSharedMcpServer(server: SharedMcpServer): SharedMcpServer {
const { headers: _headers, http_headers: _httpHeaders, ...rest } = server;
const normalizedHeaders = mergeHeaders(server);
return {
...rest,
...(normalizedHeaders ? { headers: normalizedHeaders } : {}),
};
}
export function normalizeSharedMcpConfigFile(config: SharedMcpConfigFile): SharedMcpConfigFile {
const normalizedServers: Record<string, SharedMcpServer> = {};
for (const [serverName, server] of Object.entries(config.servers ?? {})) {
normalizedServers[serverName] = normalizeSharedMcpServer(server);
}
return {
...config,
...(Object.keys(normalizedServers).length > 0 ? { servers: normalizedServers } : {}),
};
}
export function inferTransport(server: SharedMcpServer): Transport {
if (server.type) {
@@ -10,6 +47,7 @@ export function inferTransport(server: SharedMcpServer): Transport {
export function toCodexServerConfig(serverName: string, server: SharedMcpServer): CodexConfigObject {
const type = inferTransport(server);
const headers = mergeHeaders(server);
if (type === "stdio" && !server.command) {
throw new Error(`Shared MCP server "${serverName}" requires "command" for stdio transport.`);
@@ -38,9 +76,8 @@ export function toCodexServerConfig(serverName: string, server: SharedMcpServer)
if (server.bearer_token_env_var) {
config.bearer_token_env_var = server.bearer_token_env_var;
}
const httpHeaders = server.http_headers ?? server.headers;
if (httpHeaders) {
config.http_headers = httpHeaders;
if (headers) {
config.http_headers = headers;
}
if (server.env_http_headers) config.env_http_headers = server.env_http_headers;
if (server.env_vars) config.env_vars = server.env_vars;
@@ -50,6 +87,7 @@ export function toCodexServerConfig(serverName: string, server: SharedMcpServer)
export function toClaudeServerConfig(serverName: string, server: SharedMcpServer): McpServerConfig {
const type = inferTransport(server);
const headers = mergeHeaders(server);
if (type === "stdio") {
if (!server.command) {
@@ -70,7 +108,6 @@ export function toClaudeServerConfig(serverName: string, server: SharedMcpServer
return {
type,
url: server.url,
...(server.headers ? { headers: server.headers } : {}),
...(headers ? { headers } : {}),
};
}

View File

@@ -127,107 +127,121 @@ function applyEnabledByDefault(input: McpHandlerBusinessLogicInput): McpHandlerR
: input.baseResult;
}
const context7Handler = createMcpHandlerShell({
id: "context7",
description:
"Dedicated extension point for Context7 policy/behavior. Business logic belongs in applyBusinessLogic.",
matches: (input) => isNamedLike(input, ["context7"]),
applyBusinessLogic: applyEnabledByDefault,
});
const claudeTaskMasterHandler = createMcpHandlerShell({
id: "claude-task-master",
description:
"Dedicated extension point for Claude Task Master policy/behavior. Business logic belongs in applyBusinessLogic.",
matches: (input) =>
isNamedLike(input, ["claude-task-master", "task-master", "taskmaster"]),
applyBusinessLogic: applyEnabledByDefault,
});
const genericHandler: McpServerHandler = {
id: "generic",
description: "Default passthrough mapping for project-specific MCP servers.",
matches: () => true,
resolve: ({ serverName, server, utils: localUtils }) =>
createDefaultResult({ serverName, server, localUtils }),
};
const handlerRegistry = new Map<string, McpServerHandler>();
const handlerOrder: string[] = [];
function installBuiltinHandlers(): void {
registerMcpHandler(context7Handler);
registerMcpHandler(claudeTaskMasterHandler);
registerMcpHandler(genericHandler);
}
export function registerMcpHandler(handler: McpServerHandler): void {
if (handlerRegistry.has(handler.id)) {
handlerRegistry.set(handler.id, handler);
return;
}
handlerRegistry.set(handler.id, handler);
handlerOrder.push(handler.id);
}
export function listMcpHandlers(): McpServerHandler[] {
return handlerOrder
.map((id) => handlerRegistry.get(id))
.filter((handler): handler is McpServerHandler => Boolean(handler));
}
function resolveHandler(serverName: string, server: SharedMcpServer): McpServerHandler {
if (server.handler) {
const explicit = handlerRegistry.get(server.handler);
if (!explicit) {
throw new Error(
`Unknown MCP handler "${server.handler}" configured for server "${serverName}".`,
);
}
return explicit;
}
for (const id of handlerOrder) {
const handler = handlerRegistry.get(id);
if (!handler || id === "generic") {
continue;
}
if (handler.matches({ serverName, server })) {
return handler;
}
}
const fallback = handlerRegistry.get("generic");
if (!fallback) {
throw new Error('No MCP fallback handler registered. Expected handler id "generic".');
}
return fallback;
}
export function resolveServerWithHandler(input: {
serverName: string;
server: SharedMcpServer;
context: McpLoadContext;
fullConfig: SharedMcpConfigFile;
}): McpHandlerResult & { handlerId: string } {
const { serverName, server, context, fullConfig } = input;
const handler = resolveHandler(serverName, server);
const handlerConfig = {
...(fullConfig.handlerSettings?.[handler.id] ?? {}),
...(server.handlerOptions ?? {}),
};
const result = handler.resolve({
serverName,
server,
context,
handlerConfig,
fullConfig,
utils,
function createBuiltinHandlers(): McpServerHandler[] {
const context7Handler = createMcpHandlerShell({
id: "context7",
description:
"Dedicated extension point for Context7 policy/behavior. Business logic belongs in applyBusinessLogic.",
matches: (input) => isNamedLike(input, ["context7"]),
applyBusinessLogic: applyEnabledByDefault,
});
return {
...result,
handlerId: handler.id,
const claudeTaskMasterHandler = createMcpHandlerShell({
id: "claude-task-master",
description:
"Dedicated extension point for Claude Task Master policy/behavior. Business logic belongs in applyBusinessLogic.",
matches: (input) =>
isNamedLike(input, ["claude-task-master", "task-master", "taskmaster"]),
applyBusinessLogic: applyEnabledByDefault,
});
const genericHandler: McpServerHandler = {
id: "generic",
description: "Default passthrough mapping for project-specific MCP servers.",
matches: () => true,
resolve: ({ serverName, server, utils: localUtils }) =>
createDefaultResult({ serverName, server, localUtils }),
};
return [context7Handler, claudeTaskMasterHandler, genericHandler];
}
installBuiltinHandlers();
export class McpRegistry {
private readonly handlerRegistry = new Map<string, McpServerHandler>();
private readonly handlerOrder: string[] = [];
constructor(input?: { handlers?: McpServerHandler[] }) {
for (const handler of input?.handlers ?? []) {
this.register(handler);
}
}
register(handler: McpServerHandler): void {
if (this.handlerRegistry.has(handler.id)) {
this.handlerRegistry.set(handler.id, handler);
return;
}
this.handlerRegistry.set(handler.id, handler);
this.handlerOrder.push(handler.id);
}
listHandlers(): McpServerHandler[] {
return this.handlerOrder
.map((id) => this.handlerRegistry.get(id))
.filter((handler): handler is McpServerHandler => Boolean(handler));
}
resolveServerWithHandler(input: {
serverName: string;
server: SharedMcpServer;
context: McpLoadContext;
fullConfig: SharedMcpConfigFile;
}): McpHandlerResult & { handlerId: string } {
const { serverName, server, context, fullConfig } = input;
const handler = this.resolveHandler(serverName, server);
const handlerConfig = {
...(fullConfig.handlerSettings?.[handler.id] ?? {}),
...(server.handlerOptions ?? {}),
};
const result = handler.resolve({
serverName,
server,
context,
handlerConfig,
fullConfig,
utils,
});
return {
...result,
handlerId: handler.id,
};
}
private resolveHandler(serverName: string, server: SharedMcpServer): McpServerHandler {
if (server.handler) {
const explicit = this.handlerRegistry.get(server.handler);
if (!explicit) {
throw new Error(
`Unknown MCP handler "${server.handler}" configured for server "${serverName}".`,
);
}
return explicit;
}
for (const id of this.handlerOrder) {
const handler = this.handlerRegistry.get(id);
if (!handler || id === "generic") {
continue;
}
if (handler.matches({ serverName, server })) {
return handler;
}
}
const fallback = this.handlerRegistry.get("generic");
if (!fallback) {
throw new Error('No MCP fallback handler registered. Expected handler id "generic".');
}
return fallback;
}
}
export function createDefaultMcpRegistry(): McpRegistry {
return new McpRegistry({
handlers: createBuiltinHandlers(),
});
}