Skip to main content
Glama

hypertool-mcp

extensionConfig.test.tsโ€ข9.96 kB
/** * Extension Configuration Manager Tests */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { ExtensionConfigManager } from "./extensionConfig.js"; import { getFeatureFlagService } from "./featureFlagService.js"; import { mkdtemp, rm, writeFile } from "fs/promises"; import { join } from "path"; import { tmpdir } from "os"; describe("ExtensionConfigManager", () => { let tempDir: string; let configPath: string; let configManager: ExtensionConfigManager; beforeEach(async () => { // Enable DXT feature flag for testing const featureFlagService = getFeatureFlagService(); featureFlagService.forceSet("dxtEnabled", true); // Create temporary directory tempDir = await mkdtemp(join(tmpdir(), "hypertool-test-")); configPath = join(tempDir, "config.json"); configManager = new ExtensionConfigManager(configPath); }); afterEach(async () => { // Reset feature flag service const featureFlagService = getFeatureFlagService(); featureFlagService.reset(); // Cleanup try { await rm(tempDir, { recursive: true, force: true }); } catch { // Ignore cleanup errors } }); describe("load", () => { it("should load default config when file doesn't exist", async () => { const config = await configManager.load(); expect(config.extensions).toBeDefined(); expect(config.extensions!.autoDiscovery).toBe(true); expect(config.extensions!.settings).toEqual({}); }); it("should return disabled config when DXT feature flag is disabled", async () => { // Disable DXT feature flag const featureFlagService = getFeatureFlagService(); featureFlagService.forceSet("dxtEnabled", false); const config = await configManager.load(); expect(config.extensions).toBeDefined(); expect(config.extensions!.autoDiscovery).toBe(false); expect(config.extensions!.directory).toBe(""); expect(config.extensions!.settings).toEqual({}); }); it("should load existing config file", async () => { const testConfig = { extensions: { autoDiscovery: false, settings: { "test-extension": { isEnabled: true, userConfig: { api_key: "test-key", }, }, }, }, }; await writeFile(configPath, JSON.stringify(testConfig)); const config = await configManager.load(); expect(config.extensions!.autoDiscovery).toBe(false); expect(config.extensions!.settings["test-extension"]).toEqual({ isEnabled: true, userConfig: { api_key: "test-key", }, }); }); it("should handle malformed config file gracefully", async () => { await writeFile(configPath, "invalid json"); const config = await configManager.load(); // Should fall back to defaults expect(config.extensions).toBeDefined(); expect(config.extensions!.autoDiscovery).toBe(true); }); }); describe("save", () => { it("should save config to file", async () => { const config = { extensions: { autoDiscovery: true, settings: { "test-extension": { isEnabled: false, userConfig: { timeout: 30, }, }, }, }, }; await configManager.save(config); // Load and verify const loadedConfig = await configManager.load(); expect(loadedConfig.extensions!.settings["test-extension"]).toEqual({ isEnabled: false, userConfig: { timeout: 30, }, }); }); }); describe("extension settings management", () => { beforeEach(async () => { await configManager.load(); }); it("should get extension settings", async () => { await configManager.setExtensionSettings("test-ext", { isEnabled: true, userConfig: { key: "value" }, }); const settings = configManager.getExtensionSettings("test-ext"); expect(settings).toEqual({ isEnabled: true, userConfig: { key: "value" }, }); }); it("should return undefined for non-existent extension", () => { const settings = configManager.getExtensionSettings("non-existent"); expect(settings).toBeUndefined(); }); it("should enable extension", async () => { await configManager.setExtensionSettings("test-ext", { isEnabled: false, userConfig: { key: "value" }, }); await configManager.enableExtension("test-ext"); const settings = configManager.getExtensionSettings("test-ext"); expect(settings!.isEnabled).toBe(true); expect(settings!.userConfig).toEqual({ key: "value" }); }); it("should disable extension", async () => { await configManager.setExtensionSettings("test-ext", { isEnabled: true, userConfig: { key: "value" }, }); await configManager.disableExtension("test-ext"); const settings = configManager.getExtensionSettings("test-ext"); expect(settings!.isEnabled).toBe(false); expect(settings!.userConfig).toEqual({ key: "value" }); }); it("should update extension user config", async () => { await configManager.setExtensionSettings("test-ext", { isEnabled: true, userConfig: { old_key: "old_value" }, }); await configManager.updateExtensionUserConfig("test-ext", { new_key: "new_value", number_key: 42, }); const settings = configManager.getExtensionSettings("test-ext"); expect(settings!.isEnabled).toBe(true); expect(settings!.userConfig).toEqual({ new_key: "new_value", number_key: 42, }); }); it("should remove extension", async () => { await configManager.setExtensionSettings("test-ext", { isEnabled: true, userConfig: { key: "value" }, }); await configManager.removeExtension("test-ext"); const settings = configManager.getExtensionSettings("test-ext"); expect(settings).toBeUndefined(); }); it("should get extension names", async () => { await configManager.setExtensionSettings("ext1", { isEnabled: true }); await configManager.setExtensionSettings("ext2", { isEnabled: false }); const names = configManager.getExtensionNames(); expect(names).toEqual(expect.arrayContaining(["ext1", "ext2"])); }); }); describe("auto-discovery management", () => { beforeEach(async () => { await configManager.load(); }); it("should get auto-discovery setting", () => { const isEnabled = configManager.isAutoDiscoveryEnabled(); expect(isEnabled).toBe(true); // Default }); it("should set auto-discovery setting", async () => { await configManager.setAutoDiscovery(false); const isEnabled = configManager.isAutoDiscoveryEnabled(); expect(isEnabled).toBe(false); }); }); describe("directory management", () => { beforeEach(async () => { await configManager.load(); }); it("should get extensions directory", () => { const dir = configManager.getExtensionsDirectory(); expect(dir).toContain(".toolprint/hypertool-mcp/extensions"); }); it("should set extensions directory", async () => { const customDir = "/custom/extensions/path"; await configManager.setExtensionsDirectory(customDir); const dir = configManager.getExtensionsDirectory(); expect(dir).toBe(customDir); }); }); describe("validateConfig", () => { it("should validate correct config", () => { const config = { extensions: { directory: "/path/to/extensions", autoDiscovery: true, settings: { "test-ext": { isEnabled: true, userConfig: { key: "value", }, }, }, }, }; const result = configManager.validateConfig(config); expect(result.isValid).toBe(true); expect(result.errors).toHaveLength(0); }); it("should detect invalid directory type", () => { const config = { extensions: { directory: 123, autoDiscovery: true, settings: {}, }, }; const result = configManager.validateConfig(config); expect(result.isValid).toBe(false); expect(result.errors).toContain("extensions.directory must be a string"); }); it("should detect invalid autoDiscovery type", () => { const config = { extensions: { autoDiscovery: "true", settings: {}, }, }; const result = configManager.validateConfig(config); expect(result.isValid).toBe(false); expect(result.errors).toContain( "extensions.autoDiscovery must be a boolean" ); }); it("should detect invalid settings structure", () => { const config = { extensions: { settings: "not an object", }, }; const result = configManager.validateConfig(config); expect(result.isValid).toBe(false); expect(result.errors).toContain("extensions.settings must be an object"); }); it("should detect invalid extension setting", () => { const config = { extensions: { settings: { "test-ext": { isEnabled: "not a boolean", userConfig: [], }, }, }, }; const result = configManager.validateConfig(config); expect(result.isValid).toBe(false); expect(result.errors).toContain( "extensions.settings.test-ext.isEnabled must be a boolean" ); expect(result.errors).toContain( "extensions.settings.test-ext.userConfig must be an object" ); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/toolprint/hypertool-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server