feat(FN-3717): add OpenClaw MCP bridge (+5 more)

Commits merged:
- docs(FN-3717): update openclaw runtime and settings docs
- test(FN-3717): fix openclaw engine test typing
- test(FN-3717): strengthen openclaw bridge coverage
- feat(FN-3717): complete Step 2 — wire engine and bundle delivery
- fix(FN-3717): address openclaw bridge review feedback
- feat(FN-3717): complete Step 1 — add OpenClaw MCP bridge

Files changed:
.changeset/fn-3717-openclaw-tool-bridge.md         |  5 ++
 docs/settings-reference.md                         | 28 +++++---
 packages/cli/src/__tests__/bundle-output.test.ts   |  9 +++
 packages/cli/tsup.config.ts                        |  7 ++
 .../src/__tests__/openclaw-runtime-e2e.test.ts     | 28 ++++++++
 .../__tests__/openclaw-runtime-integration.test.ts | 10 +++
 plugins/fusion-plugin-openclaw-runtime/README.md   | 13 ++++
 .../src/__tests__/cli-spawn.test.ts                | 82 +++++++++++++++++++---
 .../src/__tests__/mcp-config.test.ts               | 45 ++++++++++++
 .../src/__tests__/runtime-adapter.test.ts          | 46 ++++++++++++
 .../fusion-plugin-openclaw-runtime/src/index.ts    |  5 ++
 .../src/mcp-config.ts                              | 60 ++++++++++++++++
 .../src/mcp-schema-server.cjs                      | 59 ++++++++++++++++
 .../src/pi-module.ts                               | 52 ++++++++++++--
 .../src/runtime-adapter.ts                         | 26 +++++++
 .../fusion-plugin-openclaw-runtime/src/types.ts    |  4 ++
 16 files changed, 457 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-3717
This commit is contained in:
Fusion
2026-05-07 17:56:43 -07:00
committed by gsxdsm
parent c32999b293
commit 836ca6807a
16 changed files with 457 additions and 22 deletions

View File

@@ -7,11 +7,13 @@ const {
mockCreateCliSession,
mockPromptCli,
mockDescribeCliModel,
mockConfigureOpenClawMcpServer,
} = vi.hoisted(() => ({
mockResolveCliConfig: vi.fn(),
mockCreateCliSession: vi.fn(),
mockPromptCli: vi.fn(),
mockDescribeCliModel: vi.fn(),
mockConfigureOpenClawMcpServer: vi.fn(),
}));
vi.mock("../pi-module.js", () => ({
@@ -19,6 +21,7 @@ vi.mock("../pi-module.js", () => ({
createCliSession: mockCreateCliSession,
promptCli: mockPromptCli,
describeCliModel: mockDescribeCliModel,
configureOpenClawMcpServer: mockConfigureOpenClawMcpServer,
}));
beforeEach(() => {
@@ -41,6 +44,7 @@ beforeEach(() => {
callbacks,
}));
mockDescribeCliModel.mockReturnValue("openclaw/main");
mockConfigureOpenClawMcpServer.mockResolvedValue(undefined);
});
describe("OpenClawRuntimeAdapter — identity", () => {
@@ -58,6 +62,48 @@ describe("OpenClawRuntimeAdapter — identity", () => {
});
describe("OpenClawRuntimeAdapter — createSession", () => {
it("configures MCP bridge when custom tools are present", async () => {
const adapter = new OpenClawRuntimeAdapter({ agentId: "ops" });
await adapter.createSession({
cwd: "/repo",
systemPrompt: "You are helpful",
tools: [
{ name: "read", description: "builtin", parameters: { type: "object" } },
{ name: "fn_task_list", description: "list", parameters: { type: "object", properties: {} } },
],
});
expect(mockConfigureOpenClawMcpServer).toHaveBeenCalledOnce();
expect(mockCreateCliSession).toHaveBeenCalledWith(
expect.objectContaining({ mcpProfile: expect.stringContaining("fusion-") }),
);
});
it("configures MCP bridge when tools arrive through customTools", async () => {
const adapter = new OpenClawRuntimeAdapter({ agentId: "ops" });
await adapter.createSession({
cwd: "/repo",
systemPrompt: "You are helpful",
customTools: [{ name: "fn_task_show", description: "custom", parameters: { type: "object" } }],
});
expect(mockConfigureOpenClawMcpServer).toHaveBeenCalledOnce();
});
it("does not configure MCP bridge when only built-in tools are provided", async () => {
const adapter = new OpenClawRuntimeAdapter({ agentId: "ops" });
await adapter.createSession({
cwd: "/repo",
systemPrompt: "You are helpful",
tools: [{ name: "read", description: "builtin", parameters: { type: "object" } }],
});
expect(mockConfigureOpenClawMcpServer).not.toHaveBeenCalled();
expect(mockCreateCliSession).toHaveBeenCalledWith(
expect.objectContaining({ mcpProfile: undefined }),
);
});
it("delegates to createCliSession with systemPrompt + agentId + callbacks", async () => {
const adapter = new OpenClawRuntimeAdapter({ agentId: "ops" });
const onText = vi.fn();