UNPKG

mcp-cisco-support

Version:

MCP server for Cisco Support APIs including Bug Search and future tools

161 lines 7.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SmartBondingBaseApi = void 0; const smart_bonding_auth_js_1 = require("../utils/smart-bonding-auth.js"); const logger_js_1 = require("../utils/logger.js"); const validation_js_1 = require("../utils/validation.js"); /** * ⚠️ EXPERIMENTAL: Smart Bonding Base API * * Base class for Smart Bonding API tools with separate authentication system. * Uses different OAuth2 endpoint (cloudsso.cisco.com) than standard Support APIs. * * Status: UNTESTED - Requires Smart Bonding credentials from Cisco Account Manager */ class SmartBondingBaseApi { baseUrl; apiName = 'Smart Bonding'; constructor() { // Environment-based URL (staging vs production) const env = process.env.SMART_BONDING_ENV || 'production'; this.baseUrl = env === 'staging' ? 'https://stage.sbnprd.xylem.cisco.com/sb-partner-oauth-proxy-api/rest/v1' : 'https://sb.xylem.cisco.com/sb-partner-oauth-proxy-api/rest/v1'; logger_js_1.logger.info(`Smart Bonding API initialized`, { environment: env, baseUrl: this.baseUrl, status: 'EXPERIMENTAL/UNTESTED' }); } /** * Make authenticated API call to Smart Bonding endpoint * Supports both GET and POST methods (unlike standard Support APIs) */ async makeApiCall(endpoint, method = 'GET', body, params = {}, correlationId) { const token = await (0, smart_bonding_auth_js_1.getValidSmartBondingToken)(); // Build query string for GET requests const queryParams = new URLSearchParams(); if (method === 'GET') { Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== '') { queryParams.append(key, String(value)); } }); } const queryString = queryParams.toString(); const url = `${this.baseUrl}${endpoint}${queryString ? '?' + queryString : ''}`; try { logger_js_1.logger.info(`Making Smart Bonding API call [EXPERIMENTAL]`, { method, endpoint, params, fullUrl: url, hasBody: !!body, correlationId: correlationId || '(none)' }); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 second timeout const headers = { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json', 'User-Agent': 'mcp-cisco-support/1.0-smart-bonding-experimental' }; // Add correlation ID header if provided if (correlationId) { headers['x-correlation-id'] = correlationId; } // Add Content-Type for POST requests if (method === 'POST' && body) { headers['Content-Type'] = 'application/json'; } const fetchOptions = { method, headers, signal: controller.signal }; // Add body for POST requests if (method === 'POST' && body) { fetchOptions.body = JSON.stringify(body); } const response = await fetch(url, fetchOptions); clearTimeout(timeoutId); if (response.status === 401) { logger_js_1.logger.warn('Smart Bonding API returned 401, token may be expired, refreshing...'); // Token expired, refresh and retry once const newToken = await (0, smart_bonding_auth_js_1.getValidSmartBondingToken)(); const retryController = new AbortController(); const retryTimeoutId = setTimeout(() => retryController.abort(), 60000); const retryHeaders = { ...headers, 'Authorization': `Bearer ${newToken}` }; const retryOptions = { ...fetchOptions, signal: retryController.signal, headers: retryHeaders }; const retryResponse = await fetch(url, retryOptions); clearTimeout(retryTimeoutId); if (!retryResponse.ok) { const errorText = await retryResponse.text(); logger_js_1.logger.error('Smart Bonding API call failed after token refresh', { status: retryResponse.status, errorText: errorText.substring(0, 500) }); throw new Error(`Smart Bonding API call failed after token refresh: ${retryResponse.status} ${retryResponse.statusText} - ${errorText}`); } const retryData = await retryResponse.json(); return retryData; } if (!response.ok) { const errorText = await response.text(); logger_js_1.logger.error(`Smart Bonding API call failed`, { status: response.status, statusText: response.statusText, url: url, method, errorText: errorText.substring(0, 500) }); throw new Error(`Smart Bonding API call failed: ${response.status} ${response.statusText} - URL: ${url} - ${errorText}`); } const data = await response.json(); logger_js_1.logger.info(`Smart Bonding API call successful`, { endpoint, method, resultCount: this.getResultCount(data) }); return data; } catch (error) { // Handle specific timeout errors if (error instanceof Error) { if (error.name === 'AbortError' || error.message.includes('timeout')) { logger_js_1.logger.error(`Smart Bonding API call timed out`, { endpoint, method, timeout: '60s' }); throw new Error(`Smart Bonding API call timed out after 60 seconds. The API may be experiencing high load. Please try again later.`); } else if (error.message.includes('Headers Timeout') || error.message.includes('UND_ERR_HEADERS_TIMEOUT')) { logger_js_1.logger.error(`Smart Bonding API headers timeout`, { endpoint, method }); throw new Error(`Smart Bonding API connection timed out while waiting for response headers. The service may be temporarily unavailable.`); } } logger_js_1.logger.error(`Smart Bonding API call failed`, { endpoint, method, error: error instanceof Error ? error.message : error }); throw error; } } // Validate tool arguments validateTool(name, args) { const tools = this.getTools(); const tool = tools.find(t => t.name === name); if (!tool) { throw new Error(`Unknown Smart Bonding tool: ${name}`); } (0, validation_js_1.validateToolArgs)(tool, args); const processedArgs = (0, validation_js_1.setDefaultValues)(args); return { tool, processedArgs }; } // Get result count from API response getResultCount(data) { if ('tickets' in data && Array.isArray(data.tickets)) { return data.tickets.length; } if ('status' in data && data.status === 'success') { return 1; // Single operation success } return 0; } } exports.SmartBondingBaseApi = SmartBondingBaseApi; //# sourceMappingURL=smart-bonding-base-api.js.map