openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
241 lines (240 loc) • 7.07 kB
JavaScript
import { c as isRecord } from "./utils-CCC-BEJH.js";
import { E as validateConfigObjectWithPlugins, m as readSourceConfigSnapshot } from "./io-Gi7-pyU-.js";
import { i as replaceConfigFile } from "./config-C9RxTsn1.js";
import { r as normalizeConfiguredMcpServers, t as canonicalizeConfiguredMcpServer } from "./mcp-config-normalize-BZTreK5Y.js";
//#region src/auto-reply/reply/config-value.ts
function parseConfigValue(raw) {
const trimmed = raw.trim();
if (!trimmed) return { error: "Missing value." };
if (trimmed.startsWith("{") || trimmed.startsWith("[")) try {
return { value: JSON.parse(trimmed) };
} catch (err) {
return { error: `Invalid JSON: ${String(err)}` };
}
if (trimmed === "true") return { value: true };
if (trimmed === "false") return { value: false };
if (trimmed === "null") return { value: null };
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
const num = Number(trimmed);
if (Number.isFinite(num)) return { value: num };
}
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) try {
return { value: JSON.parse(trimmed) };
} catch {
return { value: trimmed.slice(1, -1) };
}
return { value: trimmed };
}
//#endregion
//#region src/config/mcp-config.ts
function normalizeToolSelectionList(value) {
if (!value) return;
const normalized = Array.from(new Set(value.map((entry) => entry.trim()).filter((entry) => entry.length > 0))).toSorted((a, b) => a.localeCompare(b));
return normalized.length > 0 ? normalized : void 0;
}
async function listConfiguredMcpServers() {
const snapshot = await readSourceConfigSnapshot();
if (!snapshot.valid) return {
ok: false,
path: snapshot.path,
error: "Config file is invalid; fix it before using MCP config commands."
};
const sourceConfig = snapshot.sourceConfig ?? snapshot.resolved;
return {
ok: true,
path: snapshot.path,
config: structuredClone(sourceConfig),
mcpServers: normalizeConfiguredMcpServers(sourceConfig.mcp?.servers),
baseHash: snapshot.hash
};
}
async function updateConfiguredMcpServerTools(params) {
const name = params.name.trim();
if (!name) return {
ok: false,
path: "",
error: "MCP server name is required."
};
const loaded = await listConfiguredMcpServers();
if (!loaded.ok) return loaded;
if (!Object.hasOwn(loaded.mcpServers, name)) return {
ok: true,
path: loaded.path,
config: loaded.config,
mcpServers: loaded.mcpServers,
updated: false
};
const next = structuredClone(loaded.config);
const servers = normalizeConfiguredMcpServers(next.mcp?.servers);
const server = { ...servers[name] };
if (params.tools === null) delete server.toolFilter;
else {
const include = normalizeToolSelectionList(params.tools.include);
const exclude = normalizeToolSelectionList(params.tools.exclude);
if (include || exclude) server.toolFilter = {
...include ? { include } : {},
...exclude ? { exclude } : {}
};
else delete server.toolFilter;
}
servers[name] = server;
next.mcp = {
...next.mcp,
servers
};
const validated = validateConfigObjectWithPlugins(next);
if (!validated.ok) {
const issue = validated.issues[0];
return {
ok: false,
path: loaded.path,
error: `Config invalid after MCP tool selection update (${issue.path}: ${issue.message}).`
};
}
await replaceConfigFile({
nextConfig: validated.config,
baseHash: loaded.baseHash
});
return {
ok: true,
path: loaded.path,
config: validated.config,
mcpServers: servers,
updated: true
};
}
async function updateConfiguredMcpServer(params) {
const name = params.name.trim();
if (!name) return {
ok: false,
path: "",
error: "MCP server name is required."
};
const loaded = await listConfiguredMcpServers();
if (!loaded.ok) return loaded;
if (!Object.hasOwn(loaded.mcpServers, name)) return {
ok: true,
path: loaded.path,
config: loaded.config,
mcpServers: loaded.mcpServers,
updated: false
};
const next = structuredClone(loaded.config);
const servers = normalizeConfiguredMcpServers(next.mcp?.servers);
servers[name] = canonicalizeConfiguredMcpServer(params.update({ ...servers[name] }));
next.mcp = {
...next.mcp,
servers
};
const validated = validateConfigObjectWithPlugins(next);
if (!validated.ok) {
const issue = validated.issues[0];
return {
ok: false,
path: loaded.path,
error: `Config invalid after MCP configure (${issue.path}: ${issue.message}).`
};
}
await replaceConfigFile({
nextConfig: validated.config,
baseHash: loaded.baseHash
});
return {
ok: true,
path: loaded.path,
config: validated.config,
mcpServers: servers,
updated: true
};
}
async function setConfiguredMcpServer(params) {
const name = params.name.trim();
if (!name) return {
ok: false,
path: "",
error: "MCP server name is required."
};
if (!isRecord(params.server)) return {
ok: false,
path: "",
error: "MCP server config must be a JSON object."
};
const loaded = await listConfiguredMcpServers();
if (!loaded.ok) return loaded;
const next = structuredClone(loaded.config);
const servers = normalizeConfiguredMcpServers(next.mcp?.servers);
servers[name] = canonicalizeConfiguredMcpServer(params.server);
next.mcp = {
...next.mcp,
servers
};
const validated = validateConfigObjectWithPlugins(next);
if (!validated.ok) {
const issue = validated.issues[0];
return {
ok: false,
path: loaded.path,
error: `Config invalid after MCP set (${issue.path}: ${issue.message}).`
};
}
await replaceConfigFile({
nextConfig: validated.config,
baseHash: loaded.baseHash
});
return {
ok: true,
path: loaded.path,
config: validated.config,
mcpServers: servers
};
}
async function unsetConfiguredMcpServer(params) {
const name = params.name.trim();
if (!name) return {
ok: false,
path: "",
error: "MCP server name is required."
};
const loaded = await listConfiguredMcpServers();
if (!loaded.ok) return loaded;
if (!Object.hasOwn(loaded.mcpServers, name)) return {
ok: true,
path: loaded.path,
config: loaded.config,
mcpServers: loaded.mcpServers,
removed: false
};
const next = structuredClone(loaded.config);
const servers = normalizeConfiguredMcpServers(next.mcp?.servers);
delete servers[name];
if (Object.keys(servers).length > 0) next.mcp = {
...next.mcp,
servers
};
else if (next.mcp) {
delete next.mcp.servers;
if (Object.keys(next.mcp).length === 0) delete next.mcp;
}
const validated = validateConfigObjectWithPlugins(next);
if (!validated.ok) {
const issue = validated.issues[0];
return {
ok: false,
path: loaded.path,
error: `Config invalid after MCP unset (${issue.path}: ${issue.message}).`
};
}
await replaceConfigFile({
nextConfig: validated.config,
baseHash: loaded.baseHash
});
return {
ok: true,
path: loaded.path,
config: validated.config,
mcpServers: servers,
removed: true
};
}
//#endregion
export { updateConfiguredMcpServerTools as a, updateConfiguredMcpServer as i, setConfiguredMcpServer as n, parseConfigValue as o, unsetConfiguredMcpServer as r, listConfiguredMcpServers as t };