Skip to main content
Glama

VoiceAI-MCP-VAVicky

Official
index.js27.1 kB
#!/usr/bin/env node /** * Vavicky MCP Server * Complete MCP implementation for VoiceAI VAVicky AiAgency platform */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import fetch from 'node-fetch'; class VavickyMCPServer { constructor() { this.server = new Server( { name: 'vavicky-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.apiKey = process.env.VAVICKY_API_KEY; this.baseUrl = 'https://backend.vavicky.com/vavicky/api'; this.setupToolHandlers(); } setupToolHandlers() { // List all available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ // User Management { name: 'get_user', description: 'Get user data including tokens and settings', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'update_white_label', description: 'Update White Label details: name, description, domain and color', inputSchema: { type: 'object', properties: { whitelabel_name: { type: 'string', description: 'White label name' }, whitelabel_description: { type: 'string', description: 'White label description' }, whitelabel_domain: { type: 'string', description: 'White label domain' }, whitelabel_color: { type: 'string', description: 'White label color (hex code)' } }, required: [] } }, { name: 'update_smtp', description: 'Update SMTP settings for custom email notifications', inputSchema: { type: 'object', properties: { smtp_email: { type: 'string', description: 'SMTP email address' }, smtp_password: { type: 'string', description: 'SMTP password' }, smtp_host: { type: 'string', description: 'SMTP host' }, smtp_port: { type: 'string', description: 'SMTP port' } }, required: ['smtp_email', 'smtp_password', 'smtp_host'] } }, // API Token Management { name: 'update_openai_token', description: 'Update OpenAI API Key', inputSchema: { type: 'object', properties: { openai_token: { type: 'string', description: 'OpenAI API Key' } }, required: ['openai_token'] } }, { name: 'update_elevenlabs_token', description: 'Update Elevenlabs API Key', inputSchema: { type: 'object', properties: { elevenlabs_token: { type: 'string', description: 'Elevenlabs API Key' } }, required: ['elevenlabs_token'] } }, { name: 'update_deepseek_token', description: 'Update Deepseek API Key', inputSchema: { type: 'object', properties: { deepseek_token: { type: 'string', description: 'Deepseek API Key' } }, required: ['deepseek_token'] } }, { name: 'update_gemini_token', description: 'Update Google Gemini API Key', inputSchema: { type: 'object', properties: { gemini_token: { type: 'string', description: 'Google Gemini API Key' } }, required: ['gemini_token'] } }, { name: 'update_openrouter_token', description: 'Update Open Router API Key', inputSchema: { type: 'object', properties: { openrouter_token: { type: 'string', description: 'Open Router API Key' } }, required: ['openrouter_token'] } }, // Assistant Management { name: 'get_assistants', description: 'Get all assistants for the authenticated user', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_assistant', description: 'Get basic information about a specific assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' } }, required: ['assistant_id'] } }, { name: 'get_one_assistant', description: 'Get complete information about a specific assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' } }, required: ['assistant_id'] } }, { name: 'create_assistant', description: 'Create a new assistant with comprehensive configuration', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Assistant name' }, apiKey: { type: 'string', description: 'OpenAI API Key' }, welcome_message: { type: 'string', description: 'Welcome message', default: 'Hello how can I help you today?' }, prompt: { type: 'string', description: 'Instructions/Prompt for the assistant' }, active: { type: 'boolean', description: 'Whether assistant is active', default: true }, assistant_type: { type: 'string', enum: ['Text Only', 'Voice Only', 'Text & Voice', 'Voice & Text'], description: 'AI Type' }, ai_platform: { type: 'string', enum: ['openai', 'gemini', 'openrouter', 'deepseek'], description: 'AI Provider' }, openai_model: { type: 'string', description: 'AI Model', default: 'gpt-3.5-turbo' }, openai_temperature: { type: 'number', description: 'AI Temperature (0-2)', default: 0.8 }, booking_bot: { type: 'boolean', description: 'Is booking bot', default: false }, location: { type: 'string', description: 'GoHighLevel Location' }, calendar: { type: 'string', description: 'Calendar ID' }, timezone: { type: 'string', description: 'Timezone' }, custom_field: { type: 'string', description: 'Custom field' }, limit_call_time: { type: 'number', description: 'Limit call time in seconds', default: 240 }, limit_call_tokens: { type: 'number', description: 'Limit call tokens', default: 2000 }, max_call_tokens: { type: 'number', description: 'Max call tokens', default: 18000 }, elevenlabs_voice_id: { type: 'string', description: 'ElevenLabs Voice ID' }, twilio_sid: { type: 'string', description: 'Twilio SID' }, twilio_token: { type: 'string', description: 'Twilio Token' }, twilio_phone: { type: 'string', description: 'Twilio Phone Number' }, twilio_welcome: { type: 'string', description: 'Twilio Welcome Message' }, twilio_speech_timeout: { type: 'number', description: 'Twilio Speech Timeout', default: 3 }, twilio_initial_delay: { type: 'number', description: 'Twilio Initial Delay', default: 1 }, google_calendar: { type: 'boolean', description: 'Google Calendar Integration', default: false }, webhook_to_send: { type: 'string', description: 'Webhook URL' }, openai_realtime: { type: 'boolean', description: 'OpenAI Realtime', default: false }, openai_realtime_voice: { type: 'string', enum: ['alloy', 'echo', 'fable', 'nova', 'onyx', 'shimmer'], description: 'OpenAI Realtime Voice' }, openai_websites: { type: 'array', items: { type: 'string' }, description: 'OpenAI Websites' } }, required: ['name', 'apiKey'] } }, { name: 'update_assistant', description: 'Update an existing assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, name: { type: 'string', description: 'Assistant name' }, apiKey: { type: 'string', description: 'OpenAI API Key' }, welcome_message: { type: 'string', description: 'Welcome message' }, prompt: { type: 'string', description: 'Instructions/Prompt' }, active: { type: 'boolean', description: 'Whether assistant is active' }, assistant_type: { type: 'string', enum: ['Text Only', 'Voice Only', 'Text & Voice', 'Voice & Text'] }, ai_platform: { type: 'string', enum: ['openai', 'gemini', 'openrouter', 'deepseek'] }, openai_model: { type: 'string', description: 'AI Model' }, openai_temperature: { type: 'number', description: 'AI Temperature (0-2)' }, booking_bot: { type: 'boolean', description: 'Is booking bot' }, location: { type: 'string', description: 'GoHighLevel Location' }, calendar: { type: 'string', description: 'Calendar ID' }, timezone: { type: 'string', description: 'Timezone' }, custom_field: { type: 'string', description: 'Custom field' } }, required: ['assistant_id'] } }, { name: 'delete_assistant', description: 'Delete an assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' } }, required: ['assistant_id'] } }, // Assistant Files { name: 'get_assistant_files', description: 'Get files associated with an assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' } }, required: ['assistant_id'] } }, { name: 'delete_assistant_file', description: 'Delete a specific file from an assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, file_id: { type: 'string', description: 'File ID' } }, required: ['assistant_id', 'file_id'] } }, // Assistant Usage & Analytics { name: 'get_assistant_usage', description: 'Get usage statistics for an assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' } }, required: ['assistant_id'] } }, { name: 'get_assistants_token_usage', description: 'Get token usage across all assistants', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_dashboard_assistant', description: 'Get the dashboard assistant for the authenticated user', inputSchema: { type: 'object', properties: {}, required: [] } }, // Chat with Assistant { name: 'chat_with_assistant', description: 'Chat with a specific assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, message: { type: 'string', description: 'Message to send' }, thread_id: { type: 'string', description: 'Chat/Thread ID' }, audio: { type: 'boolean', description: 'Enable audio response', default: false } }, required: ['assistant_id', 'message', 'thread_id'] } }, // Twilio Operations { name: 'connect_twilio', description: 'Connect Twilio account credentials', inputSchema: { type: 'object', properties: { twilio_sid: { type: 'string', description: 'Twilio Account SID' }, twilio_token: { type: 'string', description: 'Twilio Auth Token' } }, required: ['twilio_sid', 'twilio_token'] } }, { name: 'disconnect_twilio', description: 'Disconnect Twilio account', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_twilio_numbers', description: 'Get all Twilio phone numbers', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_available_numbers', description: 'Get available phone numbers for purchase', inputSchema: { type: 'object', properties: { country_code: { type: 'string', description: 'Country code', default: 'US' }, number_type: { type: 'string', enum: ['local', 'tollfree', 'mobile'], description: 'Number type', default: 'local' }, search_pattern: { type: 'string', description: 'Search for numbers containing this pattern' }, locality: { type: 'string', description: 'Locality/city for local numbers' } }, required: [] } }, { name: 'buy_twilio_number', description: 'Purchase a new Twilio phone number', inputSchema: { type: 'object', properties: { phone_number: { type: 'string', description: 'Phone number to purchase' } }, required: ['phone_number'] } }, { name: 'update_twilio_number', description: 'Update Twilio number configuration', inputSchema: { type: 'object', properties: { number_sid: { type: 'string', description: 'Number SID' }, friendly_name: { type: 'string', description: 'Friendly name' }, voice_webhook: { type: 'string', description: 'Voice webhook URL' }, sms_webhook: { type: 'string', description: 'SMS webhook URL' } }, required: ['number_sid'] } }, { name: 'get_twilio_usage', description: 'Get Twilio usage statistics', inputSchema: { type: 'object', properties: { start_date: { type: 'string', description: 'Start date (ISO format)' }, end_date: { type: 'string', description: 'End date (ISO format)' }, limit: { type: 'number', description: 'Max number of results', default: 50 } }, required: [] } }, // Call Management { name: 'make_call', description: 'Make a phone call through assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, phone_number: { type: 'string', description: 'Phone number to call' }, contact_id: { type: 'string', description: 'Contact ID (optional)' } }, required: ['assistant_id', 'phone_number'] } }, { name: 'make_bulk_call', description: 'Make bulk phone calls', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, contact_bulk_id: { type: 'string', description: 'Contact bulk ID' } }, required: ['assistant_id', 'contact_bulk_id'] } }, { name: 'get_calls_in_progress', description: 'Get all calls currently in progress', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'cancel_call', description: 'Cancel an active phone call', inputSchema: { type: 'object', properties: { call_id: { type: 'string', description: 'Call ID' } }, required: ['call_id'] } }, // SMS Operations { name: 'send_sms', description: 'Send SMS message through assistant', inputSchema: { type: 'object', properties: { assistant_id: { type: 'string', description: 'Assistant ID' }, phone_number: { type: 'string', description: 'Phone number to send SMS' }, message: { type: 'string', description: 'SMS message content' }, contact_id: { type: 'string', description: 'Contact ID (optional)' } }, required: ['assistant_id', 'phone_number', 'message'] } } ] }; }); // Handle tool execution this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (!this.apiKey) { throw new McpError( ErrorCode.InvalidRequest, 'VAVICKY_API_KEY environment variable is required' ); } try { const result = await this.executeTool(name, args || {}); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } catch (error) { throw new McpError( ErrorCode.InternalError, `Tool execution failed: ${error.message}` ); } }); } async executeTool(toolName, args) { const headers = { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json' }; let url, method = 'GET', body = null; switch (toolName) { // User Management case 'get_user': url = `${this.baseUrl}/user`; break; case 'update_white_label': url = `${this.baseUrl}/user`; method = 'PATCH'; body = { whitelabel_name: args.whitelabel_name, whitelabel_description: args.whitelabel_description, whitelabel_domain: args.whitelabel_domain, whitelabel_color: args.whitelabel_color }; break; case 'update_smtp': url = `${this.baseUrl}/user/smtp`; method = 'PATCH'; body = { smtp_email: args.smtp_email, smtp_password: args.smtp_password, smtp_host: args.smtp_host, smtp_port: args.smtp_port }; break; // Token Management case 'update_openai_token': url = `${this.baseUrl}/openai/oauth`; method = 'POST'; body = { openai_token: args.openai_token }; break; case 'update_elevenlabs_token': url = `${this.baseUrl}/elevenlabs/oauth`; method = 'POST'; body = { elevenlabs_token: args.elevenlabs_token }; break; case 'update_deepseek_token': url = `${this.baseUrl}/deepseek/oauth`; method = 'POST'; body = { deepseek_token: args.deepseek_token }; break; case 'update_gemini_token': url = `${this.baseUrl}/gemini/oauth`; method = 'POST'; body = { gemini_token: args.gemini_token }; break; case 'update_openrouter_token': url = `${this.baseUrl}/openrouter/oauth`; method = 'POST'; body = { openrouter_token: args.openrouter_token }; break; // Assistant Management case 'get_assistants': url = `${this.baseUrl}/assistants`; break; case 'get_assistant': url = `${this.baseUrl}/assistants/${args.assistant_id}`; break; case 'get_one_assistant': url = `${this.baseUrl}/assistants/one/${args.assistant_id}`; break; case 'create_assistant': url = `${this.baseUrl}/assistants`; method = 'POST'; body = this.filterEmptyValues(args); break; case 'update_assistant': url = `${this.baseUrl}/assistants/${args.assistant_id}`; method = 'PATCH'; const { assistant_id, ...updateData } = args; body = this.filterEmptyValues(updateData); break; case 'delete_assistant': url = `${this.baseUrl}/assistants/${args.assistant_id}`; method = 'DELETE'; break; case 'get_assistant_files': url = `${this.baseUrl}/assistants/${args.assistant_id}/files`; break; case 'delete_assistant_file': url = `${this.baseUrl}/assistants/${args.assistant_id}/files/${args.file_id}`; method = 'DELETE'; break; case 'get_assistant_usage': url = `${this.baseUrl}/assistants/${args.assistant_id}/usage`; break; case 'get_assistants_token_usage': url = `${this.baseUrl}/assistants/all/token/usage`; break; case 'get_dashboard_assistant': url = `${this.baseUrl}/assistants/gohighlevel/dashboard`; break; case 'chat_with_assistant': url = `${this.baseUrl}/assistants/${args.assistant_id}/chat?audio=${args.audio || false}`; method = 'POST'; body = { message: args.message, thread_id: args.thread_id }; break; // Twilio Operations case 'connect_twilio': url = `${this.baseUrl}/twilio/oauth`; method = 'POST'; body = { sid: args.twilio_sid, token: args.twilio_token }; break; case 'disconnect_twilio': url = `${this.baseUrl}/twilio/`; method = 'DELETE'; break; case 'get_twilio_numbers': url = `${this.baseUrl}/twilio/numbers`; break; case 'get_available_numbers': const params = new URLSearchParams(); if (args.country_code) params.append('code', args.country_code); if (args.number_type) params.append('type', args.number_type); if (args.search_pattern) params.append('search', args.search_pattern); if (args.locality) params.append('locality', args.locality); url = `${this.baseUrl}/twilio/numbers/available?${params.toString()}`; break; case 'buy_twilio_number': url = `${this.baseUrl}/twilio/number/buy`; method = 'POST'; body = { phoneNumber: args.phone_number }; break; case 'update_twilio_number': url = `${this.baseUrl}/twilio/numbers/${args.number_sid}`; method = 'PATCH'; body = {}; if (args.friendly_name) body.name = args.friendly_name; if (args.voice_webhook) body.webhook = args.voice_webhook; if (args.sms_webhook) body.smsWebhook = args.sms_webhook; break; case 'get_twilio_usage': const usageParams = new URLSearchParams(); if (args.start_date) usageParams.append('start', args.start_date); if (args.end_date) usageParams.append('end', args.end_date); if (args.limit) usageParams.append('limit', args.limit.toString()); url = `${this.baseUrl}/twilio/usage?${usageParams.toString()}`; break; // Call Management case 'make_call': url = `${this.baseUrl}/twilio/${args.assistant_id}/call`; method = 'POST'; body = { phonenumber: args.phone_number }; if (args.contact_id) { body.contact_id = args.contact_id; body.customData = { phonenumber: args.phone_number }; } break; case 'make_bulk_call': url = `${this.baseUrl}/twilio/${args.assistant_id}/callbulk/${args.contact_bulk_id}`; method = 'POST'; body = {}; break; case 'get_calls_in_progress': url = `${this.baseUrl}/twilio/calls`; break; case 'cancel_call': url = `${this.baseUrl}/twilio/calls/${args.call_id}`; method = 'DELETE'; break; // SMS Operations case 'send_sms': url = `${this.baseUrl}/twilio/${args.assistant_id}/sms`; method = 'POST'; body = { phonenumber: args.phone_number, message: args.message }; if (args.contact_id) { body.contact_id = args.contact_id; body.customData = { phonenumber: args.phone_number, message: args.message }; } break; default: throw new Error(`Unknown tool: ${toolName}`); } const options = { method, headers }; if (body) { options.body = JSON.stringify(body); } const response = await fetch(url, options); if (!response.ok) { const errorText = await response.text(); throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`); } return await response.json(); } filterEmptyValues(obj) { const cleaned = {}; for (const [key, value] of Object.entries(obj)) { if (value !== undefined && value !== null && value !== '') { cleaned[key] = value; } } return cleaned; } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Vavicky MCP server running on stdio'); } } const server = new VavickyMCPServer(); server.run().catch(console.error); export { VavickyMCPServer };

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/Business-On-Steroids/MCP-VoiceAI-WhiteLabel'

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