Plugins: warn on unsupported bundle MCP transports

This commit is contained in:
Vincent Koc 2026-03-16 18:38:42 -07:00
parent cb45d7d737
commit 320c718c7e
3 changed files with 117 additions and 0 deletions

View File

@ -28,6 +28,11 @@ export type EnabledBundleMcpConfigResult = {
config: BundleMcpConfig;
diagnostics: BundleMcpDiagnostic[];
};
export type BundleMcpRuntimeSupport = {
hasSupportedStdioServer: boolean;
unsupportedServerNames: string[];
diagnostics: string[];
};
const MANIFEST_PATH_BY_FORMAT: Record<PluginBundleFormat, string> = {
claude: CLAUDE_BUNDLE_MANIFEST_RELATIVE_PATH,
@ -292,6 +297,28 @@ function loadBundleMcpConfig(params: {
return { config: merged, diagnostics: [] };
}
export function inspectBundleMcpRuntimeSupport(params: {
pluginId: string;
rootDir: string;
bundleFormat: PluginBundleFormat;
}): BundleMcpRuntimeSupport {
const loaded = loadBundleMcpConfig(params);
const unsupportedServerNames: string[] = [];
let hasSupportedStdioServer = false;
for (const [serverName, server] of Object.entries(loaded.config.mcpServers)) {
if (typeof server.command === "string" && server.command.trim().length > 0) {
hasSupportedStdioServer = true;
continue;
}
unsupportedServerNames.push(serverName);
}
return {
hasSupportedStdioServer,
unsupportedServerNames,
diagnostics: loaded.diagnostics,
};
}
export function loadEnabledBundleMcpConfig(params: {
workspaceDir: string;
cfg?: OpenClawConfig;

View File

@ -471,6 +471,65 @@ describe("bundle plugins", () => {
).toBe(false);
});
it("warns when bundle MCP only declares unsupported non-stdio transports", () => {
useNoBundledPlugins();
const workspaceDir = makeTempDir();
const stateDir = makeTempDir();
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", "claude-mcp-url");
fs.mkdirSync(path.join(bundleRoot, ".claude-plugin"), { recursive: true });
fs.writeFileSync(
path.join(bundleRoot, ".claude-plugin", "plugin.json"),
JSON.stringify({
name: "Claude MCP URL",
}),
"utf-8",
);
fs.writeFileSync(
path.join(bundleRoot, ".mcp.json"),
JSON.stringify({
mcpServers: {
remoteProbe: {
url: "http://127.0.0.1:8787/mcp",
},
},
}),
"utf-8",
);
const registry = withEnv(
{
OPENCLAW_HOME: stateDir,
OPENCLAW_STATE_DIR: stateDir,
},
() =>
loadOpenClawPlugins({
workspaceDir,
config: {
plugins: {
entries: {
"claude-mcp-url": {
enabled: true,
},
},
},
},
cache: false,
}),
);
const plugin = registry.plugins.find((entry) => entry.id === "claude-mcp-url");
expect(plugin?.status).toBe("loaded");
expect(plugin?.bundleCapabilities).toEqual(expect.arrayContaining(["mcpServers"]));
expect(
registry.diagnostics.some(
(diag) =>
diag.pluginId === "claude-mcp-url" &&
diag.message.includes("stdio only today") &&
diag.message.includes("remoteProbe"),
),
).toBe(true);
});
it("treats Cursor command roots as supported bundle skill surfaces", () => {
useNoBundledPlugins();
const workspaceDir = makeTempDir();

View File

@ -11,6 +11,7 @@ import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveUserPath } from "../utils.js";
import { inspectBundleMcpRuntimeSupport } from "./bundle-mcp.js";
import { clearPluginCommands } from "./commands.js";
import {
applyTestPluginDefaults,
@ -1115,6 +1116,36 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
message: `bundle capability detected but not wired into OpenClaw yet: ${capability}`,
});
}
if (
enableState.enabled &&
record.rootDir &&
record.bundleFormat &&
(record.bundleCapabilities ?? []).includes("mcpServers")
) {
const runtimeSupport = inspectBundleMcpRuntimeSupport({
pluginId: record.id,
rootDir: record.rootDir,
bundleFormat: record.bundleFormat,
});
for (const message of runtimeSupport.diagnostics) {
registry.diagnostics.push({
level: "warn",
pluginId: record.id,
source: record.source,
message,
});
}
if (runtimeSupport.unsupportedServerNames.length > 0) {
registry.diagnostics.push({
level: "warn",
pluginId: record.id,
source: record.source,
message:
"bundle MCP servers use unsupported transports or incomplete configs " +
`(stdio only today): ${runtimeSupport.unsupportedServerNames.join(", ")}`,
});
}
}
registry.plugins.push(record);
seenIds.set(pluginId, candidate.origin);
continue;