diff --git a/src/index.ts b/src/index.ts index 6a03dc2..81c80bc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import { execSync } from "child_process"; import { compressRead } from "./compressors/read.js"; import { compressGrep } from "./compressors/grep.js"; import { compressGlob } from "./compressors/glob.js"; +import { logTelemetry, calculateCompressionRatio } from "./telemetry.js"; // Configuration from environment const COMPRESSION_LEVEL = process.env.COMPRESSION_LEVEL || "medium"; @@ -177,6 +178,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { const result = compressRead(content, path, options); + // Log telemetry + logTelemetry({ + tool: "compressed_read", + inputSize: result.originalLines, + outputSize: result.compressedLines, + compressionRatio: calculateCompressionRatio(result.originalLines, result.compressedLines), + path, + success: true, + }); + return { content: [ { @@ -219,6 +230,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { const result = compressGrep(output, options); + // Log telemetry + logTelemetry({ + tool: "compressed_grep", + inputSize: result.originalMatches, + outputSize: result.compressedMatches, + compressionRatio: calculateCompressionRatio(result.originalMatches, result.compressedMatches), + path: searchPath, + pattern, + success: true, + }); + return { content: [ { @@ -266,6 +288,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { const result = compressGlob(paths, options); + // Log telemetry + logTelemetry({ + tool: "compressed_glob", + inputSize: paths.length, + outputSize: result.compressedCount, + compressionRatio: calculateCompressionRatio(paths.length, result.compressedCount), + path: basePath, + pattern, + success: true, + }); + return { content: [ { diff --git a/src/telemetry.ts b/src/telemetry.ts new file mode 100644 index 0000000..364d2ca --- /dev/null +++ b/src/telemetry.ts @@ -0,0 +1,46 @@ +/** + * Telemetry for compressed tools usage tracking + * Logs to ~/.local/share/mcp/compressed-tools.jsonl + */ + +import { appendFileSync, mkdirSync, existsSync } from "fs"; +import { homedir } from "os"; +import { join } from "path"; + +const LOG_DIR = join(homedir(), ".local", "share", "mcp"); +const LOG_FILE = join(LOG_DIR, "compressed-tools.jsonl"); + +// Ensure log directory exists +if (!existsSync(LOG_DIR)) { + mkdirSync(LOG_DIR, { recursive: true }); +} + +export interface TelemetryEvent { + timestamp: string; + tool: "compressed_read" | "compressed_grep" | "compressed_glob"; + inputSize: number; + outputSize: number; + compressionRatio: number; + path?: string; + pattern?: string; + success: boolean; + error?: string; +} + +export function logTelemetry(event: Omit): void { + const entry: TelemetryEvent = { + timestamp: new Date().toISOString(), + ...event, + }; + + try { + appendFileSync(LOG_FILE, JSON.stringify(entry) + "\n"); + } catch { + // Silently fail - telemetry should never break the tool + } +} + +export function calculateCompressionRatio(original: number, compressed: number): number { + if (original === 0) return 0; + return Math.round((1 - compressed / original) * 100 * 10) / 10; +}