Skip to main content
Glama

Self-Improving Memory MCP

by SuperPiTT
validation.test.js6.55 kB
import { expect } from 'chai'; import { EntityType, EntitySchema, RelationSchema, SearchQuerySchema, sanitize, validate, validateSafe, validateBatch } from '../../src/schemas/validation.js'; describe('Validation Schemas', () => { describe('sanitize utilities', () => { it('should sanitize string by trimming and removing HTML tags', () => { const dirty = ' <script>alert("xss")</script>Hello '; const clean = sanitize.string(dirty); expect(clean).to.equal('scriptalert("xss")/scriptHello'); expect(clean).to.not.include('<'); expect(clean).to.not.include('>'); }); it('should remove control characters', () => { const dirty = 'Hello\x00\x01\x02World'; const clean = sanitize.string(dirty); expect(clean).to.equal('HelloWorld'); }); it('should handle non-string input', () => { expect(sanitize.string(null)).to.equal(''); expect(sanitize.string(undefined)).to.equal(''); expect(sanitize.string(123)).to.equal(''); }); it('should sanitize string array', () => { const dirty = [' tag1 ', '<tag2>', null, 'tag3']; const clean = sanitize.stringArray(dirty); expect(clean).to.deep.equal(['tag1', 'tag2', 'tag3']); }); it('should sanitize entity name more strictly', () => { const dirty = 'My Entity! @#$ Name_123'; const clean = sanitize.entityName(dirty); expect(clean).to.equal('My Entity Name_123'); expect(clean).to.not.match(/[!@#$]/); }); }); describe('EntityType enum', () => { it('should accept valid entity types', () => { const validTypes = [ 'project', 'component', 'dependency', 'error', 'solution', 'pattern', 'insight', 'decision', 'user-intent', 'user-preference', 'requirement', 'style-rule', 'architectural-pattern', 'tool-preference', 'session-snapshot', 'continuation-point', 'work-in-progress' ]; validTypes.forEach(type => { expect(() => EntityType.parse(type)).to.not.throw(); }); }); it('should reject invalid entity types', () => { expect(() => EntityType.parse('invalid-type')).to.throw(); expect(() => EntityType.parse('')).to.throw(); expect(() => EntityType.parse(null)).to.throw(); }); }); describe('EntitySchema', () => { it('should validate correct entity', () => { const validEntity = { name: 'Test Entity', entityType: 'component', observations: ['Observation 1', 'Observation 2'] }; const result = EntitySchema.parse(validEntity); expect(result).to.deep.equal(validEntity); }); it('should reject entity with empty name', () => { const invalidEntity = { name: '', entityType: 'component', observations: ['Test'] }; expect(() => EntitySchema.parse(invalidEntity)).to.throw(); }); it('should reject entity with name too long', () => { const invalidEntity = { name: 'a'.repeat(201), entityType: 'component', observations: ['Test'] }; expect(() => EntitySchema.parse(invalidEntity)).to.throw(/too long/); }); it('should reject entity with no observations', () => { const invalidEntity = { name: 'Test', entityType: 'component', observations: [] }; expect(() => EntitySchema.parse(invalidEntity)).to.throw(/At least one observation/); }); it('should trim entity name', () => { const entity = { name: ' Trimmed Name ', entityType: 'component', observations: ['Test'] }; const result = EntitySchema.parse(entity); expect(result.name).to.equal('Trimmed Name'); }); it('should reject observation too long', () => { const invalidEntity = { name: 'Test', entityType: 'component', observations: ['a'.repeat(10001)] }; expect(() => EntitySchema.parse(invalidEntity)).to.throw(/too long/); }); }); describe('RelationSchema', () => { it('should validate correct relation', () => { const validRelation = { from: 'Entity A', to: 'Entity B', relationType: 'uses' }; const result = RelationSchema.parse(validRelation); expect(result).to.deep.equal(validRelation); }); it('should reject relation with empty from', () => { const invalid = { from: '', to: 'Entity B', relationType: 'uses' }; expect(() => RelationSchema.parse(invalid)).to.throw(); }); it('should reject relation with empty relationType', () => { const invalid = { from: 'A', to: 'B', relationType: '' }; expect(() => RelationSchema.parse(invalid)).to.throw(); }); }); describe('SearchQuerySchema', () => { it('should validate correct search query', () => { const validQuery = { query: 'test search', limit: 10 }; const result = SearchQuerySchema.parse(validQuery); expect(result).to.deep.equal(validQuery); }); it('should accept query without limit', () => { const validQuery = { query: 'test' }; const result = SearchQuerySchema.parse(validQuery); expect(result.query).to.equal('test'); expect(result.limit).to.be.undefined; }); it('should reject empty query', () => { expect(() => SearchQuerySchema.parse({ query: '' })).to.throw(/cannot be empty/); }); it('should reject query too long', () => { const tooLong = { query: 'a'.repeat(501) }; expect(() => SearchQuerySchema.parse(tooLong)).to.throw(/too long/); }); it('should reject invalid limit', () => { expect(() => SearchQuerySchema.parse({ query: 'test', limit: -1 })).to.throw(); expect(() => SearchQuerySchema.parse({ query: 'test', limit: 0 })).to.throw(); expect(() => SearchQuerySchema.parse({ query: 'test', limit: 101 })).to.throw(); expect(() => SearchQuerySchema.parse({ query: 'test', limit: 1.5 })).to.throw(); }); }); // Note: validate, validateSafe, validateBatch helpers are available but not exported // These tests are commented out pending export implementation /* describe('validate helper', () => { it('should validate and return data', () => { const data = { query: 'test', limit: 5 }; const result = validate(SearchQuerySchema, data); expect(result).to.deep.equal(data); }); }); */ });

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/SuperPiTT/self-improving-memory-mcp'

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