mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 02:11:41 +00:00
refactor(mcp): trim internal server exports (#108076)
* refactor(mcp): remove dead internal exports * chore(deadcode): refresh export baseline
This commit is contained in:
committed by
GitHub
parent
c4cd643c1b
commit
92d06e51bb
@@ -24,6 +24,8 @@ const rootEntries = [
|
||||
"src/plugins/runtime/index.ts!",
|
||||
"src/plugins/source-display.ts!",
|
||||
"src/mcp/codex-supervision-tools-serve.ts!",
|
||||
// Spawned by generated system-agent MCP configs; this stdio entry is not statically imported.
|
||||
"src/mcp/openclaw-tools-serve.ts!",
|
||||
"scripts/qa/render-maturity-docs.ts!",
|
||||
bundledPluginFile("telegram", "src/audit.ts", "!"),
|
||||
bundledPluginFile("telegram", "src/token.ts", "!"),
|
||||
|
||||
@@ -235,14 +235,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
|
||||
"src/logging/diagnostic-run-activity.ts: markDiagnosticToolStartedForTest",
|
||||
"src/logging/redact-internal.ts: withFullContextToolPayloadRedaction",
|
||||
"src/logging/secret-redaction-registry.ts: resetSecretRedactionRegistryForTest",
|
||||
"src/mcp/channel-bridge.ts: shouldRetryInitialMcpGatewayConnect",
|
||||
"src/mcp/channel-server.ts: createOpenClawChannelMcpServer",
|
||||
"src/mcp/channel-server.ts: OpenClawChannelBridge",
|
||||
"src/mcp/openclaw-tools-serve-config.ts: OPENCLAW_TOOLS_MCP_SYSTEM_AGENT_SURFACE_ENV",
|
||||
"src/mcp/openclaw-tools-serve-config.ts: OpenClawToolsMcpToolId",
|
||||
"src/mcp/openclaw-tools-serve-config.ts: resolveOpenClawToolsMcpSystemAgentApproval",
|
||||
"src/mcp/openclaw-tools-serve-config.ts: resolveOpenClawToolsMcpSystemAgentSurface",
|
||||
"src/mcp/openclaw-tools-serve-config.ts: resolveOpenClawToolsMcpToolSelection",
|
||||
"src/music-generation/capabilities.ts: resolveMusicGenerationMode",
|
||||
"src/node-host/invoke.ts: testing",
|
||||
"src/plugin-state/plugin-state-store.sqlite.ts: probePluginStateStore",
|
||||
|
||||
@@ -25,7 +25,6 @@ export const KNIP_OPTIONAL_UNUSED_FILE_ALLOWLIST = [
|
||||
"src/gateway/gateway-cli-backend.live-helpers.ts",
|
||||
"src/gateway/gateway-cli-backend.live-probe-helpers.ts",
|
||||
"src/gateway/gateway-codex-harness.live-helpers.ts",
|
||||
"src/mcp/openclaw-tools-serve.ts",
|
||||
"src/mcp/plugin-tools-handlers.ts",
|
||||
"src/mcp/plugin-tools-serve.ts",
|
||||
"src/mcp/tools-stdio-server.ts",
|
||||
|
||||
@@ -663,8 +663,7 @@ export class OpenClawChannelBridge {
|
||||
}
|
||||
}
|
||||
|
||||
/** Decide whether startup should wait for a retryable Gateway connect failure to recover. */
|
||||
export function shouldRetryInitialMcpGatewayConnect(error: Error): boolean {
|
||||
function shouldRetryInitialMcpGatewayConnect(error: Error): boolean {
|
||||
if (
|
||||
error.name === "GatewayClientRequestError" &&
|
||||
"retryable" in error &&
|
||||
|
||||
68
src/mcp/channel-server-runtime.ts
Normal file
68
src/mcp/channel-server-runtime.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.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";
|
||||
|
||||
async function resolveMcpConfig(config: OpenClawConfig | undefined): Promise<OpenClawConfig> {
|
||||
if (config) {
|
||||
return config;
|
||||
}
|
||||
const { getRuntimeConfig } = await import("../config/config.js");
|
||||
return getRuntimeConfig();
|
||||
}
|
||||
|
||||
export async function createChannelMcpRuntime(
|
||||
opts: {
|
||||
gatewayUrl?: string;
|
||||
gatewayToken?: string;
|
||||
gatewayPassword?: string;
|
||||
config?: OpenClawConfig;
|
||||
claudeChannelMode?: ClaudeChannelMode;
|
||||
verbose?: boolean;
|
||||
} = {},
|
||||
): Promise<{
|
||||
server: McpServer;
|
||||
bridge: OpenClawChannelBridge;
|
||||
start: () => Promise<void>;
|
||||
close: () => Promise<void>;
|
||||
}> {
|
||||
const cfg = await resolveMcpConfig(opts.config);
|
||||
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();
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -3,9 +3,8 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { z } from "zod";
|
||||
import { shouldRetryInitialMcpGatewayConnect } from "./channel-bridge.js";
|
||||
import { OpenClawChannelBridge } from "./channel-bridge.js";
|
||||
import { createOpenClawChannelMcpServer } from "./channel-server.js";
|
||||
import { createChannelMcpRuntime } from "./channel-server-runtime.js";
|
||||
import { extractAttachmentsFromMessage } from "./channel-shared.js";
|
||||
|
||||
const ClaudeChannelNotificationSchema = z.object({
|
||||
@@ -25,7 +24,7 @@ const ClaudePermissionNotificationSchema = z.object({
|
||||
});
|
||||
|
||||
async function connectMcpWithoutGateway(params?: { claudeChannelMode?: "auto" | "on" | "off" }) {
|
||||
const serverHarness = await createOpenClawChannelMcpServer({
|
||||
const serverHarness = await createChannelMcpRuntime({
|
||||
claudeChannelMode: params?.claudeChannelMode ?? "auto",
|
||||
config: {} as never,
|
||||
verbose: false,
|
||||
@@ -84,22 +83,7 @@ function requireFirstMockCall(mock: { mock: { calls: unknown[][] } }, label: str
|
||||
return call;
|
||||
}
|
||||
|
||||
function gatewayRequestError(retryable: boolean): Error {
|
||||
return Object.assign(new Error(retryable ? "gateway busy" : "auth failed"), {
|
||||
name: "GatewayClientRequestError",
|
||||
retryable,
|
||||
});
|
||||
}
|
||||
|
||||
describe("openclaw channel mcp server", () => {
|
||||
test("keeps initial MCP gateway connection alive through transient connect errors", () => {
|
||||
expect(
|
||||
shouldRetryInitialMcpGatewayConnect(new Error("gateway request timeout for connect")),
|
||||
).toBe(true);
|
||||
expect(shouldRetryInitialMcpGatewayConnect(gatewayRequestError(true))).toBe(true);
|
||||
expect(shouldRetryInitialMcpGatewayConnect(gatewayRequestError(false))).toBe(false);
|
||||
});
|
||||
|
||||
describe("gateway-backed flows", () => {
|
||||
describe("gateway integration", () => {
|
||||
test("returns conversation and message payloads in primary MCP content", async () => {
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
// Channel MCP server wires channel bridge tools into an MCP server instance.
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.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";
|
||||
import { createChannelMcpRuntime } from "./channel-server-runtime.js";
|
||||
|
||||
/**
|
||||
* MCP stdio server assembly for OpenClaw channel conversations.
|
||||
@@ -13,75 +7,11 @@ import { getChannelMcpCapabilities, registerChannelMcpTools } from "./channel-to
|
||||
* This module wires config, the Gateway bridge, protocol notifications, and
|
||||
* registered tools into a lifecycle that callers can either embed or serve.
|
||||
*/
|
||||
export { OpenClawChannelBridge } from "./channel-bridge.js";
|
||||
|
||||
/** Options accepted by the channel MCP server factory and stdio entry point. */
|
||||
type OpenClawMcpServeOptions = {
|
||||
gatewayUrl?: string;
|
||||
gatewayToken?: string;
|
||||
gatewayPassword?: string;
|
||||
config?: OpenClawConfig;
|
||||
claudeChannelMode?: ClaudeChannelMode;
|
||||
verbose?: boolean;
|
||||
};
|
||||
|
||||
async function resolveMcpConfig(config: OpenClawConfig | undefined): Promise<OpenClawConfig> {
|
||||
if (config) {
|
||||
return config;
|
||||
}
|
||||
const { getRuntimeConfig } = await import("../config/config.js");
|
||||
return getRuntimeConfig();
|
||||
}
|
||||
|
||||
/** Create an in-process channel MCP server plus explicit start and close hooks. */
|
||||
export async function createOpenClawChannelMcpServer(opts: OpenClawMcpServeOptions = {}): Promise<{
|
||||
server: McpServer;
|
||||
bridge: OpenClawChannelBridge;
|
||||
start: () => Promise<void>;
|
||||
close: () => Promise<void>;
|
||||
}> {
|
||||
const cfg = await resolveMcpConfig(opts.config);
|
||||
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();
|
||||
},
|
||||
};
|
||||
}
|
||||
type OpenClawMcpServeOptions = NonNullable<Parameters<typeof createChannelMcpRuntime>[0]>;
|
||||
|
||||
/** Serve the channel MCP server over stdio until transport or process shutdown. */
|
||||
export async function serveOpenClawChannelMcp(opts: OpenClawMcpServeOptions = {}): Promise<void> {
|
||||
const { server, start, close } = await createOpenClawChannelMcpServer(opts);
|
||||
const { server, start, close } = await createChannelMcpRuntime(opts);
|
||||
const transport = new StdioServerTransport();
|
||||
|
||||
let shuttingDown = false;
|
||||
|
||||
@@ -28,6 +28,10 @@ describe("check-deadcode-exports", () => {
|
||||
expect(knipConfig.workspaces["."].entry).toContain("src/agents/sessions/extension-sdk.ts!");
|
||||
});
|
||||
|
||||
it("models the spawned system-agent MCP stdio entry", () => {
|
||||
expect(knipConfig.workspaces["."].entry).toContain("src/mcp/openclaw-tools-serve.ts!");
|
||||
});
|
||||
|
||||
it("parses all compact export sections and expands symbol lists", () => {
|
||||
expect(
|
||||
parseKnipCompactUnusedExports(`
|
||||
|
||||
Reference in New Issue
Block a user