Skip to main content
Glama

MCP Time Server Node

by pshempel
security-input-limits-research.jsβ€’5.73 kB
#!/usr/bin/env node /** * Security Research: Input Length Limits * * This script tests the memory and performance impact of large inputs * to determine appropriate limits for the MCP Time Server. */ console.log('=== Security Research: Input Length Limits ===\n'); // Test 1: Memory usage of large strings console.log('1. Testing memory impact of large strings:'); function getMemoryUsage() { const used = process.memoryUsage(); return { heapUsed: Math.round((used.heapUsed / 1024 / 1024) * 100) / 100, external: Math.round((used.external / 1024 / 1024) * 100) / 100, total: Math.round(((used.heapUsed + used.external) / 1024 / 1024) * 100) / 100, }; } // Baseline memory const baseline = getMemoryUsage(); console.log('Baseline memory:', baseline); // Test different string sizes const stringSizes = [ { size: 100, label: '100 chars' }, { size: 1000, label: '1KB' }, { size: 10000, label: '10KB' }, { size: 100000, label: '100KB' }, { size: 1000000, label: '1MB' }, ]; const strings = {}; stringSizes.forEach(({ size, label }) => { strings[label] = 'x'.repeat(size); const current = getMemoryUsage(); const delta = current.total - baseline.total; console.log(`After ${label}: ${current.total}MB (Ξ”${delta}MB)`); }); console.log('\n2. Testing JSON.stringify with large inputs:'); // Test JSON.stringify performance stringSizes.forEach(({ size, label }) => { if (size <= 100000) { // Don't test 1MB for JSON const testObj = { timezone: 'x'.repeat(size), format: 'yyyy-MM-dd', include_offset: true, }; const start = process.hrtime.bigint(); const json = JSON.stringify(testObj); const end = process.hrtime.bigint(); const timeMs = Number(end - start) / 1000000; console.log(`JSON.stringify ${label}: ${timeMs.toFixed(2)}ms, output: ${json.length} chars`); } }); console.log('\n3. Testing date-fns parseISO with large strings:'); const { parseISO, isValid } = require('date-fns'); // Test parseISO with various malformed inputs const malformedInputs = [ { input: 'x'.repeat(100), label: '100 chars of x' }, { input: 'x'.repeat(1000), label: '1000 chars of x' }, { input: '2024-01-01' + 'x'.repeat(1000), label: 'valid date + 1000 chars' }, { input: '\x00'.repeat(100), label: '100 null bytes' }, { input: 'πŸ”₯'.repeat(100), label: '100 emoji' }, { input: '\u202E' + '2024-01-01', label: 'RTL override + date' }, ]; malformedInputs.forEach(({ input, label }) => { try { const start = process.hrtime.bigint(); const parsed = parseISO(input); const valid = isValid(parsed); const end = process.hrtime.bigint(); const timeMs = Number(end - start) / 1000000; console.log(`parseISO ${label}: ${timeMs.toFixed(2)}ms, valid: ${valid}`); } catch (error) { console.log(`parseISO ${label}: ERROR - ${error.message}`); } }); console.log('\n4. Testing timezone validation with large strings:'); const { getTimezoneOffset } = require('date-fns-tz'); const timezoneInputs = [ { input: 'x'.repeat(100), label: '100 chars' }, { input: 'x'.repeat(1000), label: '1000 chars' }, { input: 'America/New_York' + 'x'.repeat(1000), label: 'valid + 1000 chars' }, { input: '../../../etc/passwd', label: 'path traversal attempt' }, { input: 'America/New_York\x00malicious', label: 'null byte injection' }, ]; timezoneInputs.forEach(({ input, label }) => { try { const start = process.hrtime.bigint(); const offset = getTimezoneOffset(input, new Date()); const end = process.hrtime.bigint(); const timeMs = Number(end - start) / 1000000; const valid = !isNaN(offset); console.log(`Timezone ${label}: ${timeMs.toFixed(2)}ms, valid: ${valid}`); } catch (error) { console.log(`Timezone ${label}: ERROR - ${error.message}`); } }); console.log('\n5. Testing array size limits:'); // Test large arrays const arraySizes = [100, 365, 1000, 10000]; arraySizes.forEach((size) => { const array = Array(size).fill('2024-01-01'); const memBefore = getMemoryUsage(); const start = process.hrtime.bigint(); const json = JSON.stringify(array); const end = process.hrtime.bigint(); const memAfter = getMemoryUsage(); const timeMs = Number(end - start) / 1000000; const memDelta = memAfter.total - memBefore.total; console.log( `Array ${size} items: ${timeMs.toFixed(2)}ms, Ξ”mem: ${memDelta}MB, JSON: ${json.length} chars`, ); }); console.log('\n6. Cache key collision testing:'); // Test potential cache key collisions const crypto = require('crypto'); function testCacheKey(input) { // Current approach - direct concatenation const directKey = `current_${input}_format_true`; // Proposed approach - hash const hash = crypto.createHash('sha256').update(directKey).digest('hex').substring(0, 16); return { directKey, hash }; } const collisionTests = [ 'America/New_York', 'America/New_York\x00malicious', 'America/New_York/../../../etc', 'x'.repeat(1000), ]; console.log('Testing cache key approaches:'); collisionTests.forEach((input) => { const { directKey, hash } = testCacheKey(input); console.log( `Input: "${input.substring(0, 30)}${input.length > 30 ? '...' : ''}" (${input.length} chars)`, ); console.log(` Direct: ${directKey.length} chars`); console.log(` Hash: ${hash} (16 chars)`); }); console.log('\n=== Recommendations ==='); console.log('1. String inputs should be limited to 1000 characters'); console.log('2. Array inputs should be limited to 365 items (1 year of dates)'); console.log('3. Cache keys should be hashed to prevent memory issues'); console.log('4. All inputs handle null bytes and unicode safely'); console.log('5. No significant performance impact up to 1KB strings');

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/pshempel/mcp-time-server-node'

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