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

117 lines (116 loc) 5.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetchApi = fetchApi; exports.post = post; exports.getSsoOidcEndpoint = getSsoOidcEndpoint; const logger_util_js_1 = require("./logger.util.js"); const error_util_js_1 = require("./error.util.js"); // Create a contextualized logger for this file const transportLogger = logger_util_js_1.Logger.forContext('utils/transport.util.ts'); // Log transport utility initialization transportLogger.debug('Transport utility initialized'); /** * Generic and reusable function to fetch data from any API endpoint. * Handles standard HTTP request setup, response checking, basic error handling, and logging. * * @param url The full URL to fetch data from. * @param options Request options including method, headers, and body. * @returns The response data parsed as type T. * @throws {McpError} If the request fails, including network errors, non-OK HTTP status, or JSON parsing issues. */ async function fetchApi(url, options = {}) { const methodLogger = logger_util_js_1.Logger.forContext('utils/transport.util.ts', 'fetchApi'); // Prepare standard request options const requestOptions = { method: options.method || 'GET', headers: { // Standard headers, allow overrides via options.headers 'Content-Type': 'application/json', Accept: 'application/json', ...options.headers, }, body: options.body ? JSON.stringify(options.body) : undefined, }; methodLogger.debug(`Executing API call: ${requestOptions.method} ${url}`); const startTime = performance.now(); // Track performance try { const response = await fetch(url, requestOptions); const endTime = performance.now(); const duration = (endTime - startTime).toFixed(2); methodLogger.debug(`API call completed in ${duration}ms with status: ${response.status} ${response.statusText}`, { url, status: response.status }); // Check if the response status is OK (2xx) if (!response.ok) { const errorText = await response.text(); // Get error body for context methodLogger.error(`API error response (${response.status}):`, errorText); // Classify standard HTTP errors if (response.status === 401) { throw (0, error_util_js_1.createAuthInvalidError)('Authentication failed. Check API token if required.'); } else if (response.status === 403) { throw (0, error_util_js_1.createAuthInvalidError)('Permission denied for the requested resource.'); } else if (response.status === 404) { throw (0, error_util_js_1.createApiError)('Resource not found at the specified URL.', response.status, errorText); } else { // Generic API error for other non-2xx statuses throw (0, error_util_js_1.createApiError)(`API request failed with status ${response.status}: ${response.statusText}`, response.status, errorText); } } // Attempt to parse the response body as JSON try { const responseData = await response.json(); methodLogger.debug('Response body successfully parsed as JSON.'); // methodLogger.debug('Response Data:', responseData); // Uncomment for full response logging return responseData; } catch (parseError) { methodLogger.error('Failed to parse API response JSON:', parseError); // Throw a specific error for JSON parsing failure throw (0, error_util_js_1.createApiError)(`Failed to parse API response JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`, response.status, // Include original status for context parseError); } } catch (error) { const endTime = performance.now(); const duration = (endTime - startTime).toFixed(2); methodLogger.error(`API call failed after ${duration}ms for ${url}:`, error); // Rethrow if it's already an McpError (e.g., from status checks or parsing) if (error instanceof error_util_js_1.McpError) { throw error; } // Handle potential network errors (TypeError in fetch) if (error instanceof TypeError) { throw (0, error_util_js_1.createApiError)(`Network error during API call: ${error.message}`, undefined, // No specific HTTP status for network errors error); } // Wrap any other unexpected errors throw (0, error_util_js_1.createUnexpectedError)(`Unexpected error during API call: ${error instanceof Error ? error.message : String(error)}`, error); } } /** * Convenience function to make a POST request using fetchApi * @param url The URL to send the POST request to * @param data The data to include in the request body * @returns The response data parsed as type T */ async function post(url, data) { return fetchApi(url, { method: 'POST', body: data, }); } /** * Constructs a fully qualified AWS SSO OIDC endpoint URL * @param region The AWS region (e.g., 'us-east-1') * @param apiPath The API path (e.g., '/client/register', '/device_authorization', '/token') * @returns The fully constructed endpoint URL */ function getSsoOidcEndpoint(region, apiPath) { // Ensure the API path starts with a slash const normalizedPath = apiPath.startsWith('/') ? apiPath : `/${apiPath}`; // Construct the base URL with the region const baseUrl = `https://oidc.${region}.amazonaws.com`; // Return the full endpoint URL return `${baseUrl}${normalizedPath}`; }