UNPKG

@aashari/mcp-server-aws-sso

Version:

Node.js/TypeScript MCP server for AWS Single Sign-On (SSO). Enables AI systems (LLMs) with tools to initiate SSO login (device auth flow), list accounts/roles, and securely execute AWS CLI commands using temporary credentials. Streamlines AI interaction w

248 lines (247 loc) 9.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.McpError = exports.ErrorType = void 0; exports.createMcpError = createMcpError; exports.createAuthMissingError = createAuthMissingError; exports.createAuthTimeoutError = createAuthTimeoutError; exports.createApiError = createApiError; exports.createUnexpectedError = createUnexpectedError; exports.ensureMcpError = ensureMcpError; exports.getDeepOriginalError = getDeepOriginalError; exports.formatErrorForMcpTool = formatErrorForMcpTool; exports.handleCliError = handleCliError; const logger_util_js_1 = require("./logger.util.js"); /** * Error types for classification */ var ErrorType; (function (ErrorType) { ErrorType["AUTH_MISSING"] = "AUTH_MISSING"; ErrorType["AUTH_INVALID"] = "AUTH_INVALID"; ErrorType["API_ERROR"] = "API_ERROR"; ErrorType["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR"; })(ErrorType || (exports.ErrorType = ErrorType = {})); /** * Custom error class with type classification */ class McpError extends Error { constructor(message, typeOrOptions, statusCode, originalError) { if (typeof typeOrOptions === 'object') { // New constructor style with options super(message); this.name = 'McpError'; this.type = ErrorType.UNEXPECTED_ERROR; // Default type this.originalError = typeOrOptions.cause; } else { // Original constructor style super(message); this.name = 'McpError'; this.type = typeOrOptions; this.statusCode = statusCode; this.originalError = originalError; } // Ensure prototype chain is properly maintained Object.setPrototypeOf(this, McpError.prototype); } } exports.McpError = McpError; /** * Create a standardized McpError with additional properties * @param message Error message * @param options Additional error options including cause and error type * @returns McpError instance */ function createMcpError(message, options) { const error = new McpError(message, { cause: options?.cause }); if (options?.errorType) { error.errorType = options.errorType; } if (options?.metadata) { error.$metadata = options.metadata; } return error; } /** * Create an authentication missing error * @param message Error message * @param cause Optional cause of the error * @returns McpError with authentication missing details */ function createAuthMissingError(message, cause) { const error = new McpError(message, { cause }); error.errorType = 'AUTHENTICATION_MISSING'; return error; } /** * Create an authentication timeout error * @param message Error message * @param cause Optional cause of the error * @returns McpError with authentication timeout details */ function createAuthTimeoutError(message, cause) { const error = new McpError(message, { cause }); error.errorType = 'AUTHENTICATION_TIMEOUT'; return error; } /** * Create an API error * @param message Error message * @param statusCode Optional HTTP status code * @param cause Optional cause of the error * @returns McpError with API error details */ function createApiError(message, statusCode, cause) { const error = new McpError(message, { cause }); error.errorType = 'API_ERROR'; if (statusCode) { error.$metadata = { httpStatusCode: statusCode, }; } return error; } /** * Create an unexpected error * @param message Error message * @param cause Optional cause of the error * @returns McpError with unexpected error details */ function createUnexpectedError(message, cause) { const error = new McpError(message, { cause }); error.errorType = 'UNEXPECTED_ERROR'; return error; } /** * Ensure an error is an McpError * @param error The error to convert to an McpError * @returns An McpError instance */ function ensureMcpError(error) { if (error instanceof McpError) { return error; } if (error instanceof Error) { return createMcpError(error.message, { cause: error, errorType: error.errorType || 'UNEXPECTED_ERROR', }); } return createMcpError(String(error), { errorType: 'UNEXPECTED_ERROR' }); } /** * Get the deepest original error from an error chain * @param error The error to extract the original cause from * @returns The deepest original error or the error itself */ function getDeepOriginalError(error) { if (!error) { return error; } let current = error; let depth = 0; const maxDepth = 10; // Prevent infinite recursion while (depth < maxDepth && current instanceof Error && 'originalError' in current && current.originalError) { current = current.originalError; depth++; } return current; } /** * Format error for MCP tool response */ function formatErrorForMcpTool(error) { const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'formatErrorForMcpTool'); const mcpError = ensureMcpError(error); methodLogger.error(`${mcpError.type} error`, mcpError); // Get the deep original error for additional context const originalError = getDeepOriginalError(mcpError.originalError); // Safely extract details from the original error const errorDetails = originalError instanceof Error ? { message: originalError.message } : originalError; // Generate user-friendly error message based on error type let errorMessage = mcpError.message; // Check for specific error types to provide more helpful messages if (mcpError.errorType === 'AUTHENTICATION_MISSING') { errorMessage = `# AWS SSO: Authentication Required\n\nYou need to authenticate with AWS SSO before using this command.\n\nUse the \`aws_sso_login\` tool to authenticate with AWS SSO.`; } else if (mcpError.errorType === 'AUTHENTICATION_TIMEOUT') { errorMessage = `# AWS SSO: Authentication Timeout\n\nYour authentication attempt timed out. Please try again.\n\nUse the \`aws_sso_login\` tool to attempt authentication again.`; } else if (originalError && typeof originalError === 'object' && 'error' in originalError) { // Handle specific OAuth errors if (originalError.error === 'authorization_pending') { errorMessage = `# AWS SSO: Authentication Pending\n\nYour authentication is still pending. Complete the authentication in your browser using the verification code.`; } else if (originalError.error === 'access_denied') { errorMessage = `# AWS SSO: Authentication Denied\n\nYour authentication request was denied. Please try again.`; } else if (originalError.error === 'expired_token') { errorMessage = `# AWS SSO: Token Expired\n\nYour AWS SSO token has expired. Please authenticate again using the \`aws_sso_login\` tool.`; } } return { content: [ { type: 'text', text: errorMessage, }, ], metadata: { errorType: mcpError.type, statusCode: mcpError.statusCode, errorDetails, }, }; } /** * Handle error in CLI context with improved user feedback */ function handleCliError(error) { const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'handleCliError'); const mcpError = ensureMcpError(error); methodLogger.error(`${mcpError.type} error`, mcpError); // Get the deep original error for more context const originalError = getDeepOriginalError(mcpError.originalError); // Print the error message console.error(`Error: ${mcpError.message}`); // Provide helpful context based on error type if (mcpError.type === ErrorType.AUTH_MISSING) { console.error('\nTip: Run "mcp-aws-sso login" to authenticate with AWS SSO.'); } else if (mcpError.type === ErrorType.AUTH_INVALID) { console.error('\nTip: Your AWS SSO session may have expired. Run "mcp-aws-sso login" to re-authenticate.'); } else if (mcpError.type === ErrorType.API_ERROR) { if (mcpError.statusCode === 429) { console.error('\nTip: You may have exceeded AWS API rate limits. Try again later with fewer concurrent requests.'); } // Add AWS SSO specific context if available if (originalError && typeof originalError === 'object') { const origErr = originalError; if (origErr.error === 'authorization_pending') { console.error('\nThe AWS SSO authorization is still pending. Please complete the authorization in your browser.'); } else if (origErr.error === 'access_denied') { console.error('\nThe AWS SSO authorization was denied. Please try again and approve the access request.'); } else if (origErr.error === 'expired_token') { console.error('\nThe AWS SSO token has expired. Please run "mcp-aws-sso login" to get a new token.'); } else if (origErr.error === 'slow_down') { console.error('\nYou are polling too frequently. Please wait longer between authorization checks.'); } } } // Display DEBUG tip if (process.env.DEBUG !== 'true') { console.error('\nFor more detailed error information, run with DEBUG=true environment variable.'); } process.exit(1); }