Skip to main content
Glama
smart-bonding-api.ts19.2 kB
import { Tool } from '@modelcontextprotocol/sdk/types.js'; import { SmartBondingBaseApi } from './smart-bonding-base-api.js'; import { ToolArgs } from '../utils/validation.js'; import { ApiResponse } from '../utils/formatting.js'; /** * ⚠️ EXPERIMENTAL: Smart Bonding Customer API Implementation * * Provides tools for: * - Pulling ticket updates from Cisco Smart Bonding * - Pushing (creating/updating) tickets to Cisco Smart Bonding * * Status: UNTESTED - Requires credentials from Cisco Account Manager * * Credentials needed: * - SMART_BONDING_CLIENT_ID * - SMART_BONDING_CLIENT_SECRET * * Contact your Cisco Account Manager to obtain Smart Bonding API access. */ export class SmartBondingApi extends SmartBondingBaseApi { getTools(): Tool[] { return [ { name: 'get_smart_bonding_tsp_codes', description: '⚠️ EXPERIMENTAL/UNTESTED: Retrieve TSP (Technology, Sub-Technology, Problem Code) details for use in ticket classification. TSP codes provide standardized problem categorization for support tickets. Returns taxonomic codes with technical descriptions. Requires SMART_BONDING_CLIENT_ID and SMART_BONDING_CLIENT_SECRET environment variables (contact Cisco Account Manager to obtain).', inputSchema: { type: 'object', properties: { since_id: { type: 'integer', description: 'Only retrieve records with ID greater than this value (optional filter)' }, max_id: { type: 'integer', description: 'Only retrieve records with ID up to this value (optional filter)' }, limit: { type: 'integer', description: 'Limit number of returned records. Must be non-negative.' } }, required: [] } }, { name: 'pull_smart_bonding_tickets', description: '⚠️ EXPERIMENTAL/UNTESTED: Retrieve ticket updates from Cisco Smart Bonding that have not yet been pulled. Returns all new ticket updates since last pull. Requires SMART_BONDING_CLIENT_ID and SMART_BONDING_CLIENT_SECRET environment variables (contact Cisco Account Manager to obtain).', inputSchema: { type: 'object', properties: { correlation_id: { type: 'string', description: 'Optional tracking identifier for end-to-end traceability. If provided, the response will include a corresponding transaction ID.' } }, required: [] } }, { name: 'create_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Create a new support ticket in Cisco Smart Bonding system. Requires complete ticket information including customer ID, description, caller details, and component information. Requires SMART_BONDING_CLIENT_ID and SMART_BONDING_CLIENT_SECRET environment variables (contact Cisco Account Manager to obtain).', inputSchema: { type: 'object', properties: { CustCallID: { type: 'string', description: 'Customer ticket ID (required) - your internal ticket reference' }, ShortDescription: { type: 'string', description: 'Brief description of the issue (required)' }, DetailedDescription: { type: 'string', description: 'Full description of the issue with all relevant details' }, Caller: { type: 'object', description: 'Information about the person reporting the issue (required)', properties: { Name: { type: 'string', description: 'Full name of the caller' }, Email: { type: 'string', description: 'Email address of the caller' }, Phone: { type: 'string', description: 'Phone number of the caller' } }, required: ['Name', 'Email'] }, Priority: { type: 'string', description: 'Priority level of the ticket', enum: ['Low', 'Medium', 'High', 'Critical', 'Escalated'] }, Severity: { type: 'string', description: 'Severity level (1=Critical, 2=High, 3=Medium, 4=Low)', enum: ['1', '2', '3', '4'] }, correlation_id: { type: 'string', description: 'Optional tracking identifier for end-to-end traceability' } }, required: ['CustCallID', 'ShortDescription', 'Caller'] } }, { name: 'update_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Update an existing support ticket with work notes and status changes. Use this to add updates, notes, or modify ticket information.', inputSchema: { type: 'object', properties: { CustCallID: { type: 'string', description: 'Customer ticket ID to update (required)' }, Remarks: { type: 'string', description: 'Work notes or update comments to add to the ticket' }, Status: { type: 'string', description: 'New status for the ticket', enum: ['Update', 'Open', 'Pending', 'In Progress'] }, correlation_id: { type: 'string', description: 'Optional tracking identifier for end-to-end traceability' } }, required: ['CustCallID'] } }, { name: 'upload_file_to_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Upload a file to a Smart Bonding ticket using credentials from ticket creation response. Upload credentials (Field80-82) are provided when creating a ticket and must be saved. Uses HTTPS PUT to Cisco upload domain (cxd.cisco.com). Files cannot be modified after upload - submit new files for corrections.', inputSchema: { type: 'object', properties: { ticket_number: { type: 'string', description: 'Cisco SR ticket number (username for upload authentication)' }, upload_token: { type: 'string', description: 'Upload token from Field81 of ticket creation response (password for authentication)' }, upload_domain: { type: 'string', description: 'Upload domain from Field80 (e.g., cxd.cisco.com). Optional - defaults to cxd.cisco.com', default: 'cxd.cisco.com' }, filename: { type: 'string', description: 'Name of the file to upload (e.g., "showtech.txt", "screenshot.png")' }, file_content: { type: 'string', description: 'Base64-encoded file content to upload' } }, required: ['ticket_number', 'upload_token', 'filename', 'file_content'] } }, { name: 'escalate_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Escalate a support ticket to Cisco by changing priority to "Escalated". Use this for critical issues requiring immediate Cisco attention.', inputSchema: { type: 'object', properties: { CustCallID: { type: 'string', description: 'Customer ticket ID to escalate (required)' }, Remarks: { type: 'string', description: 'Escalation reason and details' }, Severity: { type: 'string', description: 'Escalated severity level (typically 1 for critical escalations)', enum: ['1', '2', '3', '4'] }, correlation_id: { type: 'string', description: 'Optional tracking identifier' } }, required: ['CustCallID', 'Remarks'] } }, { name: 'resolve_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Mark a support ticket as "Resolved" with resolution notes. Use this when the issue has been fixed but before final closure.', inputSchema: { type: 'object', properties: { CustCallID: { type: 'string', description: 'Customer ticket ID to resolve (required)' }, Remarks: { type: 'string', description: 'Resolution details and work notes (required)' }, correlation_id: { type: 'string', description: 'Optional tracking identifier' } }, required: ['CustCallID', 'Remarks'] } }, { name: 'close_smart_bonding_ticket', description: '⚠️ EXPERIMENTAL/UNTESTED: Close a completed support ticket with diagnosis and solution. This is the final state for a ticket after resolution and customer confirmation.', inputSchema: { type: 'object', properties: { CustCallID: { type: 'string', description: 'Customer ticket ID to close (required)' }, Solution: { type: 'string', description: 'Final solution description (required)' }, Diagnosis: { type: 'string', description: 'Problem diagnosis details' }, correlation_id: { type: 'string', description: 'Optional tracking identifier' } }, required: ['CustCallID', 'Solution'] } } ]; } async executeTool(name: string, args: ToolArgs, meta?: { progressToken?: string }): Promise<ApiResponse> { const { tool, processedArgs } = this.validateTool(name, args); switch (name) { case 'get_smart_bonding_tsp_codes': return await this.getTspCodes(processedArgs); case 'pull_smart_bonding_tickets': return await this.pullTickets(processedArgs); case 'create_smart_bonding_ticket': return await this.createTicket(processedArgs); case 'update_smart_bonding_ticket': return await this.updateTicket(processedArgs); case 'upload_file_to_smart_bonding_ticket': return await this.uploadFile(processedArgs); case 'escalate_smart_bonding_ticket': return await this.escalateTicket(processedArgs); case 'resolve_smart_bonding_ticket': return await this.resolveTicket(processedArgs); case 'close_smart_bonding_ticket': return await this.closeTicket(processedArgs); default: throw new Error(`Unknown Smart Bonding tool: ${name}`); } } /** * Get TSP (Technology, Sub-Technology, Problem Code) details * GET /tspcodes */ private async getTspCodes(args: ToolArgs): Promise<ApiResponse> { const params: Record<string, any> = {}; if (args.since_id !== undefined) { params.since_id = args.since_id; } if (args.max_id !== undefined) { params.max_id = args.max_id; } if (args.limit !== undefined) { params.limit = args.limit; } const result = await this.makeApiCall( '/tspcodes', 'GET', undefined, params ); // Add experimental warning to response return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature. Smart Bonding API requires credentials from Cisco Account Manager.', _environment: process.env.SMART_BONDING_ENV || 'production', _usage_note: 'Use these TSP codes when creating tickets to ensure proper problem categorization.' }; } /** * Pull ticket updates from Cisco Smart Bonding * GET /pull/call */ private async pullTickets(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; const result = await this.makeApiCall( '/pull/call', 'GET', undefined, {}, correlationId ); // Add experimental warning to response return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature. Smart Bonding API requires credentials from Cisco Account Manager.', _environment: process.env.SMART_BONDING_ENV || 'production' }; } /** * Create a new ticket in Cisco Smart Bonding * POST /push/call */ private async createTicket(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; // Build ticket creation payload const ticketData: Record<string, any> = { CustCallID: args.CustCallID, ShortDescription: args.ShortDescription, Caller: args.Caller }; if (args.DetailedDescription) { ticketData.DetailedDescription = args.DetailedDescription; } if (args.Priority) { ticketData.Priority = args.Priority; } if (args.Severity) { ticketData.Severity = args.Severity; } const result = await this.makeApiCall( '/push/call', 'POST', ticketData, {}, correlationId ); return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature. Smart Bonding API requires credentials from Cisco Account Manager.', _environment: process.env.SMART_BONDING_ENV || 'production', _operation: 'create_ticket' }; } /** * Update an existing ticket with work notes * POST /push/call */ private async updateTicket(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; const ticketData: Record<string, any> = { CustCallID: args.CustCallID }; if (args.Remarks) { ticketData.Remarks = args.Remarks; } if (args.Status) { ticketData.CallStates = args.Status; } const result = await this.makeApiCall( '/push/call', 'POST', ticketData, {}, correlationId ); return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature.', _environment: process.env.SMART_BONDING_ENV || 'production', _operation: 'update_ticket' }; } /** * Upload file to Smart Bonding ticket using credentials from ticket creation * HTTPS PUT to cxd.cisco.com (separate from Smart Bonding API) */ private async uploadFile(args: ToolArgs): Promise<ApiResponse> { const ticketNumber = args.ticket_number as string; const uploadToken = args.upload_token as string; const uploadDomain = (args.upload_domain as string) || 'cxd.cisco.com'; const filename = args.filename as string; const fileContent = args.file_content as string; // Decode Base64 file content let fileBuffer: Buffer; try { fileBuffer = Buffer.from(fileContent, 'base64'); } catch (error) { throw new Error('Invalid Base64 file content'); } const uploadUrl = `https://${uploadDomain}/home/${filename}`; const credentials = Buffer.from(`${ticketNumber}:${uploadToken}`).toString('base64'); try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 120000); // 2 minute timeout for file uploads const response = await fetch(uploadUrl, { method: 'PUT', headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/octet-stream', 'Content-Length': fileBuffer.length.toString() }, body: fileBuffer, signal: controller.signal }); clearTimeout(timeoutId); if (response.status === 201) { return { status: 'success', message: 'File uploaded successfully', filename: filename, upload_url: uploadUrl, http_status: 201, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature.', _operation: 'file_upload', _note: 'Files cannot be modified after upload. Submit new files for corrections.' }; } else { const errorText = await response.text(); throw new Error(`File upload failed: ${response.status} ${response.statusText} - ${errorText}`); } } catch (error) { if (error instanceof Error) { if (error.name === 'AbortError') { throw new Error('File upload timed out after 2 minutes. Please try with a smaller file.'); } } throw error; } } /** * Escalate ticket to Cisco * POST /push/call */ private async escalateTicket(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; const ticketData: Record<string, any> = { CustCallID: args.CustCallID, Priorities: 'Escalated' }; if (args.Remarks) { ticketData.Remarks = args.Remarks; } if (args.Severity) { ticketData.Severities = args.Severity; } const result = await this.makeApiCall( '/push/call', 'POST', ticketData, {}, correlationId ); return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature.', _environment: process.env.SMART_BONDING_ENV || 'production', _operation: 'escalate_ticket' }; } /** * Resolve ticket with resolution notes * POST /push/call */ private async resolveTicket(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; const ticketData: Record<string, any> = { CustCallID: args.CustCallID, CallStates: 'Resolved', Remarks: args.Remarks }; const result = await this.makeApiCall( '/push/call', 'POST', ticketData, {}, correlationId ); return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature.', _environment: process.env.SMART_BONDING_ENV || 'production', _operation: 'resolve_ticket' }; } /** * Close ticket with diagnosis and solution * POST /push/call */ private async closeTicket(args: ToolArgs): Promise<ApiResponse> { const correlationId = args.correlation_id as string | undefined; const ticketData: Record<string, any> = { CustCallID: args.CustCallID, CallStates: 'Closed', Solution: args.Solution }; if (args.Diagnosis) { ticketData.Diagnosis = args.Diagnosis; } const result = await this.makeApiCall( '/push/call', 'POST', ticketData, {}, correlationId ); return { ...result, _experimental_warning: '⚠️ This is an EXPERIMENTAL/UNTESTED feature.', _environment: process.env.SMART_BONDING_ENV || 'production', _operation: 'close_ticket' }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sieteunoseis/mcp-cisco-support'

If you have feedback or need assistance with the MCP directory API, please join our Discord server