mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 04:40:42 +00:00
88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
/**
|
|
* Standalone MCP server that exposes OpenClaw plugin-registered tools
|
|
* (e.g. memory-lancedb's memory_recall, memory_store, memory_forget)
|
|
* so ACP sessions running Claude Code can use them.
|
|
*
|
|
* Run via: node --import tsx src/mcp/plugin-tools-serve.ts
|
|
* Or: bun src/mcp/plugin-tools-serve.ts
|
|
*/
|
|
import { pathToFileURL } from "node:url";
|
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
import { pickSandboxToolPolicy } from "../agents/sandbox-tool-policy.js";
|
|
import {
|
|
collectExplicitAllowlist,
|
|
collectExplicitDenylist,
|
|
mergeAlsoAllowPolicy,
|
|
resolveToolProfilePolicy,
|
|
} from "../agents/tool-policy.js";
|
|
import type { AnyAgentTool } from "../agents/tools/common.js";
|
|
import { getRuntimeConfig } from "../config/config.js";
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import { formatErrorMessage } from "../infra/errors.js";
|
|
import { routeLogsToStderr } from "../logging/console.js";
|
|
import { ensureStandalonePluginToolRegistryLoaded, resolvePluginTools } from "../plugins/tools.js";
|
|
import { connectToolsMcpServerToStdio, createToolsMcpServer } from "./tools-stdio-server.js";
|
|
|
|
function resolvePluginToolPolicy(config: OpenClawConfig): {
|
|
toolAllowlist?: string[];
|
|
toolDenylist?: string[];
|
|
} {
|
|
const profilePolicy = mergeAlsoAllowPolicy(
|
|
resolveToolProfilePolicy(config.tools?.profile),
|
|
config.tools?.alsoAllow,
|
|
);
|
|
const globalPolicy = pickSandboxToolPolicy(config.tools);
|
|
const toolAllowlist = collectExplicitAllowlist([profilePolicy, globalPolicy]);
|
|
const toolDenylist = collectExplicitDenylist([profilePolicy, globalPolicy]);
|
|
return {
|
|
...(toolAllowlist.length > 0 ? { toolAllowlist } : {}),
|
|
...(toolDenylist.length > 0 ? { toolDenylist } : {}),
|
|
};
|
|
}
|
|
|
|
function resolveTools(config: OpenClawConfig): AnyAgentTool[] {
|
|
const pluginToolPolicy = resolvePluginToolPolicy(config);
|
|
ensureStandalonePluginToolRegistryLoaded({
|
|
context: { config },
|
|
...pluginToolPolicy,
|
|
});
|
|
return resolvePluginTools({
|
|
context: { config },
|
|
...pluginToolPolicy,
|
|
suppressNameConflicts: true,
|
|
});
|
|
}
|
|
|
|
export function createPluginToolsMcpServer(
|
|
params: {
|
|
config?: OpenClawConfig;
|
|
tools?: AnyAgentTool[];
|
|
} = {},
|
|
): Server {
|
|
const cfg = params.config ?? getRuntimeConfig();
|
|
const tools = params.tools ?? resolveTools(cfg);
|
|
return createToolsMcpServer({ name: "openclaw-plugin-tools", tools });
|
|
}
|
|
|
|
export async function servePluginToolsMcp(): Promise<void> {
|
|
// MCP stdio requires stdout to stay protocol-only, including during plugin
|
|
// tool discovery before the transport is connected.
|
|
routeLogsToStderr();
|
|
|
|
const config = getRuntimeConfig();
|
|
const tools = resolveTools(config);
|
|
const server = createPluginToolsMcpServer({ config, tools });
|
|
if (tools.length === 0) {
|
|
process.stderr.write("plugin-tools-serve: no plugin tools found\n");
|
|
}
|
|
|
|
await connectToolsMcpServerToStdio(server);
|
|
}
|
|
|
|
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
servePluginToolsMcp().catch((err) => {
|
|
process.stderr.write(`plugin-tools-serve: ${formatErrorMessage(err)}\n`);
|
|
process.exit(1);
|
|
});
|
|
}
|