@cortexguardai/mcp
Version:
A Node.js-based MCP adapter for seamless integration with AI development environments.
213 lines • 6.63 kB
JavaScript
/**
* Logging utilities with configurable verbosity
*/
export class Logger {
verbose;
constructor(verbose = false) {
this.verbose = verbose;
}
info(message, ...args) {
console.error(`[INFO] ${message}`, ...args);
}
warn(message, ...args) {
console.error(`[WARN] ${message}`, ...args);
}
error(message, ...args) {
console.error(`[ERROR] ${message}`, ...args);
}
debug(message, ...args) {
if (this.verbose) {
console.error(`[DEBUG] ${message}`, ...args);
}
}
setVerbose(verbose) {
this.verbose = verbose;
}
}
/**
* Validation utilities
*/
export class Validator {
static UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
static URL_REGEX = /^https?:\/\/.+/;
static isValidUUID(uuid) {
return typeof uuid === 'string' && this.UUID_REGEX.test(uuid);
}
static isValidURL(url) {
if (typeof url !== 'string')
return false;
try {
const parsed = new URL(url);
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
}
catch {
return false;
}
}
static isValidTimeout(timeout) {
return typeof timeout === 'number' && timeout > 0 && timeout <= 300000; // Max 5 minutes
}
static isValidToken(token) {
return typeof token === 'string' && token.length > 0 && token.length <= 1000;
}
static validateConfig(config) {
const errors = [];
if (!this.isValidURL(config.serverUrl)) {
errors.push('Invalid server URL format');
}
if (!this.isValidToken(config.authToken)) {
errors.push('Invalid auth token');
}
if (!this.isValidTimeout(config.timeout)) {
errors.push('Invalid timeout value (must be 1-300000ms)');
}
return errors;
}
}
/**
* Content-Length framing utilities
*/
export class FramingUtils {
static HEADER_SEPARATOR = '\r\n\r\n';
static LINE_SEPARATOR = '\r\n';
static frameMessage(content) {
const contentBytes = Buffer.byteLength(content, 'utf8');
return `Content-Length: ${contentBytes}${this.HEADER_SEPARATOR}${content}`;
}
static parseFramedMessage(buffer) {
const bufferStr = buffer.toString('utf8');
const headerEndIndex = bufferStr.indexOf(this.HEADER_SEPARATOR);
if (headerEndIndex === -1) {
// No complete header yet
return null;
}
const headerSection = bufferStr.substring(0, headerEndIndex);
const contentLengthMatch = headerSection.match(/^Content-Length: (\d+)$/m);
if (!contentLengthMatch) {
throw new Error('Invalid Content-Length header');
}
const contentLength = parseInt(contentLengthMatch[1], 10);
const messageStart = headerEndIndex + this.HEADER_SEPARATOR.length;
const messageEnd = messageStart + contentLength;
if (buffer.length < messageEnd) {
// Incomplete message
return null;
}
const messageBytes = buffer.subarray(messageStart, messageEnd);
const message = messageBytes.toString('utf8');
const remaining = buffer.subarray(messageEnd);
return { message, remaining };
}
}
/**
* JSON utilities with error handling
*/
export class JsonUtils {
static safeStringify(obj) {
try {
return JSON.stringify(obj);
}
catch (error) {
throw new Error(`JSON stringify error: ${error}`);
}
}
static safeParse(json) {
try {
return JSON.parse(json);
}
catch (error) {
throw new Error(`JSON parse error: ${error}`);
}
}
}
/**
* Error handling utilities
*/
export class ErrorUtils {
static isNetworkError(error) {
return (error &&
(error.code === 'ECONNREFUSED' ||
error.code === 'ENOTFOUND' ||
error.code === 'ETIMEDOUT' ||
error.code === 'ECONNRESET'));
}
static isTimeoutError(error) {
return (error &&
(error.code === 'ETIMEDOUT' ||
error.message?.includes('timeout')));
}
static getErrorMessage(error) {
if (typeof error === 'string') {
return error;
}
if (error && error.message) {
return error.message;
}
return 'Unknown error';
}
static sanitizeError(error) {
// Remove sensitive information from errors
const sanitized = { ...error };
// Remove auth tokens from error messages
if (sanitized.message) {
sanitized.message = sanitized.message.replace(/Bearer [A-Za-z0-9._-]+/g, 'Bearer [REDACTED]');
}
if (sanitized.config?.headers?.Authorization) {
sanitized.config.headers.Authorization = '[REDACTED]';
}
return sanitized;
}
}
/**
* Performance monitoring utilities
*/
export class PerfUtils {
static timers = new Map();
static startTimer(name) {
this.timers.set(name, Date.now());
}
static endTimer(name) {
const start = this.timers.get(name);
if (!start) {
throw new Error(`Timer '${name}' not found`);
}
const duration = Date.now() - start;
this.timers.delete(name);
return duration;
}
static measureAsync(name, fn) {
this.startTimer(name);
return fn().finally(() => {
const duration = this.endTimer(name);
console.error(`[PERF] ${name}: ${duration}ms`);
});
}
}
/**
* Retry utilities for network operations
*/
export class RetryUtils {
static async withRetry(operation, maxRetries = 3, baseDelay = 1000) {
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation();
}
catch (error) {
lastError = error;
if (attempt === maxRetries) {
break;
}
// Only retry on network errors
if (!ErrorUtils.isNetworkError(error)) {
throw error;
}
// Exponential backoff with jitter
const delay = baseDelay * Math.pow(2, attempt) + Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
}
//# sourceMappingURL=utils.js.map