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:
@@ -10,6 +10,7 @@
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import type {
|
||||
CliConfig,
|
||||
GatewayCallbacks,
|
||||
@@ -101,15 +102,21 @@ export function resolveCliConfig(settings?: Record<string, unknown>): CliConfig
|
||||
*/
|
||||
export function buildOpenClawArgs(
|
||||
config: CliConfig,
|
||||
sessionId: string,
|
||||
session: Pick<GatewaySession, "sessionId" | "mcpProfile">,
|
||||
message: string,
|
||||
): string[] {
|
||||
const args: string[] = ["--no-color", "agent"];
|
||||
const args: string[] = ["--no-color"];
|
||||
|
||||
if (session.mcpProfile) {
|
||||
args.push("--profile", session.mcpProfile);
|
||||
}
|
||||
|
||||
args.push("agent");
|
||||
|
||||
if (!config.useGateway) args.push("--local");
|
||||
|
||||
args.push("--json");
|
||||
args.push("--session-id", sessionId);
|
||||
args.push("--session-id", session.sessionId);
|
||||
args.push("--message", message);
|
||||
args.push("--agent", config.agentId);
|
||||
|
||||
@@ -152,6 +159,8 @@ export function createCliSession(opts: {
|
||||
systemPrompt: string;
|
||||
agentId?: string;
|
||||
callbacks?: GatewayCallbacks;
|
||||
mcpProfile?: string;
|
||||
mcpConfigPath?: string;
|
||||
}): GatewaySession {
|
||||
return {
|
||||
sessionId: randomUUID(),
|
||||
@@ -161,9 +170,44 @@ export function createCliSession(opts: {
|
||||
lastModelDescription: `openclaw/${opts.agentId ?? DEFAULT_AGENT_ID}`,
|
||||
lastUsage: undefined,
|
||||
callbacks: opts.callbacks,
|
||||
mcpProfile: opts.mcpProfile,
|
||||
mcpConfigPath: opts.mcpConfigPath,
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// configureOpenClawMcpServer — configure profile-scoped MCP server via CLI
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function configureOpenClawMcpServer(opts: {
|
||||
binaryPath: string;
|
||||
profile: string;
|
||||
serverName: string;
|
||||
serverConfigPath: string;
|
||||
}): Promise<void> {
|
||||
const serverValue = await readFile(opts.serverConfigPath, "utf-8");
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const child = spawn(opts.binaryPath, ["--no-color", "--profile", opts.profile, "mcp", "set", opts.serverName, serverValue], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let stderr = "";
|
||||
child.stderr?.on("data", (chunk: Buffer) => {
|
||||
stderr += chunk.toString("utf-8");
|
||||
});
|
||||
|
||||
child.on("error", (err) => reject(new Error(`openclaw: failed to configure MCP server — ${err.message}`)));
|
||||
child.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
reject(new Error(`openclaw: mcp set failed (${String(code)}): ${extractStderrError(stderr)}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// promptCli — spawns openclaw, parses the JSON, fires callbacks
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -175,7 +219,7 @@ export async function promptCli(
|
||||
callbacks?: GatewayCallbacks,
|
||||
signal?: AbortSignal,
|
||||
): Promise<void> {
|
||||
const args = buildOpenClawArgs(config, session.sessionId, message);
|
||||
const args = buildOpenClawArgs(config, session, message);
|
||||
const cb: GatewayCallbacks = { ...session.callbacks, ...callbacks };
|
||||
|
||||
cb.onToolStart?.("openclaw.agent", { sessionId: session.sessionId });
|
||||
|
||||
Reference in New Issue
Block a user