Skip to main content
Glama

Stampchain MCP Server

Official
configuration.test.ts9.96 kB
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; /** * Tests for configuration management system */ import { loadConfiguration, ServerConfigSchema, mergeConfigs } from '../../config/index.js'; import { writeFileSync, unlinkSync, mkdirSync, rmSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; describe('Configuration System', () => { const testConfigDir = join(tmpdir(), 'stampchain-mcp-test'); const testConfigPath = join(testConfigDir, 'test-config.json'); // Create test directory beforeEach(() => { try { mkdirSync(testConfigDir, { recursive: true }); } catch { // Directory might already exist } }); // Clean up test files afterEach(() => { try { rmSync(testConfigDir, { recursive: true, force: true }); } catch { // Directory might not exist } }); describe('ServerConfigSchema', () => { it('should validate default configuration', () => { const defaultConfig = { name: 'stampchain-mcp', version: '0.1.0', logging: { level: 'info', enableColors: true, }, api: { baseUrl: 'https://stampchain.io/api', timeout: 30000, retries: 3, retryDelay: 1000, }, registry: { maxTools: 1000, validateOnRegister: true, allowDuplicateNames: false, }, development: { enableStackTraces: false, }, }; const result = ServerConfigSchema.safeParse(defaultConfig); expect(result.success).toBe(true); }); it('should apply default values for missing fields', () => { const minimalConfig = { name: 'test-server', version: '1.0.0', }; const result = ServerConfigSchema.safeParse(minimalConfig); expect(result.success).toBe(true); if (result.success) { expect(result.data.logging.level).toBe('info'); expect(result.data.api.timeout).toBe(30000); expect(result.data.registry.maxTools).toBe(1000); } }); it('should reject invalid log levels', () => { const invalidConfig = { name: 'test-server', version: '1.0.0', logging: { level: 'invalid-level', }, }; const result = ServerConfigSchema.safeParse(invalidConfig); expect(result.success).toBe(false); }); it('should validate timeout ranges', () => { const invalidConfig = { name: 'test-server', version: '1.0.0', api: { timeout: -1000, // Invalid negative timeout }, }; const result = ServerConfigSchema.safeParse(invalidConfig); expect(result.success).toBe(false); }); it('should validate retry configuration', () => { const invalidConfig = { name: 'test-server', version: '1.0.0', api: { retries: -1, // Invalid negative retries }, }; const result = ServerConfigSchema.safeParse(invalidConfig); expect(result.success).toBe(false); }); it('should validate registry limits', () => { const invalidConfig = { name: 'test-server', version: '1.0.0', registry: { maxTools: 0, // Invalid zero limit }, }; const result = ServerConfigSchema.safeParse(invalidConfig); expect(result.success).toBe(false); }); }); describe('mergeConfigs', () => { it('should merge flat configuration objects', () => { const base = { a: 1, b: 2, c: 3 }; const override = { b: 20, d: 4 }; const result = mergeConfigs(base, override); expect(result).toEqual({ a: 1, b: 20, // Overridden c: 3, d: 4, // Added }); }); it('should merge nested configuration objects', () => { const base = { logging: { level: 'info', enableColors: true }, api: { timeout: 30000, retries: 3 }, }; const override = { logging: { level: 'debug' }, api: { timeout: 10000 }, registry: { maxTools: 500 }, }; const result = mergeConfigs(base, override); expect(result).toEqual({ logging: { level: 'debug', enableColors: true }, api: { timeout: 10000, retries: 3 }, registry: { maxTools: 500 }, }); }); it('should handle null and undefined values', () => { const base = { a: 1, b: 2 }; const override = { b: null, c: undefined, d: 3 }; const result = mergeConfigs(base, override); expect(result).toEqual({ a: 1, b: null, c: undefined, d: 3, }); }); it('should not mutate original objects', () => { const base = { nested: { value: 1 } }; const override = { nested: { value: 2 } }; const originalBase = JSON.parse(JSON.stringify(base)); const originalOverride = JSON.parse(JSON.stringify(override)); mergeConfigs(base, override); expect(base).toEqual(originalBase); expect(override).toEqual(originalOverride); }); }); describe('loadConfiguration', () => { beforeEach(() => { // Clear environment variables delete process.env.STAMPCHAIN_LOG_LEVEL; delete process.env.STAMPCHAIN_API_URL; delete process.env.STAMPCHAIN_API_TIMEOUT; delete process.env.STAMPCHAIN_MAX_TOOLS; }); it('should load default configuration', () => { const config = loadConfiguration(); expect(config.name).toBe('stampchain-mcp'); expect(config.version).toBe('0.1.0'); expect(config.logging.level).toBe('info'); expect(config.api.baseUrl).toBe('https://stampchain.io/api'); }); it('should override with environment variables', () => { process.env.STAMPCHAIN_LOG_LEVEL = 'debug'; process.env.STAMPCHAIN_API_URL = 'https://custom.api.com'; process.env.STAMPCHAIN_API_TIMEOUT = '15000'; process.env.STAMPCHAIN_MAX_TOOLS = '500'; const config = loadConfiguration(); expect(config.logging.level).toBe('debug'); expect(config.api.baseUrl).toBe('https://custom.api.com'); expect(config.api.timeout).toBe(15000); expect(config.registry.maxTools).toBe(500); }); it('should load configuration from file', () => { const fileConfig = { name: 'custom-server', logging: { level: 'warn' }, api: { timeout: 20000 }, }; // Create test config file writeFileSync(testConfigPath, JSON.stringify(fileConfig, null, 2)); const config = loadConfiguration({ configFile: testConfigPath }); expect(config.name).toBe('custom-server'); expect(config.logging.level).toBe('warn'); expect(config.api.timeout).toBe(20000); // Default values should still be present expect(config.api.baseUrl).toBe('https://stampchain.io/api'); }); it('should override with CLI arguments', () => { const cliArgs = { logLevel: 'error', apiUrl: 'https://cli.api.com', debug: true, }; const config = loadConfiguration({ cliArgs }); expect(config.logging.level).toBe('error'); expect(config.api.baseUrl).toBe('https://cli.api.com'); expect(config.development.enableStackTraces).toBe(true); }); it('should apply configuration precedence (CLI > ENV > File > Default)', () => { // Set up all sources process.env.STAMPCHAIN_LOG_LEVEL = 'warn'; const fileConfig = { logging: { level: 'info' }, api: { timeout: 25000 }, }; writeFileSync(testConfigPath, JSON.stringify(fileConfig, null, 2)); const cliArgs = { logLevel: 'debug', // Should override everything }; const config = loadConfiguration({ configFile: testConfigPath, cliArgs, }); expect(config.logging.level).toBe('debug'); // CLI wins expect(config.api.timeout).toBe(25000); // From file }); it('should handle missing configuration file gracefully', () => { expect(() => { loadConfiguration({ configFile: '/non/existent/path.json' }); }).not.toThrow(); }); it('should handle invalid JSON in configuration file', () => { writeFileSync(testConfigPath, 'invalid json content'); expect(() => { loadConfiguration({ configFile: testConfigPath }); }).toThrow('Failed to parse configuration file'); }); it('should validate final configuration', () => { const invalidConfig = { logging: { level: 'invalid-level' }, }; writeFileSync(testConfigPath, JSON.stringify(invalidConfig, null, 2)); expect(() => { loadConfiguration({ configFile: testConfigPath }); }).toThrow('Configuration validation failed'); }); it('should handle boolean environment variables', () => { process.env.STAMPCHAIN_ENABLE_COLORS = 'false'; process.env.STAMPCHAIN_VALIDATE_ON_REGISTER = 'true'; const config = loadConfiguration(); expect(config.logging.enableColors).toBe(false); expect(config.registry.validateOnRegister).toBe(true); }); it('should handle numeric environment variables', () => { process.env.STAMPCHAIN_API_TIMEOUT = '45000'; process.env.STAMPCHAIN_API_RETRIES = '5'; process.env.STAMPCHAIN_MAX_TOOLS = '2000'; const config = loadConfiguration(); expect(config.api.timeout).toBe(45000); expect(config.api.retries).toBe(5); expect(config.registry.maxTools).toBe(2000); }); it('should ignore invalid environment variable values', () => { process.env.STAMPCHAIN_API_TIMEOUT = 'not-a-number'; process.env.STAMPCHAIN_MAX_TOOLS = 'invalid'; const config = loadConfiguration(); // Should fall back to defaults expect(config.api.timeout).toBe(30000); expect(config.registry.maxTools).toBe(1000); }); }); });

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/stampchain-io/stampchain-mcp'

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