Skip to main content
Glama

MiniMax MCP JS

Official
by MiniMax-AI
mcp-server.ts33.5 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { Config, ServerOptions, TransportMode } from './types/index.js'; import { MiniMaxAPI } from './utils/api.js'; import { TTSAPI } from './api/tts.js'; import { ImageAPI } from './api/image.js'; import { VideoAPI } from './api/video.js'; import { VoiceCloneAPI } from './api/voice-clone.js'; import { VoiceAPI } from './api/voice.js'; import { VoiceDesignAPI } from './api/voice-design.js'; import { MusicAPI } from './api/music.js'; import { playAudio } from './utils/audio.js'; import { getParamValue } from '@chatmcp/sdk/utils/index.js'; import fs from 'fs'; import { DEFAULT_API_HOST, DEFAULT_BITRATE, DEFAULT_CHANNEL, DEFAULT_EMOTION, DEFAULT_FORMAT, DEFAULT_LANGUAGE_BOOST, DEFAULT_PITCH, DEFAULT_SAMPLE_RATE, DEFAULT_SPEECH_MODEL, DEFAULT_SPEED, DEFAULT_T2I_MODEL, DEFAULT_VIDEO_MODEL, DEFAULT_VOICE_ID, DEFAULT_VOLUME, ENV_CONFIG_PATH, ENV_MINIMAX_API_HOST, ENV_MINIMAX_API_KEY, ENV_MINIMAX_MCP_BASE_PATH, ENV_RESOURCE_MODE, ERROR_API_HOST_REQUIRED, ERROR_API_KEY_REQUIRED, RESOURCE_MODE_URL, } from './const/index.js'; import { ConfigManager } from './config/ConfigManager.js'; import { COMMON_PARAMETERS_SCHEMA } from './schema/index.js'; /** * MCP Server class for managing MiniMax MCP server configuration and functionality * Specifically designed for STDIO transport mode */ export class MCPServer { private server: McpServer; private config!: Config; private api: MiniMaxAPI; private ttsApi: TTSAPI; private imageApi: ImageAPI; private videoApi: VideoAPI; private voiceCloneApi: VoiceCloneAPI; private voiceApi: VoiceAPI; private voiceDesignApi: VoiceDesignAPI; private musicApi: MusicAPI; /** * Create an MCP server instance (STDIO mode) * @param customConfig Optional custom configuration */ constructor(customConfig?: Partial<Config>) { // Initialize configuration this.initializeConfig(customConfig); // Create API instances this.api = new MiniMaxAPI(this.config); this.ttsApi = new TTSAPI(this.api); this.imageApi = new ImageAPI(this.api); this.videoApi = new VideoAPI(this.api); this.voiceCloneApi = new VoiceCloneAPI(this.api); this.voiceApi = new VoiceAPI(this.api); this.voiceDesignApi = new VoiceDesignAPI(this.api); this.musicApi = new MusicAPI(this.api); // Create server instance this.server = new McpServer({ name: 'minimax-mcp-js', version: '1.0.0', }); // Register all tools this.registerTools(); } /** * Initialize configuration * @param customConfig Custom configuration */ private initializeConfig(customConfig?: Partial<Config>): void { // Use ConfigManager to get configuration, automatically handling priorities this.config = ConfigManager.getConfig(customConfig); // Remove unnecessary server configuration for STDIO mode // STDIO mode doesn't need port and endpoint configuration delete this.config.server; // console.log(`[${new Date().toISOString()}] STDIO server configuration initialized`); } /** * Register all MCP tools */ private registerTools(): void { this.registerTextToAudioTool(); this.registerListVoicesTool(); this.registerPlayAudioTool(); this.registerVoiceCloneTool(); this.registerTextToImageTool(); this.registerGenerateVideoTool(); this.registerImageToVideoTool(); this.registerQueryVideoGenerationTool(); this.registerMusicGenerationTool(); this.registerVoiceDesignTool(); } /** * Register text-to-speech tool */ private registerTextToAudioTool(): void { this.server.tool( 'text_to_audio', 'Convert text to audio with a given voice and save the output audio file to a given directory. If no directory is provided, the file will be saved to desktop. If no voice ID is provided, the default voice will be used.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { text: z.string().describe('Text to convert to audio'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, voiceId: z.string().optional().default(DEFAULT_VOICE_ID).describe('Voice ID to use, e.g. "female-shaonv"'), model: z.string().optional().default(DEFAULT_SPEECH_MODEL).describe('Model to use'), speed: z.number().min(0.5).max(2.0).optional().default(DEFAULT_SPEED).describe('Speech speed'), vol: z.number().min(0.1).max(10.0).optional().default(DEFAULT_VOLUME).describe('Speech volume'), pitch: z.number().min(-12).max(12).optional().default(DEFAULT_PITCH).describe('Speech pitch'), emotion: z .string() .optional() .default(DEFAULT_EMOTION) .describe('Speech emotion, values: ["happy", "sad", "angry", "fearful", "disgusted", "surprised", "neutral"]'), format: z .string() .optional() .default(DEFAULT_FORMAT) .describe('Audio format, values: ["pcm", "mp3","flac", "wav"]'), sampleRate: z .number() .optional() .default(DEFAULT_SAMPLE_RATE) .describe('Sample rate (Hz), values: [8000, 16000, 22050, 24000, 32000, 44100]'), bitrate: z .number() .optional() .default(DEFAULT_BITRATE) .describe('Bitrate (bps), values: [64000, 96000, 128000, 160000, 192000, 224000, 256000, 320000]'), channel: z.number().optional().default(DEFAULT_CHANNEL).describe('Audio channels, values: [1, 2]'), languageBoost: z.string().optional().default(DEFAULT_LANGUAGE_BOOST) .describe(`Enhance the ability to recognize specified languages and dialects. Supported values include: 'Chinese', 'Chinese,Yue', 'English', 'Arabic', 'Russian', 'Spanish', 'French', 'Portuguese', 'German', 'Turkish', 'Dutch', 'Ukrainian', 'Vietnamese', 'Indonesian', 'Japanese', 'Italian', 'Korean', 'Thai', 'Polish', 'Romanian', 'Greek', 'Czech', 'Finnish', 'Hindi', 'auto', default is 'auto'`), subtitleEnable: z .boolean() .optional() .default(false) .describe( `The parameter controls whether the subtitle service is enabled. The model must be 'speech-01-turbo' or 'speech-01-hd'. If this parameter is not provided, the default value is false`, ), outputFile: z .string() .optional() .describe('Path to save the generated audio file, automatically generated if not provided'), }, async (args, extra) => { try { // Build TTS request parameters const ttsParams = { text: args.text, outputDirectory: args.outputDirectory, voiceId: args.voiceId || DEFAULT_VOICE_ID, model: args.model || DEFAULT_SPEECH_MODEL, speed: args.speed || DEFAULT_SPEED, vol: args.vol || DEFAULT_VOLUME, pitch: args.pitch || DEFAULT_PITCH, emotion: args.emotion || DEFAULT_EMOTION, format: args.format || DEFAULT_FORMAT, sampleRate: args.sampleRate || DEFAULT_SAMPLE_RATE, bitrate: args.bitrate || DEFAULT_BITRATE, channel: args.channel || DEFAULT_CHANNEL, languageBoost: args.languageBoost || DEFAULT_LANGUAGE_BOOST, subtitleEnable: args.subtitleEnable || false, outputFile: args.outputFile, }; // Use global configuration const requestApiKey = this.config.apiKey; if (!requestApiKey) { throw new Error(ERROR_API_KEY_REQUIRED); } // Update configuration with request-specific parameters const requestConfig: Partial<Config> = { apiKey: requestApiKey, apiHost: this.config.apiHost, resourceMode: this.config.resourceMode, }; // Update API instance const requestApi = new MiniMaxAPI(requestConfig as Config); const requestTtsApi = new TTSAPI(requestApi); // Automatically set resource mode (if not specified) const outputFormat = requestConfig.resourceMode; const ttsRequest = { ...ttsParams, outputFormat, }; // If no output filename is provided, generate one automatically if (!ttsRequest.outputFile) { const textPrefix = ttsRequest.text.substring(0, 20).replace(/[^\w]/g, '_'); ttsRequest.outputFile = `tts_${textPrefix}_${Date.now()}`; } const result = await requestTtsApi.generateSpeech(ttsRequest); // Return different messages based on output format if (outputFormat === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Audio URL: ${result.audio}. ${ttsParams.subtitleEnable ? `Subtitle file saved: ${result.subtitle}` : ''}`, }, ], }; } else { return { content: [ { type: 'text', text: `Audio file saved: ${result.audio}. ${ttsParams.subtitleEnable ? `Subtitle file saved: ${result.subtitle}. ` : ''}Voice used: ${ttsParams.voiceId}`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to generate audio: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register list voices tool */ private registerListVoicesTool(): void { this.server.tool( 'list_voices', 'List all available voices. Only supported when api_host is https://api.minimax.chat.', { voiceType: z .string() .optional() .default('all') .describe('Type of voices to list, values: ["all", "system", "voice_cloning"]'), }, async (params) => { try { // No need to update configuration from request parameters in stdio mode const result = await this.voiceApi.listVoices(params); return { content: [ { type: 'text', text: `Success. System voices: ${result.systemVoices.join(', ')}, Cloned voices: ${result.voiceCloneVoices.join(', ')}`, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Failed to list voices: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register play audio tool */ private registerPlayAudioTool(): void { this.server.tool( 'play_audio', 'Play an audio file. Supports WAV and MP3 formats. Does not support video.', { inputFilePath: z.string().describe('Path to the audio file to play'), isUrl: z.boolean().optional().default(false).describe('Whether the audio file is a URL'), }, async (params) => { try { // No need to update configuration from request parameters in stdio mode const result = await playAudio(params); return { content: [ { type: 'text', text: result, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Failed to play audio: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register voice clone tool */ private registerVoiceCloneTool(): void { this.server.tool( 'voice_clone', 'Clone a voice using the provided audio file. New voices will incur costs when first used.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { voiceId: z.string().describe('Voice ID to use'), audioFile: z.string().describe('Path to the audio file'), text: z.string().optional().describe('Text for the demo audio'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, isUrl: z.boolean().optional().default(false).describe('Whether the audio file is a URL'), }, async (params) => { try { // No need to update configuration from request parameters in stdio mode const result = await this.voiceCloneApi.cloneVoice(params); return { content: [ { type: 'text', text: `Voice cloning successful: ${result}`, }, ], }; } catch (error) { // 检查是否是实名认证错误 const errorMessage = error instanceof Error ? error.message : String(error); if (errorMessage.includes('voice clone user forbidden') || errorMessage.includes('should complete real-name verification')) { // 国内平台认证URL const verificationUrl = 'https://platform.minimaxi.com/user-center/basic-information'; return { content: [ { type: 'text', text: `Voice cloning failed: Real-name verification required. To use voice cloning feature, please:\n\n1. Visit MiniMax platform (${verificationUrl})\n2. Complete the real-name verification process\n3. Try again after verification is complete\n\nThis requirement is for security and compliance purposes.`, }, ], }; } // 其他错误的常规处理 return { content: [ { type: 'text', text: `Voice cloning failed: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register text-to-image tool */ private registerTextToImageTool(): void { this.server.tool( 'text_to_image', 'Generate images based on text prompts.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { model: z.string().optional().default(DEFAULT_T2I_MODEL).describe('Model to use'), prompt: z.string().describe('Text prompt for image generation'), aspectRatio: z .string() .optional() .default('1:1') .describe('Image aspect ratio, values: ["1:1", "16:9","4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]'), n: z.number().min(1).max(9).optional().default(1).describe('Number of images to generate'), promptOptimizer: z.boolean().optional().default(true).describe('Whether to optimize the prompt'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, outputFile: z .string() .optional() .describe('Path to save the generated image file, automatically generated if not provided'), }, async (params) => { try { // No need to update configuration from request parameters in stdio mode // If no output filename is provided, generate one automatically if (!params.outputFile) { const promptPrefix = params.prompt.substring(0, 20).replace(/[^\w]/g, '_'); params.outputFile = `image_${promptPrefix}_${Date.now()}`; } const outputFiles = await this.imageApi.generateImage(params); // Handle different output formats if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Image URL(s): ${outputFiles.join(', ')}`, }, ], }; } else { return { content: [ { type: 'text', text: `Image(s) saved: ${outputFiles.join(', ')}`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to generate image: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register generate video tool */ private registerGenerateVideoTool(): void { this.server.tool( 'generate_video', 'Generate a video based on text prompts.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { model: z .string() .optional() .default(DEFAULT_VIDEO_MODEL) .describe('Model to use, values: ["T2V-01", "T2V-01-Director", "I2V-01", "I2V-01-Director", "I2V-01-live", "MiniMax-Hailuo-02"]'), prompt: z.string().describe('Text prompt for video generation'), firstFrameImage: z.string().optional().describe('First frame image'), duration: z.number().optional().describe('The duration of the video. The model must be "MiniMax-Hailuo-02". Values can be 6 and 10.'), resolution: z.string().optional().describe('The resolution of the video. The model must be "MiniMax-Hailuo-02". Values range ["768P", "1080P"]'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, outputFile: z .string() .optional() .describe('Path to save the generated video file, automatically generated if not provided'), asyncMode: z .boolean() .optional() .default(false) .describe('Whether to use async mode. Defaults to False. If True, the video generation task will be submitted asynchronously and the response will return a task_id. Should use `query_video_generation` tool to check the status of the task and get the result.'), }, async (params) => { try { // No need to update configuration from request parameters in stdio mode // If no output filename is provided, generate one automatically if (!params.outputFile) { const promptPrefix = params.prompt.substring(0, 20).replace(/[^\w]/g, '_'); params.outputFile = `video_${promptPrefix}_${Date.now()}`; } const result = await this.videoApi.generateVideo(params); if (params.asyncMode) { return { content: [ { type: 'text', text: `Success. Video generation task submitted: Task ID: ${result.task_id}. Please use \`query_video_generation\` tool to check the status of the task and get the result.`, }, ], }; } else { // Handle different output formats if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Video URL: ${result.video_url}`, }, ], }; } else { return { content: [ { type: 'text', text: `Video saved: ${result.video_path}`, }, ], }; } } } catch (error) { return { content: [ { type: 'text', text: `Failed to generate video: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register image-to-video tool */ private registerImageToVideoTool(): void { this.server.tool( 'image_to_video', 'Generate a video based on an image.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { model: z .string() .optional() .default('I2V-01') .describe('Model to use, values: ["I2V-01", "I2V-01-Director", "I2V-01-live"]'), prompt: z.string().describe('Text prompt for video generation'), firstFrameImage: z.string().describe('Path to the first frame image'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, outputFile: z .string() .optional() .describe('Path to save the generated video file, automatically generated if not provided'), asyncMode: z .boolean() .optional() .default(false) .describe('Whether to use async mode. Defaults to False. If True, the video generation task will be submitted asynchronously and the response will return a task_id. Should use `query_video_generation` tool to check the status of the task and get the result.'), }, async (params) => { try { // If no output filename is provided, generate one automatically if (!params.outputFile) { const promptPrefix = params.prompt.substring(0, 20).replace(/[^\w]/g, '_'); params.outputFile = `i2v_${promptPrefix}_${Date.now()}`; } const result = await this.videoApi.generateVideo(params); if (params.asyncMode) { return { content: [ { type: 'text', text: `Success. Video generation task submitted: Task ID: ${result.task_id}. Please use \`query_video_generation\` tool to check the status of the task and get the result.`, }, ], }; } // Handle different output formats if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Video URL: ${result.video_url}`, }, ], }; } else { return { content: [ { type: 'text', text: `Video saved: ${result.video_path}`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to generate video: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); } /** * Register query video generation tool */ private registerQueryVideoGenerationTool(): void { this.server.tool( 'query_video_generation', 'Query the status of a video generation task.', { taskId: z .string() .describe('The Task ID to query. Should be the task_id returned by `generate_video` tool if `async_mode` is True.'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, }, async (params) => { try { // No need to update configuration from request parameters in stdio mode const result = await this.videoApi.queryVideoGeneration(params); if (result.status === 'Success') { if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Video URL: ${result.video_url}`, }, ], }; } else { return { content: [ { type: 'text', text: `Success. Video saved as: ${result.video_path}`, }, ], }; } } else { return { content: [ { type: 'text', text: `Video generation task is still processing: Task ID: ${params.taskId}.`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to query video generation: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register music generation tool */ private registerMusicGenerationTool(): void { this.server.tool( 'music_generation', 'Create a music generation task using AI models. Generate music from prompt and lyrics.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { prompt: z .string() .describe('Music creation inspiration describing style, mood, scene, etc.\nExample: "Pop music, sad, suitable for rainy nights". Character range: [10, 300]'), lyrics: z .string() .describe('Song lyrics for music generation.\nUse newline (\\n) to separate each line of lyrics. Supports lyric structure tags [Intro][Verse][Chorus][Bridge][Outro]\nto enhance musicality. Character range: [10, 600] (each Chinese character, punctuation, and letter counts as 1 character)'), sampleRate: z .number() .optional() .default(DEFAULT_SAMPLE_RATE) .describe('Sample rate of generated music. Values: [16000, 24000, 32000, 44100]'), bitrate: z .number() .optional() .default(DEFAULT_BITRATE) .describe('Bitrate of generated music. Values: [32000, 64000, 128000, 256000]'), format: z .string() .optional() .default(DEFAULT_FORMAT) .describe('Format of generated music. Values: ["mp3", "wav", "pcm"]'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, }, async (params) => { try { // Automatically set resource mode (if not specified) const outputFormat = this.config.resourceMode; const musicRequest = { ...params, outputFormat, }; // No need to update configuration from request parameters in stdio mode const outputFile = await this.musicApi.generateMusic(musicRequest); // Handle different output formats if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Music URL: ${outputFile}`, }, ], }; } else { return { content: [ { type: 'text', text: `Success. Music saved as: ${outputFile}`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to generate music: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Register voice design tool */ private registerVoiceDesignTool(): void { this.server.tool( 'voice_design', 'Generate a voice based on description prompts.\n\nNote: This tool calls MiniMax API and may incur costs. Use only when explicitly requested by the user.', { prompt: z .string() .describe('The prompt to generate the voice from'), previewText: z .string() .describe('The text to preview the voice'), voiceId: z .string() .optional() .describe('The id of the voice to use. For example, "male-qn-qingse"/"audiobook_female_1"/"cute_boy"/"Charming_Lady"...'), outputDirectory: COMMON_PARAMETERS_SCHEMA.outputDirectory, }, async (params) => { try { // No need to update configuration from request parameters in stdio mode const { voiceId, outputFile } = await this.voiceDesignApi.voiceDesign(params); // Handle different output formats if (this.config.resourceMode === RESOURCE_MODE_URL) { return { content: [ { type: 'text', text: `Success. Voice ID: ${voiceId}. Voice URL: ${outputFile}`, }, ], }; } else { return { content: [ { type: 'text', text: `Success. Voice ID: ${voiceId}. Voice saved as: ${outputFile}`, }, ], }; } } catch (error) { return { content: [ { type: 'text', text: `Failed to design voice: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, ); } /** * Update configuration and recreate API instances * @param newConfig New configuration object */ public updateConfig(newConfig: Partial<Config>): void { // Merge server configuration if (newConfig.server && this.config.server) { // New configuration has higher priority and should override existing configuration this.config.server = { ...this.config.server, // Lower priority configuration loaded first ...newConfig.server // Higher priority configuration loaded last }; delete newConfig.server; } else if (newConfig.server) { this.config.server = newConfig.server; delete newConfig.server; } // Merge other configurations, new configuration has higher priority this.config = { ...this.config, // Lower priority configuration loaded first ...newConfig // Higher priority configuration loaded last }; // Update API instances this.api = new MiniMaxAPI(this.config); this.ttsApi = new TTSAPI(this.api); this.imageApi = new ImageAPI(this.api); this.videoApi = new VideoAPI(this.api); this.voiceCloneApi = new VoiceCloneAPI(this.api); this.voiceApi = new VoiceAPI(this.api); this.voiceDesignApi = new VoiceDesignAPI(this.api); this.musicApi = new MusicAPI(this.api); } /** * Read configuration from file * @returns Partial configuration object or undefined */ private getConfigFromFile(): Partial<Config> | undefined { try { // Prioritize configuration file path parameter const configPath = getParamValue("config_path") || process.env[ENV_CONFIG_PATH] || './minimax-config.json'; // Check if file exists if (!fs.existsSync(configPath)) { return undefined; } // Read and parse configuration file const fileContent = fs.readFileSync(configPath, 'utf8'); return JSON.parse(fileContent) as Partial<Config>; } catch (error) { // console.warn(`Failed to read config file: ${error instanceof Error ? error.message : String(error)}`); return undefined; } } /** * Start the server * @returns Promise to start the server */ public async start(): Promise<void> { try { // Validate necessary configuration if (!this.config.apiKey) { throw new Error(ERROR_API_KEY_REQUIRED); } if (!this.config.apiHost) { throw new Error(ERROR_API_HOST_REQUIRED); } // Start STDIO server return this.startStdioServer(); } catch (error) { // console.error(`Failed to start server: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Start standard input/output server */ public async startStdioServer(): Promise<void> { // console.log('Starting stdio server'); const transport = new StdioServerTransport(); await this.server.connect(transport); // console.log('MiniMax MCP Server running on stdio'); } /** * Get server instance * @returns McpServer instance */ public getServer(): McpServer { return this.server; } /** * Get current configuration * @returns Current configuration */ public getConfig(): Config { return this.config; } } // Export types and API instances for use in other projects export { Config, TTSRequest, ImageGenerationRequest, VideoGenerationRequest, VoiceCloneRequest, ListVoicesRequest, PlayAudioRequest, ServerOptions, TransportMode, } from './types/index.js'; export { MiniMaxAPI } from './utils/api.js'; export { TTSAPI } from './api/tts.js'; export { ImageAPI } from './api/image.js'; export { VideoAPI } from './api/video.js'; export { VoiceCloneAPI } from './api/voice-clone.js'; export { VoiceAPI } from './api/voice.js'; export * from './exceptions/index.js'; export * from './const/index.js';

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/MiniMax-AI/MiniMax-MCP-JS'

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