Forward enabled MCP server configuration through AI session creation and validation paths. - Resolve and materialize effective MCP servers with secret values at runtime for triage, execution, review, merge, evaluation, reflection, mission validation, and dashboard chat/planning lanes. - Add runtime support guards, Claude CLI MCP config generation, and a dashboard validation route for MCP server reachability probes. - Cover MCP forwarding, provider support behavior, settings resolution, validation, and pi extension config generation with targeted tests and docs. Files changed: .changeset/fn-7023-mcp-runtime-forwarding.md | 7 + docs/agents.md | 2 + docs/secrets.md | 1 + docs/settings-reference.md | 6 +- .../src/__tests__/mcp-lane-forwarding.test.ts | 79 +++++++++++ .../src/__tests__/mcp-validate-route.test.ts | 111 ++++++++++++++++ packages/dashboard/src/chat.ts | 3 + packages/dashboard/src/planning.ts | 5 + packages/dashboard/src/routes.ts | 90 ++++++++++++- .../src/__tests__/mcp-lane-forwarding.test.ts | 95 ++++++++++++++ .../engine/src/__tests__/mcp-resolution.test.ts | 104 +++++++++++++++ .../src/__tests__/mcp-runtime-support.test.ts | 44 +++++++ .../src/__tests__/mcp-validation-service.test.ts | 69 ++++++++++ packages/engine/src/__tests__/pi.test.ts | 65 +++++++++ packages/engine/src/agent-reflection.ts | 3 + packages/engine/src/agent-runtime.ts | 36 ++++- packages/engine/src/agent-session-helpers.ts | 2 + packages/engine/src/evaluator.ts | 3 + packages/engine/src/executor.ts | 14 ++ packages/engine/src/index.ts | 3 + packages/engine/src/mcp-resolution.ts | 81 ++++++++++++ packages/engine/src/mcp-runtime-support.ts | 41 ++++++ packages/engine/src/mcp-validation-service.ts | 146 +++++++++++++++++++++ packages/engine/src/merger-ai.ts | 5 + packages/engine/src/merger.ts | 14 ++ packages/engine/src/mission-execution-loop.ts | 3 + packages/engine/src/pi.ts | 44 +++++-- packages/engine/src/reviewer.ts | 3 + packages/engine/src/runtime-resolution.ts | 8 +- packages/engine/src/step-session-executor.ts | 6 +- packages/engine/src/triage.ts | 5 + packages/pi-claude-cli/index.ts | 20 ++- packages/pi-claude-cli/src/mcp-config.ts | 65 ++++++++- 33 files changed, 1150 insertions(+), 33 deletions(-) Fusion-Task-Id: FN-7023 Fusion-Task-Lineage: ea09c6c7-b3c3-4af6-9ca6-0ebbfec17139
82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
import {
|
|
materializeMcpServersSecrets,
|
|
resolveEffectiveMcpServers,
|
|
type GlobalSettings,
|
|
type McpSecretReader,
|
|
type McpSecretReaderIdentity,
|
|
type McpSecretResolutionError,
|
|
type ProjectSettings,
|
|
type ResolvedMcpServerDefinition,
|
|
} from "@fusion/core";
|
|
|
|
export interface ResolveMcpServersForRuntimeOptions {
|
|
globalSettings?: Pick<GlobalSettings, "mcpServers"> | null;
|
|
projectSettings?: Pick<ProjectSettings, "mcpServers"> | null;
|
|
secrets: McpSecretReader;
|
|
reader?: McpSecretReaderIdentity;
|
|
}
|
|
|
|
export interface ResolvedMcpServersForRuntime {
|
|
servers: ResolvedMcpServerDefinition[];
|
|
errors: McpSecretResolutionError[];
|
|
}
|
|
|
|
/**
|
|
* FNXC:McpConfig 2026-06-25-21:43:
|
|
* Runtime MCP forwarding uses Fusion's trusted-once-enabled model: enabled effective servers are materialized once at session/probe creation and then forwarded without per-call prompts. Plaintext env/header values exist only in this in-memory return value and callers must log only counts/errors, never server contents.
|
|
*/
|
|
export async function resolveMcpServersForRuntime(
|
|
options: ResolveMcpServersForRuntimeOptions,
|
|
): Promise<ResolvedMcpServersForRuntime> {
|
|
const effective = resolveEffectiveMcpServers(options.globalSettings, options.projectSettings);
|
|
if (effective.length === 0) return { servers: [], errors: [] };
|
|
|
|
const materialized = await materializeMcpServersSecrets(
|
|
effective,
|
|
options.secrets,
|
|
options.reader ?? {},
|
|
);
|
|
return {
|
|
servers: materialized.value ?? [],
|
|
errors: materialized.errors,
|
|
};
|
|
}
|
|
|
|
export interface McpSettingsAndSecretsStore {
|
|
getSettingsByScope?(): Promise<{
|
|
global: Pick<GlobalSettings, "mcpServers">;
|
|
project: Partial<Pick<ProjectSettings, "mcpServers">>;
|
|
}>;
|
|
getSecretsStore?(): Promise<McpSecretReader> | McpSecretReader;
|
|
}
|
|
|
|
const emptyMcpSecretReader: McpSecretReader = {
|
|
async revealSecret() {
|
|
throw new Error("MCP secret reader is unavailable");
|
|
},
|
|
};
|
|
|
|
export async function resolveMcpServersForStore(
|
|
store: McpSettingsAndSecretsStore,
|
|
reader?: McpSecretReaderIdentity,
|
|
): Promise<ResolvedMcpServersForRuntime> {
|
|
/*
|
|
* FNXC:McpConfig 2026-06-26-01:07:
|
|
* Older tests and lightweight TaskStore doubles may not implement the settings/secrets seams because they never configure MCP. Treat those stores as having no enabled MCP servers so all AI lanes keep their existing behavior while real stores still forward the resolved runtime configuration.
|
|
*/
|
|
if (typeof store.getSettingsByScope !== "function") {
|
|
return { servers: [], errors: [] };
|
|
}
|
|
|
|
const [settings, secrets] = await Promise.all([
|
|
store.getSettingsByScope(),
|
|
typeof store.getSecretsStore === "function" ? store.getSecretsStore() : emptyMcpSecretReader,
|
|
]);
|
|
return resolveMcpServersForRuntime({
|
|
globalSettings: settings.global,
|
|
projectSettings: settings.project,
|
|
secrets,
|
|
reader,
|
|
});
|
|
}
|