Skip to main content
Glama

fast-filesystem-mcp

content-minimizer.ts8.49 kB
// 응답 크기 최소화 유틸리티 import { gzip, gunzip } from 'zlib'; import { promisify } from 'util'; const gzipAsync = promisify(gzip); const gunzipAsync = promisify(gunzip); export interface CompressionOptions { enable_compression?: boolean; // gzip 압축 사용 summary_mode?: boolean; // 요약 모드 (큰 내용은 요약만) reference_mode?: boolean; // 참조 모드 (content_id만 반환) minimize_paths?: boolean; // 경로 최소화 minimal_metadata?: boolean; // 최소 메타데이터만 max_content_preview?: number; // 내용 미리보기 최대 크기 } export interface ContentReference { content_id: string; content_type: 'text' | 'binary' | 'directory' | 'search_results'; size: number; preview?: string; fetch_url?: string; } export class ContentMinimizer { private contentStore = new Map<string, any>(); private readonly PREVIEW_SIZE = 200; // 기본 미리보기 크기 // 텍스트 압축 async compressText(text: string): Promise<{ compressed: string; original_size: number; compressed_size: number }> { const buffer = Buffer.from(text, 'utf8'); const compressed = await gzipAsync(buffer); const compressedBase64 = compressed.toString('base64'); return { compressed: compressedBase64, original_size: buffer.length, compressed_size: compressed.length }; } // 텍스트 압축 해제 async decompressText(compressedBase64: string): Promise<string> { const compressed = Buffer.from(compressedBase64, 'base64'); const decompressed = await gunzipAsync(compressed); return decompressed.toString('utf8'); } // 텍스트 요약 생성 summarizeText(text: string, maxLength: number = 500): { summary: string; is_truncated: boolean; original_length: number } { const lines = text.split('\n'); const totalLength = text.length; if (totalLength <= maxLength) { return { summary: text, is_truncated: false, original_length: totalLength }; } // 첫 부분 + 중간 부분 + 끝 부분으로 요약 const partSize = Math.floor(maxLength / 3); const firstPart = text.substring(0, partSize); const lastPart = text.substring(text.length - partSize); // 중간 부분에서 대표적인 라인들 선택 const middleStart = Math.floor(lines.length * 0.4); const middleEnd = Math.floor(lines.length * 0.6); const middleLines = lines.slice(middleStart, middleEnd); const middlePart = middleLines.slice(0, 3).join('\n'); // 최대 3라인 const summary = `${firstPart}\n\n... [${lines.length - 6} more lines] ...\n\n${middlePart}\n\n... [more content] ...\n\n${lastPart}`; return { summary: summary.length > maxLength ? summary.substring(0, maxLength) + '...' : summary, is_truncated: true, original_length: totalLength }; } // 경로 최소화 (공통 prefix 제거) minimizePaths(paths: string[], basePath?: string): { minimized_paths: string[]; common_prefix: string } { if (paths.length === 0) { return { minimized_paths: [], common_prefix: '' }; } if (paths.length === 1) { const path = paths[0]; const commonPrefix = basePath || path.substring(0, path.lastIndexOf('/') + 1); return { minimized_paths: [path.replace(commonPrefix, '')], common_prefix: commonPrefix }; } // 공통 prefix 찾기 let commonPrefix = paths[0]; for (let i = 1; i < paths.length; i++) { while (commonPrefix && !paths[i].startsWith(commonPrefix)) { commonPrefix = commonPrefix.substring(0, commonPrefix.lastIndexOf('/')); } } if (commonPrefix && !commonPrefix.endsWith('/')) { commonPrefix += '/'; } return { minimized_paths: paths.map(path => path.replace(commonPrefix, '')), common_prefix: commonPrefix }; } // 메타데이터 최소화 minimizeMetadata(item: any): any { return { n: item.name, t: item.type === 'directory' ? 'd' : 'f', s: item.size, m: item.modified ? new Date(item.modified).getTime() : undefined }; } // Content 참조 생성 createContentReference(content: any, type: ContentReference['content_type'], options: CompressionOptions = {}): ContentReference { const contentId = `ref_${Date.now()}_${Math.random().toString(36).substring(2)}`; // 내용을 저장소에 보관 this.contentStore.set(contentId, content); // 미리보기 생성 let preview = ''; const previewSize = options.max_content_preview || this.PREVIEW_SIZE; if (type === 'text' && typeof content === 'string') { preview = content.length > previewSize ? content.substring(0, previewSize) + '...' : content; } else if (type === 'directory' && Array.isArray(content)) { preview = `${content.length} items`; } else if (type === 'search_results' && Array.isArray(content)) { preview = `${content.length} results found`; } return { content_id: contentId, content_type: type, size: JSON.stringify(content).length, preview, fetch_url: `fetch_content/${contentId}` }; } // 저장된 content 가져오기 getStoredContent(contentId: string): any | null { return this.contentStore.get(contentId); } // 저장소 정리 cleanup(): void { this.contentStore.clear(); } // 통합 최소화 함수 async minimizeResponse(data: any, options: CompressionOptions = {}): Promise<any> { const result = { ...data }; // 1. 압축 처리 if (options.enable_compression && data.content && typeof data.content === 'string') { const compressed = await this.compressText(data.content); result.content = { type: 'compressed', data: compressed.compressed, original_size: compressed.original_size, compressed_size: compressed.compressed_size, compression_ratio: compressed.original_size / compressed.compressed_size }; } // 2. 요약 모드 else if (options.summary_mode && data.content && typeof data.content === 'string') { const summary = this.summarizeText(data.content, options.max_content_preview || 1000); result.content = { type: 'summary', data: summary.summary, is_truncated: summary.is_truncated, original_length: summary.original_length }; } // 3. 참조 모드 else if (options.reference_mode && data.content) { const contentType = typeof data.content === 'string' ? 'text' : Array.isArray(data.content) ? 'search_results' : 'binary'; result.content = this.createContentReference(data.content, contentType, options); } // 4. 경로 최소화 (디렉토리 리스팅) if (options.minimize_paths && data.items && Array.isArray(data.items)) { const paths = data.items.map((item: any) => item.path).filter(Boolean); if (paths.length > 0) { const minimized = this.minimizePaths(paths, data.path); result.items = data.items.map((item: any, index: number) => ({ ...item, path: minimized.minimized_paths[index] || item.path })); result.path_info = { common_prefix: minimized.common_prefix, paths_minimized: true }; } } // 5. 메타데이터 최소화 if (options.minimal_metadata && data.items && Array.isArray(data.items)) { result.items = data.items.map((item: any) => this.minimizeMetadata(item)); result.metadata_format = 'minimized'; // n=name, t=type, s=size, m=modified_timestamp } // 크기 정보 추가 const originalSize = JSON.stringify(data).length; const minimizedSize = JSON.stringify(result).length; result.size_optimization = { original_size: originalSize, minimized_size: minimizedSize, reduction_percentage: ((originalSize - minimizedSize) / originalSize * 100).toFixed(1), techniques_used: Object.keys(options).filter(key => options[key as keyof CompressionOptions]) }; return result; } } // 전역 인스턴스 export const globalContentMinimizer = new ContentMinimizer(); // 압축 해제를 위한 헬퍼 함수 export async function fetchContent(contentId: string): Promise<any> { return globalContentMinimizer.getStoredContent(contentId); }

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/efforthye/fast-filesystem-mcp'

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