Expose Fusion knowledge graph and durable recall through a built-in MCP transport. - Add the reserved fusion-memory server with graph and recall MCP tools. - Resolve built-in availability and enable/disable tombstones across configuration and UI. - Add CLI transport, documentation, release metadata, and lane coverage tests. Files changed: .changeset/fn-8926-memory-mcp-server.md | 7 + docs/cli-reference.md | 4 + docs/mcp.md | 10 ++ packages/cli/src/bin.ts | 6 + .../__tests__/mcp-memory-server-spawn.test.ts | 79 ++++++++++ .../commands/__tests__/mcp-memory-server.test.ts | 83 +++++++++++ packages/cli/src/commands/__tests__/mcp.test.ts | 27 +++- packages/cli/src/commands/mcp-memory-server.ts | 104 +++++++++++++ packages/cli/src/commands/mcp.ts | 64 ++++++-- packages/core/package.json | 10 ++ .../core/src/__tests__/mcp-builtin-servers.test.ts | 17 +++ packages/core/src/__tests__/mcp-config.test.ts | 12 ++ packages/core/src/config/mcp-builtin-descriptor.ts | 16 ++ packages/core/src/config/mcp-builtin-servers.ts | 18 +++ packages/core/src/config/mcp-config.ts | 40 +++-- packages/core/src/config/mcp-discovery.ts | 3 +- packages/core/src/index.ts | 6 + packages/core/src/memory/index.ts | 1 + .../mcp/__tests__/memory-mcp-handler.test.ts | 36 +++++ .../mcp/__tests__/memory-mcp-serialization.test.ts | 23 +++ packages/core/src/memory/mcp/index.ts | 4 + .../core/src/memory/mcp/memory-mcp-backends.ts | 39 +++++ packages/core/src/memory/mcp/memory-mcp-handler.ts | 54 +++++++ .../src/memory/mcp/memory-mcp-serialization.ts | 48 ++++++ packages/core/src/memory/mcp/memory-mcp-tools.ts | 64 ++++++++ packages/core/src/types.ts | 10 ++ .../settings/sections/GlobalMcpSection.tsx | 14 +- .../settings/sections/McpServersCard.tsx | 67 +++++++-- .../settings/sections/ProjectMcpSection.tsx | 15 +- .../__tests__/McpServersCard.builtin.test.tsx | 45 ++++++ .../dashboard/src/__tests__/chat-manager.test.ts | 24 +++ .../register-config-mcp-pi-settings-routes.ts | 20 ++- packages/dashboard/vitest.config.ts | 2 + .../__tests__/mcp-builtin-lane-coverage.test.ts | 163 +++++++++++++++++++++ packages/engine/src/mcp/mcp-resolution.ts | 10 +- packages/engine/vitest.config.ts | 2 + 36 files changed, 1097 insertions(+), 50 deletions(-) Fusion-Task-Id: FN-8926 Fusion-Task-Lineage: b2861491-33da-4b05-b9f8-a7c1448c1c8c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
56 lines
2.8 KiB
TypeScript
56 lines
2.8 KiB
TypeScript
import type { Dispatch, SetStateAction } from "react";
|
|
import { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { GlobalSettings, PluginMcpServerContribution, Settings } from "@fusion/core";
|
|
import type { ToastType } from "../../../hooks/useToast";
|
|
import { McpServersCard } from "./McpServersCard";
|
|
|
|
export interface ProjectMcpSectionProps {
|
|
form: Settings;
|
|
setForm: Dispatch<SetStateAction<Settings>>;
|
|
globalSettings?: Pick<GlobalSettings, "mcpServers"> | null;
|
|
projectId?: string;
|
|
/** Project-scoped plugin entries; global MCP settings never receive these. */
|
|
pluginServers?: Array<{ pluginId: string; server: PluginMcpServerContribution }>;
|
|
addToast: (message: string, type?: ToastType) => void;
|
|
}
|
|
|
|
export function ProjectMcpSection({ form, setForm, globalSettings, projectId, pluginServers, addToast }: ProjectMcpSectionProps) {
|
|
const { t } = useTranslation("app");
|
|
const [loadedPluginServers, setLoadedPluginServers] = useState<Array<{ pluginId: string; server: PluginMcpServerContribution }>>([]);
|
|
const [builtInAvailable, setBuiltInAvailable] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const controller = new AbortController();
|
|
const query = projectId ? `?projectId=${encodeURIComponent(projectId)}` : "";
|
|
/*
|
|
* FNXC:PluginMcpServers 2026-07-22-12:00:
|
|
* FN-8491 obtains settings-card contributions only from the active-project
|
|
* endpoint, which owns project_plugin_states filtering. Rendering never
|
|
* writes declarations and global MCP settings never request this endpoint.
|
|
*/
|
|
void fetch(`/api/mcp/plugin-servers${query}`, { signal: controller.signal })
|
|
.then(async (response) => {
|
|
if (!response.ok) throw new Error("Failed to load project plugin MCP servers");
|
|
return response.json() as Promise<{ servers?: Array<{ pluginId: string; server: PluginMcpServerContribution }>; fusionMemoryMcpAvailable?: boolean }>;
|
|
})
|
|
.then((payload) => {
|
|
if (!controller.signal.aborted) {
|
|
if (!pluginServers) setLoadedPluginServers(Array.isArray(payload.servers) ? payload.servers : []);
|
|
setBuiltInAvailable(payload.fusionMemoryMcpAvailable === true);
|
|
}
|
|
})
|
|
.catch(() => { if (!controller.signal.aborted) { if (!pluginServers) setLoadedPluginServers([]); setBuiltInAvailable(false); } });
|
|
return () => controller.abort();
|
|
}, [pluginServers, projectId]);
|
|
|
|
return (
|
|
<>
|
|
<h4 className="settings-section-heading">{t("settings.nav.mcp", "MCP Servers")}</h4>
|
|
<McpServersCard scope="project" form={form} setForm={setForm} globalSettings={globalSettings} projectId={projectId} pluginServers={pluginServers ?? loadedPluginServers} builtInAvailable={builtInAvailable} addToast={addToast} />
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default ProjectMcpSection;
|