src / mcp / config.test.ts
src / mcp / config.test.ts
import assert from "node:assert/strict";
import test from "node:test";
import { readMcpConfig } from "./config.js";
const RENAMED_VARS = [
"MCP_MADE_FOR_BIONIC",
"MCP_MADE_FOR",
"GENERATE_IMAGE_PREVIEW_IN_CHAT",
"DRAW_THINGS_HOST",
"GENERATE_IMAGE_DRAW_THINGS_HOST",
"DRAW_THINGS_HTTP_PORT",
"GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT",
"DRAW_THINGS_GRPC_PORT",
"GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT",
"EMBED_PNG_METADATA",
"GENERATE_IMAGE_EMBED_PNG_METADATA",
"DRAW_THINGS_CUSTOM_CONFIGS_PATH",
"GENERATE_IMAGE_CUSTOM_CONFIGS_PATH",
"HTTP_SERVER_PORT",
"CLIENT_DB_LOCATION",
] as const;
/** Isolates a test's env mutations: snapshots CHAT_WORKING_DIRECTORIES + every renamed var, restores afterward. */
function withEnv(overrides: Record<string, string | undefined>, run: () => void): void {
const keys = ["CHAT_WORKING_DIRECTORIES", ...RENAMED_VARS] as const;
const before = Object.fromEntries(keys.map((key) => [key, process.env[key]]));
try {
process.env.CHAT_WORKING_DIRECTORIES = "/tmp/generate-image-mcp-config-test";
for (const key of RENAMED_VARS) delete process.env[key];
for (const [key, value] of Object.entries(overrides)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
run();
} finally {
for (const [key, value] of Object.entries(before)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
}
}
test("readMcpConfig prefers the new, un-prefixed env vars over the deprecated GENERATE_IMAGE_-prefixed ones", () => {
withEnv(
{
DRAW_THINGS_HOST: "10.0.0.1",
GENERATE_IMAGE_DRAW_THINGS_HOST: "127.0.0.1",
DRAW_THINGS_HTTP_PORT: "1111",
GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT: "2222",
DRAW_THINGS_GRPC_PORT: "3333",
GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT: "4444",
EMBED_PNG_METADATA: "false",
GENERATE_IMAGE_EMBED_PNG_METADATA: "true",
DRAW_THINGS_CUSTOM_CONFIGS_PATH: "/new/custom_configs.json",
GENERATE_IMAGE_CUSTOM_CONFIGS_PATH: "/old/custom_configs.json",
},
() => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "10.0.0.1");
assert.equal(config.drawThingsHttpPort, 1111);
assert.equal(config.drawThingsGrpcPort, 3333);
assert.equal(config.embedPngMetadata, false);
assert.equal(config.customConfigsPath, "/new/custom_configs.json");
}
);
});
test("readMcpConfig falls back to the deprecated GENERATE_IMAGE_-prefixed vars when the new ones are unset", () => {
withEnv(
{
GENERATE_IMAGE_DRAW_THINGS_HOST: "192.168.1.1",
GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT: "5555",
GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT: "6666",
GENERATE_IMAGE_EMBED_PNG_METADATA: "false",
GENERATE_IMAGE_CUSTOM_CONFIGS_PATH: "/old/custom_configs.json",
},
() => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "192.168.1.1");
assert.equal(config.drawThingsHttpPort, 5555);
assert.equal(config.drawThingsGrpcPort, 6666);
assert.equal(config.embedPngMetadata, false);
assert.equal(config.customConfigsPath, "/old/custom_configs.json");
}
);
});
test("readMcpConfig uses its documented defaults when neither the new nor the old var is set", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "127.0.0.1");
assert.equal(config.drawThingsHttpPort, 7860);
assert.equal(config.drawThingsGrpcPort, 7859);
assert.equal(config.embedPngMetadata, true);
assert.match(config.customConfigsPath, /custom_configs\.json$/);
});
});
test("readMcpConfig prefers MCP_MADE_FOR_BIONIC over the deprecated, inverted GENERATE_IMAGE_PREVIEW_IN_CHAT", () => {
withEnv({ MCP_MADE_FOR_BIONIC: "false", GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
});
test("readMcpConfig falls back to the deprecated GENERATE_IMAGE_PREVIEW_IN_CHAT, inverted, when MCP_MADE_FOR_BIONIC is unset", () => {
withEnv({ GENERATE_IMAGE_PREVIEW_IN_CHAT: "true" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
withEnv({ GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "bionic");
assert.equal(config.previewInChat, false);
});
});
test("readMcpConfig defaults to the bionic preset when neither var is set", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "bionic");
assert.equal(config.previewInChat, false);
});
});
test("readMcpConfig prefers MCP_MADE_FOR over MCP_MADE_FOR_BIONIC and the legacy fallback", () => {
withEnv({ MCP_MADE_FOR: "generic", MCP_MADE_FOR_BIONIC: "true", GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/.lmstudio/scratchpads (expanded, not a literal tilde) when unset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/\.lmstudio\/scratchpads$/);
assert.ok(!config.chatWorkingDirectories.includes("~"));
});
});
test("readMcpConfig uses an explicit CHAT_WORKING_DIRECTORIES over the default", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: "/tmp/explicit-scratchpads" }, () => {
const config = readMcpConfig();
assert.equal(config.chatWorkingDirectories, "/tmp/explicit-scratchpads");
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/.unsloth/studio/sandbox for the unsloth preset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined, MCP_MADE_FOR: "unsloth" }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/\.unsloth\/studio\/sandbox$/);
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/Pictures for the generic preset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined, MCP_MADE_FOR: "generic" }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/Pictures$/);
});
});
test("readMcpConfig defaults clientDbLocation to ~/.unsloth/studio/studio.db, overridable via CLIENT_DB_LOCATION", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.match(config.clientDbLocation, /^\/.*\/\.unsloth\/studio\/studio\.db$/);
});
withEnv({ CLIENT_DB_LOCATION: "/tmp/custom-studio.db" }, () => {
const config = readMcpConfig();
assert.equal(config.clientDbLocation, "/tmp/custom-studio.db");
});
});
test("readMcpConfig defaults HTTP_SERVER_PORT per preset (bionic 54770, unsloth 54780, generic 54790)", () => {
withEnv({}, () => {
assert.equal(readMcpConfig().httpServerPort, 54770);
});
withEnv({ MCP_MADE_FOR: "unsloth" }, () => {
assert.equal(readMcpConfig().httpServerPort, 54780);
});
withEnv({ MCP_MADE_FOR: "generic" }, () => {
assert.equal(readMcpConfig().httpServerPort, 54790);
});
withEnv({ MCP_MADE_FOR: "unsloth", HTTP_SERVER_PORT: "9999" }, () => {
assert.equal(readMcpConfig().httpServerPort, 9999);
});
});
import assert from "node:assert/strict";
import test from "node:test";
import { readMcpConfig } from "./config.js";
const RENAMED_VARS = [
"MCP_MADE_FOR_BIONIC",
"MCP_MADE_FOR",
"GENERATE_IMAGE_PREVIEW_IN_CHAT",
"DRAW_THINGS_HOST",
"GENERATE_IMAGE_DRAW_THINGS_HOST",
"DRAW_THINGS_HTTP_PORT",
"GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT",
"DRAW_THINGS_GRPC_PORT",
"GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT",
"EMBED_PNG_METADATA",
"GENERATE_IMAGE_EMBED_PNG_METADATA",
"DRAW_THINGS_CUSTOM_CONFIGS_PATH",
"GENERATE_IMAGE_CUSTOM_CONFIGS_PATH",
"HTTP_SERVER_PORT",
"CLIENT_DB_LOCATION",
] as const;
/** Isolates a test's env mutations: snapshots CHAT_WORKING_DIRECTORIES + every renamed var, restores afterward. */
function withEnv(overrides: Record<string, string | undefined>, run: () => void): void {
const keys = ["CHAT_WORKING_DIRECTORIES", ...RENAMED_VARS] as const;
const before = Object.fromEntries(keys.map((key) => [key, process.env[key]]));
try {
process.env.CHAT_WORKING_DIRECTORIES = "/tmp/generate-image-mcp-config-test";
for (const key of RENAMED_VARS) delete process.env[key];
for (const [key, value] of Object.entries(overrides)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
run();
} finally {
for (const [key, value] of Object.entries(before)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
}
}
test("readMcpConfig prefers the new, un-prefixed env vars over the deprecated GENERATE_IMAGE_-prefixed ones", () => {
withEnv(
{
DRAW_THINGS_HOST: "10.0.0.1",
GENERATE_IMAGE_DRAW_THINGS_HOST: "127.0.0.1",
DRAW_THINGS_HTTP_PORT: "1111",
GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT: "2222",
DRAW_THINGS_GRPC_PORT: "3333",
GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT: "4444",
EMBED_PNG_METADATA: "false",
GENERATE_IMAGE_EMBED_PNG_METADATA: "true",
DRAW_THINGS_CUSTOM_CONFIGS_PATH: "/new/custom_configs.json",
GENERATE_IMAGE_CUSTOM_CONFIGS_PATH: "/old/custom_configs.json",
},
() => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "10.0.0.1");
assert.equal(config.drawThingsHttpPort, 1111);
assert.equal(config.drawThingsGrpcPort, 3333);
assert.equal(config.embedPngMetadata, false);
assert.equal(config.customConfigsPath, "/new/custom_configs.json");
}
);
});
test("readMcpConfig falls back to the deprecated GENERATE_IMAGE_-prefixed vars when the new ones are unset", () => {
withEnv(
{
GENERATE_IMAGE_DRAW_THINGS_HOST: "192.168.1.1",
GENERATE_IMAGE_DRAW_THINGS_HTTP_PORT: "5555",
GENERATE_IMAGE_DRAW_THINGS_GRPC_PORT: "6666",
GENERATE_IMAGE_EMBED_PNG_METADATA: "false",
GENERATE_IMAGE_CUSTOM_CONFIGS_PATH: "/old/custom_configs.json",
},
() => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "192.168.1.1");
assert.equal(config.drawThingsHttpPort, 5555);
assert.equal(config.drawThingsGrpcPort, 6666);
assert.equal(config.embedPngMetadata, false);
assert.equal(config.customConfigsPath, "/old/custom_configs.json");
}
);
});
test("readMcpConfig uses its documented defaults when neither the new nor the old var is set", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.equal(config.drawThingsHost, "127.0.0.1");
assert.equal(config.drawThingsHttpPort, 7860);
assert.equal(config.drawThingsGrpcPort, 7859);
assert.equal(config.embedPngMetadata, true);
assert.match(config.customConfigsPath, /custom_configs\.json$/);
});
});
test("readMcpConfig prefers MCP_MADE_FOR_BIONIC over the deprecated, inverted GENERATE_IMAGE_PREVIEW_IN_CHAT", () => {
withEnv({ MCP_MADE_FOR_BIONIC: "false", GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
});
test("readMcpConfig falls back to the deprecated GENERATE_IMAGE_PREVIEW_IN_CHAT, inverted, when MCP_MADE_FOR_BIONIC is unset", () => {
withEnv({ GENERATE_IMAGE_PREVIEW_IN_CHAT: "true" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
withEnv({ GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "bionic");
assert.equal(config.previewInChat, false);
});
});
test("readMcpConfig defaults to the bionic preset when neither var is set", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "bionic");
assert.equal(config.previewInChat, false);
});
});
test("readMcpConfig prefers MCP_MADE_FOR over MCP_MADE_FOR_BIONIC and the legacy fallback", () => {
withEnv({ MCP_MADE_FOR: "generic", MCP_MADE_FOR_BIONIC: "true", GENERATE_IMAGE_PREVIEW_IN_CHAT: "false" }, () => {
const config = readMcpConfig();
assert.equal(config.preset.name, "generic");
assert.equal(config.previewInChat, true);
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/.lmstudio/scratchpads (expanded, not a literal tilde) when unset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/\.lmstudio\/scratchpads$/);
assert.ok(!config.chatWorkingDirectories.includes("~"));
});
});
test("readMcpConfig uses an explicit CHAT_WORKING_DIRECTORIES over the default", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: "/tmp/explicit-scratchpads" }, () => {
const config = readMcpConfig();
assert.equal(config.chatWorkingDirectories, "/tmp/explicit-scratchpads");
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/.unsloth/studio/sandbox for the unsloth preset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined, MCP_MADE_FOR: "unsloth" }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/\.unsloth\/studio\/sandbox$/);
});
});
test("readMcpConfig defaults CHAT_WORKING_DIRECTORIES to ~/Pictures for the generic preset", () => {
withEnv({ CHAT_WORKING_DIRECTORIES: undefined, MCP_MADE_FOR: "generic" }, () => {
const config = readMcpConfig();
assert.match(config.chatWorkingDirectories, /^\/.*\/Pictures$/);
});
});
test("readMcpConfig defaults clientDbLocation to ~/.unsloth/studio/studio.db, overridable via CLIENT_DB_LOCATION", () => {
withEnv({}, () => {
const config = readMcpConfig();
assert.match(config.clientDbLocation, /^\/.*\/\.unsloth\/studio\/studio\.db$/);
});
withEnv({ CLIENT_DB_LOCATION: "/tmp/custom-studio.db" }, () => {
const config = readMcpConfig();
assert.equal(config.clientDbLocation, "/tmp/custom-studio.db");
});
});
test("readMcpConfig defaults HTTP_SERVER_PORT per preset (bionic 54770, unsloth 54780, generic 54790)", () => {
withEnv({}, () => {
assert.equal(readMcpConfig().httpServerPort, 54770);
});
withEnv({ MCP_MADE_FOR: "unsloth" }, () => {
assert.equal(readMcpConfig().httpServerPort, 54780);
});
withEnv({ MCP_MADE_FOR: "generic" }, () => {
assert.equal(readMcpConfig().httpServerPort, 54790);
});
withEnv({ MCP_MADE_FOR: "unsloth", HTTP_SERVER_PORT: "9999" }, () => {
assert.equal(readMcpConfig().httpServerPort, 9999);
});
});