Files
fusion/packages/dashboard/app/components/settings/sections/ProjectMcpSection.tsx
gsxdsm a839c61929 FN-8926: expose graph and recall through MCP
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>
2026-08-10 17:50:27 -07:00

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;