Skip to main content
Glama
integration.test.ts14.5 kB
/** * Integration Tests for MCP-Titan Memory Server * Tests end-to-end workflows through all 11 MCP tools */ import * as tf from '@tensorflow/tfjs-node'; import { TitanMemoryServer } from '../index.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; describe('MCP Integration Tests', () => { let server: TitanMemoryServer; let testDir: string; beforeAll(async () => { // Create temporary directory for test files testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-titan-test-')); }); afterAll(async () => { // Cleanup test directory try { await fs.rm(testDir, { recursive: true, force: true }); } catch (error) { console.warn('Failed to cleanup test directory:', error); } }); beforeEach(() => { server = new TitanMemoryServer({ memoryPath: testDir }); }); afterEach(() => { // Dispose tensors tf.disposeVariables(); }); describe('Complete Workflow: Init → Forward → Train → Save → Load', () => { test('should complete full lifecycle without errors', async () => { // Step 1: Initialize model const initResult = await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100, transformerLayers: 2 }); expect(initResult).toBeDefined(); expect(initResult.content).toBeDefined(); expect(initResult.content[0].text).toContain('initialized successfully'); // Step 2: Forward pass with text const forwardResult = await (server as any).server.callTool('forward_pass', { x: 'test input text' }); expect(forwardResult).toBeDefined(); expect(forwardResult.content[0].text).toContain('Forward pass completed'); // Step 3: Training step const trainResult = await (server as any).server.callTool('train_step', { x_t: 'current input', x_next: 'next input' }); expect(trainResult).toBeDefined(); expect(trainResult.content[0].text).toContain('Training step completed'); expect(trainResult.content[0].text).toContain('Loss:'); // Step 4: Get memory state const stateResult = await (server as any).server.callTool('get_memory_state', {}); expect(stateResult).toBeDefined(); expect(stateResult.content[0].text).toContain('Memory State'); expect(stateResult.content[0].text).toContain('Capacity'); // Step 5: Save checkpoint const checkpointPath = path.join(testDir, 'test-checkpoint.json'); const saveResult = await (server as any).server.callTool('save_checkpoint', { path: checkpointPath }); expect(saveResult).toBeDefined(); expect(saveResult.content[0].text).toContain('Checkpoint saved'); // Verify file exists const fileExists = await fs.access(checkpointPath).then(() => true).catch(() => false); expect(fileExists).toBe(true); // Step 6: Load checkpoint const loadResult = await (server as any).server.callTool('load_checkpoint', { path: checkpointPath }); expect(loadResult).toBeDefined(); expect(loadResult.content[0].text).toContain('Checkpoint loaded'); }); }); describe('Input Validation', () => { beforeEach(async () => { await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); }); test('should reject empty string input', async () => { const result = await (server as any).server.callTool('forward_pass', { x: '' }); expect(result.content[0].text).toContain('cannot be empty'); }); test('should reject invalid array input with NaN', async () => { const result = await (server as any).server.callTool('forward_pass', { x: [1, 2, NaN, 4] }); expect(result.content[0].text).toContain('valid finite numbers'); }); test('should reject mismatched dimensions in train_step', async () => { const result = await (server as any).server.callTool('train_step', { x_t: [1, 2, 3], x_next: [1, 2, 3, 4, 5] // Different length }); expect(result.content[0].text).toContain("dimensions don't match"); }); test('should sanitize control characters in text input', async () => { const result = await (server as any).server.callTool('forward_pass', { x: 'test\x00\x01\x02text' // Control characters }); // Should succeed but sanitize the input expect(result.content[0].text).toContain('Forward pass completed'); }); }); describe('Path Security', () => { beforeEach(async () => { await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); }); test('should prevent path traversal in save_checkpoint', async () => { const result = await (server as any).server.callTool('save_checkpoint', { path: '../../../etc/passwd' }); expect(result.content[0].text).toContain('Path traversal detected'); }); test('should prevent path traversal in load_checkpoint', async () => { const result = await (server as any).server.callTool('load_checkpoint', { path: '../../../etc/passwd' }); expect(result.content[0].text).toContain('Path traversal detected'); }); test('should allow valid paths within allowed directories', async () => { const validPath = path.join(testDir, 'valid-checkpoint.json'); // Save first const saveResult = await (server as any).server.callTool('save_checkpoint', { path: validPath }); expect(saveResult.content[0].text).toContain('Checkpoint saved'); // Then load const loadResult = await (server as any).server.callTool('load_checkpoint', { path: validPath }); expect(loadResult.content[0].text).toContain('Checkpoint loaded'); }); }); describe('Dimension Validation', () => { test('should detect dimension mismatch on checkpoint load', async () => { // Initialize with inputDim=128 await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); const checkpointPath = path.join(testDir, 'dim-test.json'); // Save checkpoint await (server as any).server.callTool('save_checkpoint', { path: checkpointPath }); // Reinitialize with different inputDim await (server as any).server.callTool('init_model', { inputDim: 256, // Different dimension memorySlots: 100 }); // Try to load checkpoint with mismatched dimensions const loadResult = await (server as any).server.callTool('load_checkpoint', { path: checkpointPath }); expect(loadResult.content[0].text).toContain('dimension mismatch'); }); }); describe('Memory Operations', () => { beforeEach(async () => { await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100, transformerLayers: 2 }); }); test('should handle manifold_step', async () => { // Create base and velocity arrays const base = new Array(128).fill(0).map(() => Math.random()); const velocity = new Array(128).fill(0).map(() => Math.random() * 0.1); const result = await (server as any).server.callTool('manifold_step', { base, velocity }); expect(result).toBeDefined(); expect(result.content[0].text).toContain('Manifold step completed'); }); test('should handle prune_memory with custom threshold', async () => { // Add some memories first await (server as any).server.callTool('forward_pass', { x: 'memory 1' }); await (server as any).server.callTool('forward_pass', { x: 'memory 2' }); const result = await (server as any).server.callTool('prune_memory', { threshold: 0.7 }); expect(result).toBeDefined(); expect(result.content[0].text).toContain('pruned'); }); test('should reset gradients', async () => { const result = await (server as any).server.callTool('reset_gradients', {}); expect(result).toBeDefined(); expect(result.content[0].text).toContain('Gradients reset'); }); }); describe('Help Tool', () => { test('should provide help for all tools', async () => { const result = await (server as any).server.callTool('help', {}); expect(result).toBeDefined(); expect(result.content[0].text).toContain('Available tools'); expect(result.content[0].text).toContain('init_model'); expect(result.content[0].text).toContain('forward_pass'); expect(result.content[0].text).toContain('train_step'); }); test('should provide detailed help with verbose flag', async () => { const result = await (server as any).server.callTool('help', { verbose: true }); expect(result).toBeDefined(); expect(result.content[0].text).toContain('Available tools'); }); }); describe('Error Recovery', () => { beforeEach(async () => { await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); }); test('should handle graceful failure on invalid operations', async () => { // Try to load non-existent checkpoint const result = await (server as any).server.callTool('load_checkpoint', { path: path.join(testDir, 'nonexistent.json') }); expect(result).toBeDefined(); expect(result.content[0].text).toContain('Failed'); }); test('should continue operating after failed operations', async () => { // Cause an error await (server as any).server.callTool('load_checkpoint', { path: path.join(testDir, 'nonexistent.json') }); // Should still be able to perform operations const result = await (server as any).server.callTool('forward_pass', { x: 'test after error' }); expect(result.content[0].text).toContain('Forward pass completed'); }); }); describe('Concurrent Operations', () => { beforeEach(async () => { await (server as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); }); test('should handle multiple forward passes in sequence', async () => { const results = []; for (let i = 0; i < 5; i++) { const result = await (server as any).server.callTool('forward_pass', { x: `input ${i}` }); results.push(result); } expect(results).toHaveLength(5); results.forEach(result => { expect(result.content[0].text).toContain('Forward pass completed'); }); }); test('should handle alternating forward and train operations', async () => { for (let i = 0; i < 3; i++) { const forwardResult = await (server as any).server.callTool('forward_pass', { x: `input ${i}` }); expect(forwardResult.content[0].text).toContain('Forward pass completed'); const trainResult = await (server as any).server.callTool('train_step', { x_t: `input ${i}`, x_next: `input ${i + 1}` }); expect(trainResult.content[0].text).toContain('Training step completed'); } }); }); describe('Memory State Persistence', () => { test('should persist and restore memory across server instances', async () => { // First instance const server1 = new TitanMemoryServer({ memoryPath: testDir }); await (server1 as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); await (server1 as any).server.callTool('forward_pass', { x: 'persistent memory test' }); const checkpointPath = path.join(testDir, 'persist-test.json'); await (server1 as any).server.callTool('save_checkpoint', { path: checkpointPath }); // Second instance const server2 = new TitanMemoryServer({ memoryPath: testDir }); await (server2 as any).server.callTool('init_model', { inputDim: 128, memorySlots: 100 }); const loadResult = await (server2 as any).server.callTool('load_checkpoint', { path: checkpointPath }); expect(loadResult.content[0].text).toContain('Checkpoint loaded'); // Should be able to continue operations const forwardResult = await (server2 as any).server.callTool('forward_pass', { x: 'after restore' }); expect(forwardResult.content[0].text).toContain('Forward pass completed'); }); }); });

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/henryhawke/mcp-titan'

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