Skip to main content
Glama
errors.ts4.82 kB
/** * Custom error class for Liara MCP operations */ export class LiaraMcpError extends Error { constructor( message: string, public code?: string, public details?: any, public suggestions?: string[] ) { super(message); this.name = 'LiaraMcpError'; } /** * Format error message with suggestions */ formatMessage(): string { let msg = this.message; if (this.suggestions && this.suggestions.length > 0) { msg += '\n\nSuggestions:'; this.suggestions.forEach((suggestion, index) => { msg += `\n${index + 1}. ${suggestion}`; }); } return msg; } } /** * Format error for MCP response * Returns just the base message without suggestions (for structured responses) */ export function formatErrorForMcp(error: unknown): string { if (error instanceof Error) { return error.message; } return String(error); } /** * Format error message with suggestions (for plain text responses) */ export function formatErrorWithSuggestions(error: unknown): string { if (error instanceof LiaraMcpError) { return error.formatMessage(); } return formatErrorForMcp(error); } /** * Validate that a value is not empty */ export function validateRequired(value: any, fieldName: string): void { if (value === undefined || value === null || value === '') { throw new LiaraMcpError(`${fieldName} is required`); } } /** * Validate app name format * Must be lowercase alphanumeric with hyphens, 3-32 characters */ export function validateAppName(name: string): void { validateRequired(name, 'App name'); if (name.length < 3) { throw new LiaraMcpError( `App name "${name}" is too short (minimum 3 characters, got ${name.length})`, 'INVALID_APP_NAME', { name, length: name.length }, ['Use a name like "my-app" or "api-service"'] ); } if (name.length > 32) { throw new LiaraMcpError( `App name "${name}" is too long (maximum 32 characters, got ${name.length})`, 'INVALID_APP_NAME', { name, length: name.length }, ['Shorten the name to 32 characters or less'] ); } if (!/^[a-z0-9-]+$/.test(name)) { const invalidChars = name.match(/[^a-z0-9-]/g); throw new LiaraMcpError( `App name contains invalid characters: ${invalidChars?.join(', ') || 'unknown'}`, 'INVALID_APP_NAME', { name, invalidChars }, ['Use only lowercase letters, numbers, and hyphens', 'Example: "my-app" or "api-service"'] ); } if (name.startsWith('-') || name.endsWith('-')) { throw new LiaraMcpError( `App name cannot start or end with a hyphen: "${name}"`, 'INVALID_APP_NAME', { name }, ['Remove leading/trailing hyphens', 'Example: "my-app" instead of "-my-app"'] ); } } /** * Validate domain name format */ export function validateDomainName(domain: string): void { validateRequired(domain, 'Domain name'); const domainRegex = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i; if (!domainRegex.test(domain)) { throw new LiaraMcpError('Invalid domain name format'); } } /** * Validate environment variable key */ export function validateEnvKey(key: string): void { validateRequired(key, 'Environment variable key'); if (!/^[A-Z_][A-Z0-9_]*$/.test(key)) { throw new LiaraMcpError( 'Environment variable key must start with a letter or underscore and contain only uppercase letters, numbers, and underscores' ); } } /** * Unwrap API response data * Handles various response formats (direct array, wrapped in data/items/etc.) */ export function unwrapApiResponse<T>(response: any, expectedArrayKeys?: string[]): T { if (!response) return response; // If it's already the expected type (array or primitive), return as-is if (Array.isArray(response)) { return response as T; } // Common wrapper keys that APIs use const arrayKeys = expectedArrayKeys || ['data', 'items', 'results', 'projects', 'databases', 'buckets', 'zones', 'records', 'backups', 'releases', 'domains', 'vms', 'plans']; // Try to unwrap from common wrapper keys for (const key of arrayKeys) { if (response[key] !== undefined) { return response[key] as T; } } // Return as-is if no wrapper found return response as T; } /** * Safe JSON parse with fallback */ export function safeJsonParse<T>(str: string, fallback: T): T { try { return JSON.parse(str); } catch { return fallback; } }

Implementation Reference

Latest Blog Posts

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/razavioo/liara-mcp'

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