mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-11 01:01:13 +00:00
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
import { loadConfig, type OpenClawConfig } from "../config/config.js";
|
|
import { VERSION } from "../version.js";
|
|
import { OpenClawChannelBridge } from "./channel-bridge.js";
|
|
import { ClaudePermissionRequestSchema, type ClaudeChannelMode } from "./channel-shared.js";
|
|
import { getChannelMcpCapabilities, registerChannelMcpTools } from "./channel-tools.js";
|
|
|
|
export { OpenClawChannelBridge } from "./channel-bridge.js";
|
|
|
|
export type OpenClawMcpServeOptions = {
|
|
gatewayUrl?: string;
|
|
gatewayToken?: string;
|
|
gatewayPassword?: string;
|
|
config?: OpenClawConfig;
|
|
claudeChannelMode?: ClaudeChannelMode;
|
|
verbose?: boolean;
|
|
};
|
|
|
|
export async function createOpenClawChannelMcpServer(opts: OpenClawMcpServeOptions = {}): Promise<{
|
|
server: McpServer;
|
|
bridge: OpenClawChannelBridge;
|
|
start: () => Promise<void>;
|
|
close: () => Promise<void>;
|
|
}> {
|
|
const cfg = opts.config ?? loadConfig();
|
|
const claudeChannelMode = opts.claudeChannelMode ?? "auto";
|
|
const capabilities = getChannelMcpCapabilities(claudeChannelMode);
|
|
const server = new McpServer(
|
|
{ name: "openclaw", version: VERSION },
|
|
capabilities ? { capabilities } : undefined,
|
|
);
|
|
const bridge = new OpenClawChannelBridge(cfg, {
|
|
gatewayUrl: opts.gatewayUrl,
|
|
gatewayToken: opts.gatewayToken,
|
|
gatewayPassword: opts.gatewayPassword,
|
|
claudeChannelMode,
|
|
verbose: opts.verbose ?? false,
|
|
});
|
|
bridge.setServer(server);
|
|
|
|
server.server.setNotificationHandler(ClaudePermissionRequestSchema, async ({ params }) => {
|
|
await bridge.handleClaudePermissionRequest({
|
|
requestId: params.request_id,
|
|
toolName: params.tool_name,
|
|
description: params.description,
|
|
inputPreview: params.input_preview,
|
|
});
|
|
});
|
|
registerChannelMcpTools(server, bridge);
|
|
|
|
return {
|
|
server,
|
|
bridge,
|
|
start: async () => {
|
|
await bridge.start();
|
|
},
|
|
close: async () => {
|
|
await bridge.close();
|
|
await server.close();
|
|
},
|
|
};
|
|
}
|
|
|
|
export async function serveOpenClawChannelMcp(opts: OpenClawMcpServeOptions = {}): Promise<void> {
|
|
const { server, start, close } = await createOpenClawChannelMcpServer(opts);
|
|
const transport = new StdioServerTransport();
|
|
|
|
let shuttingDown = false;
|
|
let resolveClosed!: () => void;
|
|
const closed = new Promise<void>((resolve) => {
|
|
resolveClosed = resolve;
|
|
});
|
|
|
|
const shutdown = () => {
|
|
if (shuttingDown) {
|
|
return;
|
|
}
|
|
shuttingDown = true;
|
|
process.stdin.off("end", shutdown);
|
|
process.stdin.off("close", shutdown);
|
|
process.off("SIGINT", shutdown);
|
|
process.off("SIGTERM", shutdown);
|
|
transport["onclose"] = undefined;
|
|
void close().finally(resolveClosed);
|
|
};
|
|
|
|
transport["onclose"] = shutdown;
|
|
process.stdin.once("end", shutdown);
|
|
process.stdin.once("close", shutdown);
|
|
process.once("SIGINT", shutdown);
|
|
process.once("SIGTERM", shutdown);
|
|
|
|
try {
|
|
await server.connect(transport);
|
|
await start();
|
|
await closed;
|
|
} finally {
|
|
shutdown();
|
|
await closed;
|
|
}
|
|
}
|