@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
120 lines (119 loc) • 4.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatCommandResult = formatCommandResult;
const formatter_util_js_1 = require("../utils/formatter.util.js");
const aws_sso_util_js_1 = require("../utils/aws.sso.util.js");
/**
* Formats the result of an executed command into Markdown
*
* @param command The command that was executed (used for context, not displayed directly)
* @param result The execution result containing stdout, stderr, and exit code
* @param options Optional context like account, role, region, and suggested roles
* @returns Formatted Markdown string
*/
function formatCommandResult(_command, result, options) {
const defaultRegion = (0, aws_sso_util_js_1.getDefaultAwsRegion)();
const isSuccess = result.exitCode === 0;
const isPermissionError = options?.suggestedRoles && options.suggestedRoles.length > 0;
// Title with error indicator if needed
const title = isSuccess
? 'AWS SSO: Command Result'
: '❌ AWS SSO: Command Error';
// Build context properties as a single string per line
const contextProps = {};
if (options?.accountId && options?.roleName) {
contextProps['Account/Role'] =
`${options.accountId}/${options.roleName}`;
}
if (options?.region || defaultRegion) {
contextProps['Region'] = options?.region || defaultRegion;
// Add default region info if different
if (options?.region &&
defaultRegion &&
options.region !== defaultRegion) {
contextProps['Region'] =
`${options.region} (Default: ${defaultRegion})`;
}
}
// Generate output sections based on command result
const outputSections = [];
// Always add the command that was executed
outputSections.push({
heading: 'Command',
content: _command,
isCodeBlock: true,
language: 'bash',
});
if (isSuccess) {
// Success case
outputSections.push({
heading: 'Output',
content: result.stdout && result.stdout.trim()
? result.stdout
: '*Command completed successfully with no output.*',
isCodeBlock: !!(result.stdout && result.stdout.trim()),
});
// Show stderr as warnings if present, even on success
if (result.stderr && result.stderr.trim()) {
outputSections.push({
heading: 'Warnings (stderr)',
content: result.stderr,
isCodeBlock: true,
});
}
}
else {
// Error case - Customize error title based on the specific error
let errorTitle = 'Error';
let errorDescription = 'The command failed to execute.';
if (isPermissionError) {
errorTitle = 'Error: Permission Denied';
errorDescription = `The role \`${options?.roleName}\` does not have permission to execute this command.`;
}
else if (result.stderr && result.stderr.includes('not found')) {
errorTitle = 'Error: Command Not Found';
}
else if (result.exitCode) {
errorTitle = `Error: Command Failed (Exit Code ${result.exitCode})`;
}
outputSections.push({
heading: errorTitle,
content: errorDescription,
});
// Add stderr if available
if (result.stderr && result.stderr.trim()) {
outputSections.push({
heading: 'Error Details',
content: result.stderr,
isCodeBlock: true,
});
}
else if (result.stdout && result.stdout.trim()) {
// Sometimes errors go to stdout
outputSections.push({
heading: 'Command Output',
content: result.stdout,
isCodeBlock: true,
});
}
// Add troubleshooting section
if (isPermissionError && options?.suggestedRoles?.length) {
const troubleshootingContent = [
'### Available Roles',
...options.suggestedRoles.map((role) => `- ${role.roleName}`),
'',
'Try executing the command again using one of the roles listed above that has appropriate permissions.',
];
outputSections.push({
heading: 'Troubleshooting',
content: troubleshootingContent,
});
}
}
// Add simple footer with timestamp
const footerInfo = [`*Executed: ${(0, formatter_util_js_1.formatDate)(new Date())}*`];
return (0, formatter_util_js_1.baseCommandFormatter)(title, contextProps, outputSections, footerInfo,
// We no longer need the identity info section as we've incorporated
// this information directly in the contextProps
undefined);
}