UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and

162 lines (161 loc) • 6.7 kB
/** * FlexibleToolValidator - Universal Safety Checks Only * * Following Anthropic's MCP specification which intentionally leaves tool naming flexible, * this validator only blocks truly dangerous cases to support maximum MCP tool compatibility. * * Phase 1 Implementation: * - Universal safety checks only (empty names, control characters, excessive length) * - No context-specific validation or arbitrary pattern restrictions * - Designed to support ALL legitimate MCP tools (github.create_repo, filesystem.read_file, etc.) */ import { registryLogger } from "../utils/logger.js"; export class FlexibleToolValidator { // Universal safety limits (generous to support all legitimate tools) static MAX_TOOL_NAME_LENGTH = 1000; // Much more generous than npm's 214 static MIN_TOOL_NAME_LENGTH = 1; /** * Validate tool name with universal safety checks only * * This method only blocks truly dangerous cases: * 1. Empty or whitespace-only names * 2. Control characters that could break systems * 3. Excessively long names that could cause memory issues * * Everything else is allowed to support maximum MCP tool compatibility. */ static validateToolName(toolId) { const warnings = []; // Safety Check 1: Empty or whitespace-only names if (!toolId || typeof toolId !== "string") { return { isValid: false, error: "Tool name is required and must be a string", }; } // Safety Check 2: Control characters that could break systems (check BEFORE trimming!) // Only block truly dangerous control characters, not printable characters // // This regex blocks dangerous C0 control characters and DEL: // - \x00-\x08: NULL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS // - \x0B: Vertical Tab (VT) // - \x0C: Form Feed (FF) // - \x0E-\x1F: SO, SI, DLE, DC1-4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FS-US // - \x7F: DEL // // Explicitly ALLOWS these printable control characters: // - \x09: TAB (horizontal tab) - commonly used in text // - \x0A: LF (line feed) - commonly used in text // - \x0D: CR (carriage return) - commonly used in text // eslint-disable-next-line no-control-regex const hasControlCharacters = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/.test(toolId); if (hasControlCharacters) { return { isValid: false, error: "Tool name contains control characters that could break systems", }; } const trimmedName = toolId.trim(); if (trimmedName.length === 0) { return { isValid: false, error: "Tool name cannot be empty or whitespace-only", }; } // Safety Check 3: Length limits (very generous) if (trimmedName.length < this.MIN_TOOL_NAME_LENGTH) { return { isValid: false, error: `Tool name must be at least ${this.MIN_TOOL_NAME_LENGTH} character long`, }; } if (trimmedName.length > this.MAX_TOOL_NAME_LENGTH) { return { isValid: false, error: `Tool name exceeds maximum length of ${this.MAX_TOOL_NAME_LENGTH} characters`, }; } // Optional warnings for unusual but not dangerous patterns if (trimmedName !== toolId) { warnings.push("Tool name has leading/trailing whitespace (will be trimmed)"); } if (trimmedName.length > 200) { warnings.push("Tool name is unusually long but allowed"); } registryLogger.debug(`✅ FlexibleToolValidator: Tool '${toolId}' passed universal safety checks`); return { isValid: true, warnings: warnings.length > 0 ? warnings : undefined, }; } /** * Validate tool information with minimal safety checks */ static validateToolInfo(toolId, toolInfo) { // First validate the tool name const nameValidation = this.validateToolName(toolId); if (!nameValidation.isValid) { return nameValidation; } const warnings = [...(nameValidation.warnings || [])]; // Minimal safety checks for tool info if (toolInfo.description && typeof toolInfo.description !== "string") { return { isValid: false, error: "Tool description must be a string if provided", }; } if (toolInfo.serverId && typeof toolInfo.serverId !== "string") { return { isValid: false, error: "Tool serverId must be a string if provided", }; } registryLogger.debug(`✅ FlexibleToolValidator: Tool info for '${toolId}' passed validation`); return { isValid: true, warnings: warnings.length > 0 ? warnings : undefined, }; } /** * Get information about what this validator checks */ static getValidationInfo() { return { philosophy: "Maximum flexibility with universal safety only - following Anthropic's MCP specification", checks: [ "Empty or whitespace-only names", "Excessive length (over 1000 characters)", "Control characters that could break systems", ], whatIsAllowed: [ "Dots (github.create_repo, filesystem.read_file)", "Hyphens and underscores (my-tool, user_helper)", "Numbers (tool1, my_tool_v2)", "Unicode characters (🚀_tool, café_manager)", "Mixed case (createRepo, ReadFile)", "Long descriptive names (enterprise_database_connection_manager)", "Any legitimate MCP tool naming pattern", ], examples: { valid: [ "github.create_repo", "filesystem.read_file", "my-custom-tool", "user_helper", "tool1", "🚀_rocket_tool", "enterprise.database.connection.manager", "UPPERCASE_TOOL", "mixed_Case.Tool-Name_123", ], invalid: [ "", // Empty " ", // Whitespace only "tool\x00", // Control character "a".repeat(1001), // Too long ], }, }; } }