@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
JavaScript
;
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);
}