Skip to main content
Glama
tokenValidation.test.ts6.47 kB
/** * Tests for tokenValidation utility */ import { describe, it, expect } from 'vitest'; import { validateTokenLimit, validateBulkTokenLimit, validateSingleTokenLimit, } from '../../src/utils/tokenValidation.js'; import { RESOURCE_LIMITS } from '../../src/constants.js'; import { ERROR_CODES } from '../../src/errors/errorCodes.js'; describe('tokenValidation', () => { describe('validateTokenLimit', () => { it('should validate content within token limits', () => { const content = 'a'.repeat(1000); // Small content const result = validateTokenLimit({ content, toolName: 'local_ripgrep', }); expect(result.isValid).toBe(true); expect(result.estimatedTokens).toBeLessThan( RESOURCE_LIMITS.MCP_MAX_TOKENS ); expect(result.maxTokens).toBe(RESOURCE_LIMITS.MCP_MAX_TOKENS); expect(result.errorCode).toBeUndefined(); expect(result.hints).toBeUndefined(); }); it('should reject content exceeding token limits', () => { // Create content that exceeds the token limit const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_ripgrep', }); expect(result.isValid).toBe(false); expect(result.estimatedTokens).toBeGreaterThan( RESOURCE_LIMITS.MCP_MAX_TOKENS ); expect(result.errorCode).toBe(ERROR_CODES.RESPONSE_TOO_LARGE); expect(result.hints).toBeDefined(); expect(result.hints!.length).toBeGreaterThan(0); }); it('should provide single operation hints for queryCount = 1', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_ripgrep', queryCount: 1, }); expect(result.isValid).toBe(false); expect(result.hints).toBeDefined(); expect(result.hints!.some((h) => h.includes('SOLUTIONS:'))).toBe(true); expect(result.hints!.some((h) => h.includes('matchString'))).toBe(true); }); it('should provide bulk operation hints for queryCount > 1', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_ripgrep', queryCount: 5, }); expect(result.isValid).toBe(false); expect(result.hints).toBeDefined(); expect(result.hints!.some((h) => h.includes('Bulk Operation'))).toBe( true ); expect(result.hints!.some((h) => h.includes('currently 5 queries'))).toBe( true ); }); it('should include tool-specific hints for local_ripgrep', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_ripgrep', }); expect(result.isValid).toBe(false); expect(result.hints!.some((h) => h.includes('discovery'))).toBe(true); expect(result.hints!.some((h) => h.includes('excludeDir'))).toBe(true); }); it('should include tool-specific hints for local_view_structure', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_view_structure', }); expect(result.isValid).toBe(false); expect(result.hints!.some((h) => h.includes('depth'))).toBe(true); }); it('should include context in hints when provided', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateTokenLimit({ content, toolName: 'local_ripgrep', context: 'Searching node_modules', }); expect(result.isValid).toBe(false); expect( result.hints!.some((h) => h.includes('Searching node_modules')) ).toBe(true); }); it('should handle empty content', () => { const result = validateTokenLimit({ content: '', toolName: 'local_ripgrep', }); expect(result.isValid).toBe(true); expect(result.estimatedTokens).toBe(0); }); it('should estimate tokens correctly', () => { const content = 'a'.repeat(400); // Should be 100 tokens (400 / 4) const result = validateTokenLimit({ content, toolName: 'local_ripgrep', }); expect(result.estimatedTokens).toBe(100); }); }); describe('validateBulkTokenLimit', () => { it('should validate content with query count', () => { const content = 'a'.repeat(1000); const result = validateBulkTokenLimit(content, 'local_ripgrep', 3); expect(result.isValid).toBe(true); }); it('should provide bulk-specific hints when over limit', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateBulkTokenLimit(content, 'local_ripgrep', 10); expect(result.isValid).toBe(false); expect(result.hints!.some((h) => h.includes('10 queries'))).toBe(true); }); }); describe('validateSingleTokenLimit', () => { it('should validate single operation content', () => { const content = 'a'.repeat(1000); const result = validateSingleTokenLimit(content, 'local_fetch_content'); expect(result.isValid).toBe(true); }); it('should include context when provided', () => { const charsNeeded = RESOURCE_LIMITS.MCP_MAX_TOKENS * RESOURCE_LIMITS.CHARS_PER_TOKEN + 1000; const content = 'a'.repeat(charsNeeded); const result = validateSingleTokenLimit( content, 'local_fetch_content', 'Reading large file' ); expect(result.isValid).toBe(false); expect(result.hints!.some((h) => h.includes('Reading large file'))).toBe( true ); }); }); });

Latest Blog Posts

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/bgauryy/octocode-mcp'

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