Skip to main content
Glama
token-limiter.ts3.74 kB
/** * Token limiting utilities for MCP responses * Estimates token count and applies limits to prevent excessive token usage */ export interface TokenLimitConfig { maxTokens: number; includeMetadata: boolean; } export interface TokenLimitResult<T> { data: T[]; truncated: boolean; originalCount: number; returnedCount: number; estimatedTokens: number; metadata?: { message: string; suggestedActions?: string[]; }; } /** * Rough token estimation for JSON objects * Uses a conservative estimate of ~4 characters per token */ export function estimateTokens(obj: any): number { const jsonString = JSON.stringify(obj); return Math.ceil(jsonString.length / 4); } /** * Get MCP token limit from environment or use default */ export function getMcpTokenLimit(): number { const envLimit = process.env.MCP_TOKEN_LIMIT; if (envLimit) { const parsed = parseInt(envLimit, 10); if (!isNaN(parsed) && parsed > 0) { return parsed; } } return 10000; // Default 10K tokens } /** * Apply token limit to an array of objects * Returns as many objects as possible within the token limit */ export function applyTokenLimit<T>( data: T[], config?: Partial<TokenLimitConfig> ): TokenLimitResult<T> { const maxTokens = config?.maxTokens ?? getMcpTokenLimit(); const includeMetadata = config?.includeMetadata ?? true; const result: TokenLimitResult<T> = { data: [], truncated: false, originalCount: data.length, returnedCount: 0, estimatedTokens: 0 }; // Reserve tokens for metadata if needed const metadataTokenReserve = includeMetadata ? 100 : 0; const availableTokens = maxTokens - metadataTokenReserve; let currentTokens = 0; let index = 0; // Add items until we hit the token limit while (index < data.length) { const itemTokens = estimateTokens(data[index]); if (currentTokens + itemTokens > availableTokens) { result.truncated = true; break; } result.data.push(data[index]); currentTokens += itemTokens; index++; } result.returnedCount = result.data.length; result.estimatedTokens = currentTokens; // Add helpful metadata if truncated if (result.truncated && includeMetadata) { const remaining = result.originalCount - result.returnedCount; result.metadata = { message: `Results truncated: showing ${result.returnedCount} of ${result.originalCount} items (${remaining} more available)`, suggestedActions: [ "Use pagination with offset/limit parameters", "Apply more specific filters to reduce result set", "Use compact field selection to reduce token usage", `Increase MCP_TOKEN_LIMIT (currently ${maxTokens}) in environment` ] }; } return result; } /** * Create a paginated response with token limiting */ export function createPaginatedResponse<T>( data: T[], offset: number = 0, limit?: number, tokenLimit?: number ): TokenLimitResult<T> & { hasMore: boolean; nextOffset?: number } { // Apply basic pagination first if limit is specified let paginatedData = data; if (limit !== undefined) { paginatedData = data.slice(offset, offset + limit); } else { paginatedData = data.slice(offset); } // Apply token limiting const result = applyTokenLimit(paginatedData, { maxTokens: tokenLimit, includeMetadata: true }); // Calculate if there are more results const totalProcessed = offset + result.returnedCount; const hasMore = totalProcessed < data.length; const nextOffset = hasMore ? totalProcessed : undefined; return { ...result, hasMore, nextOffset, originalCount: data.length // Override to show total count, not just page count }; }

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/JonnoC/CodeRAG'

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