UNPKG

@anyshift/mcp-tools-common

Version:

Reusable JQ tool and file writing utilities for MCP servers

276 lines (263 loc) 8.97 kB
import { z } from 'zod'; /** * Configuration for the file writer module */ interface FileWriterConfig { /** Whether file writing is enabled */ enabled: boolean; /** Directory where files should be written */ outputPath: string; /** Minimum character count to trigger file writing (default: 1000) */ minCharsForWrite?: number; /** Custom abbreviations for tool names in filenames */ toolAbbreviations?: Record<string, string>; } /** * Configuration for the JQ tool */ interface JqConfig { /** Paths where JQ is allowed to read files */ allowedPaths: string[]; /** Timeout for JQ query execution in milliseconds (default: 30000) */ timeoutMs?: number; } /** * Result from file writer operations */ interface FileWriterResult { content: Array<{ type: string; text: string; }>; } /** * Schema analysis result for a JSON structure */ interface JsonSchema { type: string; properties?: Record<string, unknown>; items?: unknown; length?: number; _hasNulls?: boolean; _keysAreNumeric?: boolean; _accessPattern?: string; } /** * Nullable fields extracted from schema */ interface NullableFields { /** Fields that are always null */ alwaysNull: string[]; /** Fields that can be null (mixed types) */ nullable: string[]; } /** * Analyze JSON structure and generate enhanced schema * @param obj - The object to analyze * @param path - Current path in the object (for debugging) * @returns Schema representation of the object */ declare function analyzeJsonSchema(obj: unknown, path?: string): JsonSchema; /** * Extract nullable and always-null fields from schema * @param schema - The schema to analyze * @param basePath - Base path for field names * @returns Object containing arrays of always-null and nullable field paths */ declare function extractNullableFields(schema: unknown, basePath?: string): NullableFields; /** * Create a file writer instance with the given configuration * @param config - File writer configuration * @returns Object with handleResponse method */ declare function createFileWriter(config: FileWriterConfig): { /** * Handle tool response - writes to file if conditions are met * @param toolName - Name of the tool that generated the response * @param args - Arguments passed to the tool * @param responseData - The response data to potentially write to file * @returns Either the original response or a file reference response */ handleResponse: (toolName: string, args: Record<string, unknown>, responseData: unknown) => Promise<FileWriterResult | unknown>; }; /** * Centralized response handler with file writing capability * @param config - File writer configuration * @param toolName - Name of the tool that generated the response * @param args - Arguments passed to the tool * @param responseData - The response data to potentially write to file * @returns Either the original response or a file reference response */ declare function handleToolResponse(config: FileWriterConfig, toolName: string, args: Record<string, unknown>, responseData: unknown): Promise<FileWriterResult | unknown>; /** * Zod schema for JQ query execution */ declare const ExecuteJqQuerySchema: z.ZodObject<{ jq_query: z.ZodString; file_path: z.ZodString; description: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { jq_query: string; file_path: string; description?: string | undefined; }, { jq_query: string; file_path: string; description?: string | undefined; }>; /** * Tool definition for JQ query execution with enhanced prompts * This includes schema-first development hints for better LLM usage */ declare const JQ_TOOL_DEFINITION: { name: string; description: string; inputSchema: { type: string; properties: { jq_query: { type: string; description: string; }; file_path: { type: string; description: string; }; description: { type: string; description: string; }; }; required: string[]; }; }; /** * Execute a JQ query on a JSON file * @param config - JQ configuration * @param jqQuery - The JQ query to execute * @param filePath - Absolute path to the JSON file * @returns Promise with the query result */ declare function executeJqQuery(config: JqConfig, jqQuery: string, filePath: string): Promise<{ content: Array<{ type: 'text'; text: string; }>; }>; /** * Create a JQ tool instance with the given configuration * @param config - JQ configuration * @returns Object with handler and toolDefinition */ declare function createJqTool(config: JqConfig): { /** * Tool definition for MCP server registration */ toolDefinition: { name: string; description: string; inputSchema: { type: string; properties: { jq_query: { type: string; description: string; }; file_path: { type: string; description: string; }; description: { type: string; description: string; }; }; required: string[]; }; }; /** * Handler for JQ query execution requests * @param request - MCP request containing jq_query and file_path * @returns Promise with the query result */ handler: (request: { params: { arguments: Record<string, unknown>; }; }) => Promise<{ content: Array<{ type: "text"; text: string; }>; }>; }; /** * Generate LLM-friendly compact filename * @param toolName - Name of the tool that generated the data * @param args - Arguments passed to the tool * @param toolAbbreviations - Optional custom abbreviations for tool names * @returns Compact filename like "1697834567123_met_qry_a3b4c5.json" */ declare const generateCompactFilename: (toolName: string, args: Record<string, unknown>, toolAbbreviations?: Record<string, string>) => string; /** * Validate that a file path is within allowed directories * @param filePath - The file path to validate * @param allowedPaths - Array of allowed directory paths * @returns The validated real path (with symlinks resolved) * @throws Error if path is invalid, doesn't exist, or is outside allowed directories */ declare const validatePathWithinAllowedDirs: (filePath: string, allowedPaths: string[]) => string; /** * Configuration for response truncation */ interface TruncationConfig { /** * Maximum number of tokens allowed in response * Common values: 10000 (Datadog), 15000 (Anyshift) */ maxTokens: number; /** * Enable detailed JSON logging to stderr * Useful for debugging and monitoring truncation behavior * Default: false */ enableLogging?: boolean; /** * Custom prefix for truncation notice message * Default: "RESPONSE TRUNCATED" */ messagePrefix?: string; /** * Characters per token ratio for estimation * Default: 4 (standard approximation) */ charsPerToken?: number; } /** * Estimate token count using chars/token ratio * Uses a simple approximation where 1 token ≈ 4 characters * * @param text - The text to estimate tokens for * @param charsPerToken - Characters per token ratio (default: 4) * @returns Estimated token count */ declare function estimateTokens(text: string, charsPerToken?: number): number; /** * Check if content would be truncated without actually truncating * * @param content - The content to check * @param maxTokens - Maximum token limit * @param charsPerToken - Characters per token ratio (default: 4) * @returns True if content exceeds token limit */ declare function wouldBeTruncated(content: string, maxTokens: number, charsPerToken?: number): boolean; /** * Truncate response content if it exceeds token limit * Optionally logs detailed metrics to stderr for monitoring * * @param config - Truncation configuration * @param content - The content to potentially truncate * @returns Original content if under limit, or truncated content with notice */ declare function truncateResponseIfNeeded(config: TruncationConfig, content: string): string; export { ExecuteJqQuerySchema, type FileWriterConfig, type FileWriterResult, JQ_TOOL_DEFINITION, type JqConfig, type JsonSchema, type NullableFields, type TruncationConfig, analyzeJsonSchema, createFileWriter, createJqTool, estimateTokens, executeJqQuery, extractNullableFields, generateCompactFilename, handleToolResponse, truncateResponseIfNeeded, validatePathWithinAllowedDirs, wouldBeTruncated };