refactor(core): F2 PR A R9 — McpClientManager options-object ctor

R9 (filed as F2 follow-up from #4336 review): 7 positional ctor args
collapse to (config, toolRegistry, options?: McpClientManagerOptions).
The trailing 5 (eventEmitter, sendSdkMcpMessage, healthConfig,
budgetConfig, pool) become named fields on `McpClientManagerOptions`.
Test factory `mkManager(overrides?)` introduced at the top of
`mcp-client-manager.test.ts` so each of the prior 80 inline
constructions becomes a single line naming only the field(s) the test
overrides; the 4 `undefined` sentinels each test threaded through to
reach the trailing `pool` arg are gone.

Net: 113 LOC removed (test) + 35 LOC added (src exposes interface +
mkManager factory + tool-registry call site update). Behavior
unchanged — same field assignments, same downgrade-enforce-without-
budget breadcrumb, same budget event wiring.

Filed bucket: F2 perf / cleanup PR A (R9 + W11 + W12 + R10/R23 T7),
see issue #4175 item 7 "F2 post-merge cleanup PRs". This is the first
of the 4 fixes in PR A; W11/W12/R10 follow as separate commits.

Test sweep: 84/84 mcp-client-manager.test.ts pass; typecheck clean.
This commit is contained in:
doudouOUC 2026-05-22 00:44:38 +08:00
parent 46f8d48f13
commit f05917071c
3 changed files with 384 additions and 488 deletions

File diff suppressed because it is too large Load diff

View file

@ -343,6 +343,26 @@ function readBudgetFromEnv(): McpBudgetConfig {
return { clientBudget, budgetMode };
}
/**
* F2 (#4175 commit 6 review fix wenshao R9 / PR A): options bag for
* `McpClientManager` construction, replacing the prior 5 trailing
* positional parameters (`eventEmitter`, `sendSdkMcpMessage`,
* `healthConfig`, `budgetConfig`, `pool`). Pre-fix every test site
* threaded 4 explicit `undefined`s to reach the trailing `pool` arg
* the fixed positions also blocked future option additions without
* re-ordering. The options-object form lets each caller name only the
* fields it cares about and keeps the constructor signature stable
* across future additions (e.g. when the W8 health-monitor wire-up
* lands a new `reconnectStrategy` knob).
*/
export interface McpClientManagerOptions {
eventEmitter?: EventEmitter;
sendSdkMcpMessage?: SendSdkMcpMessage;
healthConfig?: Partial<MCPHealthMonitorConfig>;
budgetConfig?: McpBudgetConfig;
pool?: import('./mcp-transport-pool.js').McpTransportPool;
}
/**
* Manages the lifecycle of multiple MCP clients, including local child processes.
* This class is responsible for starting, stopping, and discovering tools from
@ -513,19 +533,16 @@ export class McpClientManager {
constructor(
config: Config,
toolRegistry: ToolRegistry,
eventEmitter?: EventEmitter,
sendSdkMcpMessage?: SendSdkMcpMessage,
healthConfig?: Partial<MCPHealthMonitorConfig>,
budgetConfig?: McpBudgetConfig,
pool?: import('./mcp-transport-pool.js').McpTransportPool,
options: McpClientManagerOptions = {},
) {
this.cliConfig = config;
this.toolRegistry = toolRegistry;
this.pool = pool;
this.pool = options.pool;
this.eventEmitter = eventEmitter;
this.sendSdkMcpMessage = sendSdkMcpMessage;
this.healthConfig = { ...DEFAULT_HEALTH_CONFIG, ...healthConfig };
this.eventEmitter = options.eventEmitter;
this.sendSdkMcpMessage = options.sendSdkMcpMessage;
this.healthConfig = { ...DEFAULT_HEALTH_CONFIG, ...options.healthConfig };
const budgetConfig = options.budgetConfig;
// Tests inject `budgetConfig` directly; production reads env vars
// set by `qwen serve --mcp-client-budget=N --mcp-budget-mode=X`

View file

@ -196,21 +196,19 @@ export class ToolRegistry {
sendSdkMcpMessage?: SendSdkMcpMessage,
) {
this.config = config;
this.mcpClientManager = new McpClientManager(
this.config,
this,
// F2 (#4175 commit 6 review fix — wenshao R9 / PR A): options-bag
// ctor; previously 7 positional args with `undefined, undefined`
// sentinels for `healthConfig` / `budgetConfig`. `pool` is
// forwarded from Config (set by daemon-mode QwenAgent in
// `newSessionConfig`); when undefined the manager keeps its pre-F2
// per-session spawn behavior, when defined non-SDK MCP discovery
// goes through `pool.acquire` so N sessions in the same workspace
// share one transport per unique server config.
this.mcpClientManager = new McpClientManager(this.config, this, {
eventEmitter,
sendSdkMcpMessage,
// F2 (#4175 commit 4): forward the workspace-shared MCP transport
// pool from Config (set by daemon-mode QwenAgent in
// newSessionConfig). When undefined, McpClientManager keeps its
// pre-F2 per-session spawn behavior. When defined, non-SDK MCP
// discovery goes through pool.acquire so N sessions in the same
// workspace share one transport per unique server config.
undefined, // healthConfig: keep manager defaults
undefined, // budgetConfig: keep manager defaults
this.config.getMcpTransportPool(),
);
pool: this.config.getMcpTransportPool(),
});
}
/**