@felores/kie-ai-mcp-server 1.7.3 → 1.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -709,7 +709,125 @@ Vertical video for social media:
709
709
 
710
710
  **Note**: The `callBackUrl` is optional and will use the `KIE_AI_CALLBACK_URL` environment variable if not provided. Video-to-video transformation typically takes 3-8 minutes depending on complexity and length.
711
711
 
712
- ### 14. `wan_video`
712
+ ### 16. `midjourney_generate`
713
+ Generate images and videos using Midjourney AI models (unified tool for text-to-image, image-to-image, style reference, omni reference, and video generation).
714
+
715
+ **Parameters:**
716
+ - `prompt` (string, required): Text prompt describing the desired image or video (max 2000 chars)
717
+ - `taskType` (string, optional): Task type for generation mode (auto-detected if not provided)
718
+ - Options: `mj_txt2img`, `mj_img2img`, `mj_style_reference`, `mj_omni_reference`, `mj_video`, `mj_video_hd`
719
+ - `fileUrl` (string, optional): Single image URL for image-to-image or video generation (legacy - use fileUrls instead)
720
+ - `fileUrls` (array, optional): Array of image URLs for image-to-image or video generation (recommended, max 10)
721
+ - `speed` (string, optional): Generation speed (not required for video/omni tasks)
722
+ - Options: `relaxed`, `fast`, `turbo`
723
+ - `aspectRatio` (string, optional): Output aspect ratio (default: "16:9")
724
+ - Options: `1:2`, `9:16`, `2:3`, `3:4`, `5:6`, `6:5`, `4:3`, `3:2`, `1:1`, `16:9`, `2:1`
725
+ - `version` (string, optional): Midjourney model version (default: "7")
726
+ - Options: `7`, `6.1`, `6`, `5.2`, `5.1`, `niji6`
727
+ - `variety` (integer, optional): Controls diversity of generated results (0-100, increment by 5)
728
+ - `stylization` (integer, optional): Artistic style intensity (0-1000, suggested multiple of 50)
729
+ - `weirdness` (integer, optional): Creativity and uniqueness level (0-3000, suggested multiple of 100)
730
+ - `ow` (integer, optional): Omni intensity parameter for omni reference tasks (1-1000)
731
+ - `waterMark` (string, optional): Watermark identifier (max 100 chars)
732
+ - `enableTranslation` (boolean, optional): Auto-translate non-English prompts to English (default: false)
733
+ - `videoBatchSize` (string, optional): Number of videos to generate (video mode only, default: "1")
734
+ - Options: `1`, `2`, `4`
735
+ - `motion` (string, optional): Motion level for video generation (required for video mode, default: "high")
736
+ - Options: `high`, `low`
737
+ - `high_definition_video` (boolean, optional): Use HD video generation instead of standard definition (default: false)
738
+ - `callBackUrl` (string, optional): URL for task completion notifications
739
+
740
+ **Examples:**
741
+
742
+ Text-to-image generation:
743
+ ```json
744
+ {
745
+ "prompt": "A majestic dragon perched atop a crystal mountain at sunset, digital art style",
746
+ "aspectRatio": "16:9",
747
+ "version": "7",
748
+ "speed": "fast",
749
+ "stylization": 500
750
+ }
751
+ ```
752
+
753
+ Image-to-image generation:
754
+ ```json
755
+ {
756
+ "prompt": "Transform this portrait into a cyberpunk style with neon lights",
757
+ "fileUrls": ["https://example.com/portrait.jpg"],
758
+ "aspectRatio": "1:1",
759
+ "version": "7",
760
+ "variety": 10
761
+ }
762
+ ```
763
+
764
+ Standard definition video generation (default):
765
+ ```json
766
+ {
767
+ "prompt": "Add gentle movement and atmospheric effects",
768
+ "fileUrls": ["https://example.com/landscape.jpg"],
769
+ "motion": "high",
770
+ "videoBatchSize": "1",
771
+ "aspectRatio": "16:9"
772
+ }
773
+ ```
774
+
775
+ High definition video generation (explicit):
776
+ ```json
777
+ {
778
+ "prompt": "Create cinematic video with dramatic motion",
779
+ "fileUrls": ["https://example.com/cityscape.jpg"],
780
+ "motion": "high",
781
+ "high_definition_video": true,
782
+ "videoBatchSize": "2",
783
+ "aspectRatio": "16:9"
784
+ }
785
+ ```
786
+
787
+ Omni reference generation:
788
+ ```json
789
+ {
790
+ "prompt": "Place this character in a fantasy forest setting",
791
+ "fileUrls": ["https://example.com/character.jpg"],
792
+ "ow": 500,
793
+ "aspectRatio": "16:9",
794
+ "version": "7"
795
+ }
796
+ ```
797
+
798
+ Style reference generation:
799
+ ```json
800
+ {
801
+ "prompt": "Apply this artistic style to a new landscape",
802
+ "fileUrls": ["https://example.com/artistic-style.jpg"],
803
+ "taskType": "mj_style_reference",
804
+ "aspectRatio": "16:9",
805
+ "stylization": 700
806
+ }
807
+ ```
808
+
809
+ **Key Features:**
810
+ - **Unified Interface**: Single tool for all Midjourney generation modes
811
+ - **Smart Mode Detection**: Automatically detects task type based on parameters
812
+ - **Video Default**: Uses standard definition video by default, HD only when explicitly requested
813
+ - **Multiple Aspect Ratios**: Support for vertical, horizontal, square, and ultra-wide formats
814
+ - **Style Control**: Fine-tune artistic style with stylization, variety, and weirdness parameters
815
+ - **Speed Options**: Choose generation speed based on urgency (relaxed/fast/turbo)
816
+ - **Model Versions**: Access different Midjourney models including niji for anime/illustration
817
+ - **Reference Modes**: Advanced omni and style reference for character and style transfer
818
+ - **Batch Generation**: Generate multiple videos in a single request
819
+
820
+ **Smart Detection Logic:**
821
+ - If `high_definition_video` is true → `mj_video_hd`
822
+ - If `motion` or `videoBatchSize` present → `mj_video` (standard) or `mj_video_hd` (explicit)
823
+ - If `ow` present → `mj_omni_reference`
824
+ - If `taskType` is `mj_style_reference` → `mj_style_reference`
825
+ - If `fileUrl`/`fileUrls` present → `mj_img2img`
826
+ - Otherwise → `mj_txt2img`
827
+
828
+ **Note**: The `callBackUrl` is optional and will use the `KIE_AI_CALLBACK_URL` environment variable if not provided. Generation times vary: text-to-image (1-3 minutes), image-to-image (2-4 minutes), video generation (3-8 minutes), reference modes (2-5 minutes).
829
+
830
+ ### 17. `wan_video`
713
831
  Generate videos using Alibaba Wan 2.5 models (unified tool for both text-to-video and image-to-video).
714
832
 
715
833
  **Parameters:**
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } f
5
5
  import { KieAiClient } from './kie-ai-client.js';
6
6
  import { TaskDatabase } from './database.js';
7
7
  import { z } from 'zod';
8
- import { NanoBananaGenerateSchema, NanoBananaEditSchema, NanoBananaUpscaleSchema, Veo3GenerateSchema, SunoGenerateSchema, ElevenLabsTTSSchema, ElevenLabsSoundEffectsSchema, ByteDanceSeedanceVideoSchema, ByteDanceSeedreamImageSchema, QwenImageSchema, RunwayAlephVideoSchema, WanVideoSchema } from './types.js';
8
+ import { NanoBananaGenerateSchema, NanoBananaEditSchema, NanoBananaUpscaleSchema, Veo3GenerateSchema, SunoGenerateSchema, ElevenLabsTTSSchema, ElevenLabsSoundEffectsSchema, ByteDanceSeedanceVideoSchema, ByteDanceSeedreamImageSchema, QwenImageSchema, RunwayAlephVideoSchema, WanVideoSchema, MidjourneyGenerateSchema } from './types.js';
9
9
  class KieAiMcpServer {
10
10
  server;
11
11
  client;
@@ -13,7 +13,7 @@ class KieAiMcpServer {
13
13
  constructor() {
14
14
  this.server = new Server({
15
15
  name: 'kie-ai-mcp-server',
16
- version: '1.7.3',
16
+ version: '1.7.4',
17
17
  });
18
18
  // Initialize client with config from environment
19
19
  const config = {
@@ -688,6 +688,114 @@ class KieAiMcpServer {
688
688
  required: ['prompt']
689
689
  }
690
690
  },
691
+ {
692
+ name: 'midjourney_generate',
693
+ description: 'Generate images and videos using Midjourney AI models (unified tool for text-to-image, image-to-image, style reference, omni reference, and video generation)',
694
+ inputSchema: {
695
+ type: 'object',
696
+ properties: {
697
+ prompt: {
698
+ type: 'string',
699
+ description: 'Text prompt describing the desired image or video (max 2000 characters)',
700
+ minLength: 1,
701
+ maxLength: 2000
702
+ },
703
+ taskType: {
704
+ type: 'string',
705
+ description: 'Task type for generation mode (auto-detected if not provided)',
706
+ enum: ['mj_txt2img', 'mj_img2img', 'mj_style_reference', 'mj_omni_reference', 'mj_video', 'mj_video_hd']
707
+ },
708
+ fileUrl: {
709
+ type: 'string',
710
+ description: 'Single image URL for image-to-image or video generation (legacy - use fileUrls instead)',
711
+ format: 'uri'
712
+ },
713
+ fileUrls: {
714
+ type: 'array',
715
+ description: 'Array of image URLs for image-to-image or video generation (recommended)',
716
+ items: {
717
+ type: 'string',
718
+ format: 'uri'
719
+ },
720
+ maxItems: 10
721
+ },
722
+ speed: {
723
+ type: 'string',
724
+ description: 'Generation speed (not required for video/omni tasks)',
725
+ enum: ['relaxed', 'fast', 'turbo']
726
+ },
727
+ aspectRatio: {
728
+ type: 'string',
729
+ description: 'Output aspect ratio',
730
+ enum: ['1:2', '9:16', '2:3', '3:4', '5:6', '6:5', '4:3', '3:2', '1:1', '16:9', '2:1'],
731
+ default: '16:9'
732
+ },
733
+ version: {
734
+ type: 'string',
735
+ description: 'Midjourney model version',
736
+ enum: ['7', '6.1', '6', '5.2', '5.1', 'niji6'],
737
+ default: '7'
738
+ },
739
+ variety: {
740
+ type: 'integer',
741
+ description: 'Controls diversity of generated results (0-100, increment by 5)',
742
+ minimum: 0,
743
+ maximum: 100
744
+ },
745
+ stylization: {
746
+ type: 'integer',
747
+ description: 'Artistic style intensity (0-1000, suggested multiple of 50)',
748
+ minimum: 0,
749
+ maximum: 1000
750
+ },
751
+ weirdness: {
752
+ type: 'integer',
753
+ description: 'Creativity and uniqueness level (0-3000, suggested multiple of 100)',
754
+ minimum: 0,
755
+ maximum: 3000
756
+ },
757
+ ow: {
758
+ type: 'integer',
759
+ description: 'Omni intensity parameter for omni reference tasks (1-1000)',
760
+ minimum: 1,
761
+ maximum: 1000
762
+ },
763
+ waterMark: {
764
+ type: 'string',
765
+ description: 'Watermark identifier',
766
+ maxLength: 100
767
+ },
768
+ enableTranslation: {
769
+ type: 'boolean',
770
+ description: 'Auto-translate non-English prompts to English',
771
+ default: false
772
+ },
773
+ videoBatchSize: {
774
+ type: 'string',
775
+ description: 'Number of videos to generate (video mode only)',
776
+ enum: ['1', '2', '4'],
777
+ default: '1'
778
+ },
779
+ motion: {
780
+ type: 'string',
781
+ description: 'Motion level for video generation (required for video mode)',
782
+ enum: ['high', 'low'],
783
+ default: 'high'
784
+ },
785
+ high_definition_video: {
786
+ type: 'boolean',
787
+ description: 'Use high definition video generation instead of standard definition',
788
+ default: false
789
+ },
790
+ callBackUrl: {
791
+ type: 'string',
792
+ description: 'Optional: URL for task completion notifications (uses KIE_AI_CALLBACK_URL env var if not provided)',
793
+ format: 'uri'
794
+ }
795
+ },
796
+ required: ['prompt']
797
+ }
798
+ },
691
799
  {
692
800
  name: 'runway_aleph_video',
693
801
  description: 'Transform videos using Runway Aleph video-to-video generation with AI-powered editing',
@@ -834,6 +942,8 @@ class KieAiMcpServer {
834
942
  return await this.handleByteDanceSeedreamImage(args);
835
943
  case 'qwen_image':
836
944
  return await this.handleQwenImage(args);
945
+ case 'midjourney_generate':
946
+ return await this.handleMidjourneyGenerate(args);
837
947
  case 'runway_aleph_video':
838
948
  return await this.handleRunwayAlephVideo(args);
839
949
  case 'wan_video':
@@ -1694,6 +1804,130 @@ class KieAiMcpServer {
1694
1804
  });
1695
1805
  }
1696
1806
  }
1807
+ async handleMidjourneyGenerate(args) {
1808
+ try {
1809
+ const request = MidjourneyGenerateSchema.parse(args);
1810
+ // Use environment variable as fallback if callBackUrl not provided
1811
+ if (!request.callBackUrl && process.env.KIE_AI_CALLBACK_URL) {
1812
+ request.callBackUrl = process.env.KIE_AI_CALLBACK_URL;
1813
+ }
1814
+ const response = await this.client.generateMidjourney(request);
1815
+ if (response.code === 200 && response.data?.taskId) {
1816
+ // Determine task type for user feedback
1817
+ const hasImage = request.fileUrl || (request.fileUrls && request.fileUrls.length > 0);
1818
+ const isVideoMode = request.motion || request.videoBatchSize || request.high_definition_video;
1819
+ const isOmniMode = request.ow || request.taskType === 'mj_omni_reference';
1820
+ const isStyleMode = request.taskType === 'mj_style_reference';
1821
+ let taskTypeDisplay = 'Text-to-Image';
1822
+ if (isOmniMode) {
1823
+ taskTypeDisplay = 'Omni Reference';
1824
+ }
1825
+ else if (isStyleMode) {
1826
+ taskTypeDisplay = 'Style Reference';
1827
+ }
1828
+ else if (isVideoMode) {
1829
+ taskTypeDisplay = request.high_definition_video ? 'Image-to-HD-Video' : 'Image-to-Video';
1830
+ }
1831
+ else if (hasImage) {
1832
+ taskTypeDisplay = 'Image-to-Image';
1833
+ }
1834
+ // Store task in database
1835
+ await this.db.createTask({
1836
+ task_id: response.data.taskId,
1837
+ api_type: 'midjourney',
1838
+ status: 'pending'
1839
+ });
1840
+ return {
1841
+ content: [
1842
+ {
1843
+ type: 'text',
1844
+ text: JSON.stringify({
1845
+ success: true,
1846
+ task_id: response.data.taskId,
1847
+ message: `Midjourney ${taskTypeDisplay} task created successfully`,
1848
+ parameters: {
1849
+ task_type: taskTypeDisplay,
1850
+ prompt: request.prompt.substring(0, 100) + (request.prompt.length > 100 ? '...' : ''),
1851
+ aspect_ratio: request.aspectRatio || '16:9',
1852
+ version: request.version || '7',
1853
+ speed: request.speed,
1854
+ variety: request.variety,
1855
+ stylization: request.stylization,
1856
+ weirdness: request.weirdness,
1857
+ enable_translation: request.enableTranslation || false,
1858
+ waterMark: request.waterMark,
1859
+ ...(hasImage && {
1860
+ file_urls: request.fileUrls || [request.fileUrl]
1861
+ }),
1862
+ ...(isVideoMode && {
1863
+ motion: request.motion || 'high',
1864
+ video_batch_size: request.videoBatchSize || '1',
1865
+ high_definition_video: request.high_definition_video || false
1866
+ }),
1867
+ ...(isOmniMode && {
1868
+ ow: request.ow
1869
+ })
1870
+ },
1871
+ next_steps: [
1872
+ `Use get_task_status with task_id: ${response.data.taskId} to check progress`,
1873
+ 'Generated content will be available when status is "completed"'
1874
+ ],
1875
+ usage_examples: [
1876
+ `get_task_status: {"task_id": "${response.data.taskId}"}`,
1877
+ `list_tasks: {"limit": 10}`
1878
+ ]
1879
+ }, null, 2)
1880
+ }
1881
+ ]
1882
+ };
1883
+ }
1884
+ else {
1885
+ throw new Error(response.msg || 'Failed to create Midjourney task');
1886
+ }
1887
+ }
1888
+ catch (error) {
1889
+ if (error instanceof z.ZodError) {
1890
+ return this.formatError('midjourney_generate', error, {
1891
+ prompt: 'Required: Text prompt describing the desired image (max 2000 chars)',
1892
+ taskType: 'Optional: Task type (mj_txt2img, mj_img2img, mj_style_reference, mj_omni_reference, mj_video, mj_video_hd) - auto-detected if not provided',
1893
+ fileUrl: 'Optional: Single image URL for image-to-image or video generation (legacy)',
1894
+ fileUrls: 'Optional: Array of image URLs for image-to-image or video generation (recommended)',
1895
+ speed: 'Optional: Generation speed (relaxed/fast/turbo) - not required for video/omni tasks',
1896
+ aspectRatio: 'Optional: Output aspect ratio (1:2, 9:16, 2:3, 3:4, 5:6, 6:5, 4:3, 3:2, 1:1, 16:9, 2:1, default: 16:9)',
1897
+ version: 'Optional: Midjourney model version (7, 6.1, 6, 5.2, 5.1, niji6, default: 7)',
1898
+ variety: 'Optional: Diversity control (0-100, increment by 5)',
1899
+ stylization: 'Optional: Artistic style intensity (0-1000, suggested multiple of 50)',
1900
+ weirdness: 'Optional: Creativity level (0-3000, suggested multiple of 100)',
1901
+ ow: 'Optional: Omni intensity for omni reference tasks (1-1000)',
1902
+ waterMark: 'Optional: Watermark identifier (max 100 chars)',
1903
+ enableTranslation: 'Optional: Auto-translate non-English prompts (default: false)',
1904
+ videoBatchSize: 'Optional: Number of videos to generate (1/2/4, default: 1, video mode only)',
1905
+ motion: 'Optional: Video motion level (high/low, default: high, required for video)',
1906
+ high_definition_video: 'Optional: Use HD video generation (default: false, uses standard definition)',
1907
+ callBackUrl: 'Optional: URL for task completion notifications (uses KIE_AI_CALLBACK_URL env var if not provided)'
1908
+ });
1909
+ }
1910
+ return this.formatError('midjourney_generate', error, {
1911
+ prompt: 'Required: Text prompt describing the desired image (max 2000 chars)',
1912
+ taskType: 'Optional: Task type (mj_txt2img, mj_img2img, mj_style_reference, mj_omni_reference, mj_video, mj_video_hd) - auto-detected if not provided',
1913
+ fileUrl: 'Optional: Single image URL for image-to-image or video generation (legacy)',
1914
+ fileUrls: 'Optional: Array of image URLs for image-to-image or video generation (recommended)',
1915
+ speed: 'Optional: Generation speed (relaxed/fast/turbo) - not required for video/omni tasks',
1916
+ aspectRatio: 'Optional: Output aspect ratio (1:2, 9:16, 2:3, 3:4, 5:6, 6:5, 4:3, 3:2, 1:1, 16:9, 2:1, default: 16:9)',
1917
+ version: 'Optional: Midjourney model version (7, 6.1, 6, 5.2, 5.1, niji6, default: 7)',
1918
+ variety: 'Optional: Diversity control (0-100, increment by 5)',
1919
+ stylization: 'Optional: Artistic style intensity (0-1000, suggested multiple of 50)',
1920
+ weirdness: 'Optional: Creativity level (0-3000, suggested multiple of 100)',
1921
+ ow: 'Optional: Omni intensity for omni reference tasks (1-1000)',
1922
+ waterMark: 'Optional: Watermark identifier (max 100 chars)',
1923
+ enableTranslation: 'Optional: Auto-translate non-English prompts (default: false)',
1924
+ videoBatchSize: 'Optional: Number of videos to generate (1/2/4, default: 1, video mode only)',
1925
+ motion: 'Optional: Video motion level (high/low, default: high, required for video)',
1926
+ high_definition_video: 'Optional: Use HD video generation (default: false, uses standard definition)',
1927
+ callBackUrl: 'Optional: URL for task completion notifications (uses KIE_AI_CALLBACK_URL env var if not provided)'
1928
+ });
1929
+ }
1930
+ }
1697
1931
  async handleRunwayAlephVideo(args) {
1698
1932
  try {
1699
1933
  const request = RunwayAlephVideoSchema.parse(args);
@@ -1,4 +1,4 @@
1
- import { KieAiConfig, KieAiResponse, NanoBananaGenerateRequest, NanaBananaEditRequest, NanoBananaUpscaleRequest, Veo3GenerateRequest, SunoGenerateRequest, ElevenLabsTTSRequest, ElevenLabsSoundEffectsRequest, ByteDanceSeedanceVideoRequest, RunwayAlephVideoRequest, WanVideoRequest, ByteDanceSeedreamImageRequest, QwenImageRequest, ImageResponse, TaskResponse } from './types.js';
1
+ import { KieAiConfig, KieAiResponse, NanoBananaGenerateRequest, NanaBananaEditRequest, NanoBananaUpscaleRequest, Veo3GenerateRequest, SunoGenerateRequest, ElevenLabsTTSRequest, ElevenLabsSoundEffectsRequest, ByteDanceSeedanceVideoRequest, RunwayAlephVideoRequest, WanVideoRequest, ByteDanceSeedreamImageRequest, QwenImageRequest, MidjourneyGenerateRequest, ImageResponse, TaskResponse } from './types.js';
2
2
  export declare class KieAiClient {
3
3
  private config;
4
4
  constructor(config: KieAiConfig);
@@ -16,5 +16,6 @@ export declare class KieAiClient {
16
16
  generateWanVideo(request: WanVideoRequest): Promise<KieAiResponse<TaskResponse>>;
17
17
  generateByteDanceSeedreamImage(request: ByteDanceSeedreamImageRequest): Promise<KieAiResponse<TaskResponse>>;
18
18
  generateQwenImage(request: QwenImageRequest): Promise<KieAiResponse<TaskResponse>>;
19
+ generateMidjourney(request: MidjourneyGenerateRequest): Promise<KieAiResponse<TaskResponse>>;
19
20
  getVeo1080pVideo(taskId: string, index?: number): Promise<KieAiResponse<any>>;
20
21
  }
@@ -86,7 +86,10 @@ export class KieAiClient {
86
86
  else if (apiType === 'runway-aleph-video') {
87
87
  return this.makeRequest(`/api/v1/aleph/record-info?taskId=${taskId}`, 'GET');
88
88
  }
89
- // Fallback: try jobs first, then veo, then generate (for tasks not in database)
89
+ else if (apiType === 'midjourney') {
90
+ return this.makeRequest(`/mj/record-info?taskId=${taskId}`, 'GET');
91
+ }
92
+ // Fallback: try jobs first, then veo, then generate, then mj (for tasks not in database)
90
93
  try {
91
94
  return await this.makeRequest(`/jobs/recordInfo?taskId=${taskId}`, 'GET');
92
95
  }
@@ -99,7 +102,12 @@ export class KieAiClient {
99
102
  return await this.makeRequest(`/generate/record-info?taskId=${taskId}`, 'GET');
100
103
  }
101
104
  catch (sunoError) {
102
- throw error;
105
+ try {
106
+ return await this.makeRequest(`/mj/record-info?taskId=${taskId}`, 'GET');
107
+ }
108
+ catch (mjError) {
109
+ throw error;
110
+ }
103
111
  }
104
112
  }
105
113
  }
@@ -286,6 +294,75 @@ export class KieAiClient {
286
294
  };
287
295
  return this.makeRequest('/jobs/createTask', 'POST', jobRequest);
288
296
  }
297
+ async generateMidjourney(request) {
298
+ // Smart task type detection
299
+ let taskType = request.taskType;
300
+ const hasImage = request.fileUrl || (request.fileUrls && request.fileUrls.length > 0);
301
+ const isVideoMode = request.motion || request.videoBatchSize || request.high_definition_video;
302
+ const isOmniMode = request.ow || request.taskType === 'mj_omni_reference';
303
+ const isStyleMode = request.taskType === 'mj_style_reference';
304
+ // Auto-detect task type if not provided
305
+ if (!taskType) {
306
+ if (isOmniMode) {
307
+ taskType = 'mj_omni_reference';
308
+ }
309
+ else if (isStyleMode) {
310
+ taskType = 'mj_style_reference';
311
+ }
312
+ else if (isVideoMode) {
313
+ taskType = request.high_definition_video ? 'mj_video_hd' : 'mj_video';
314
+ }
315
+ else if (hasImage) {
316
+ taskType = 'mj_img2img';
317
+ }
318
+ else {
319
+ taskType = 'mj_txt2img';
320
+ }
321
+ }
322
+ // Build request payload
323
+ const payload = {
324
+ taskType,
325
+ prompt: request.prompt,
326
+ aspectRatio: request.aspectRatio || '16:9',
327
+ version: request.version || '7',
328
+ enableTranslation: request.enableTranslation || false,
329
+ callBackUrl: request.callBackUrl || process.env.KIE_AI_CALLBACK_URL
330
+ };
331
+ // Add image URLs (prefer fileUrls array over fileUrl)
332
+ if (request.fileUrls && request.fileUrls.length > 0) {
333
+ payload.fileUrls = request.fileUrls;
334
+ }
335
+ else if (request.fileUrl) {
336
+ payload.fileUrls = [request.fileUrl];
337
+ }
338
+ // Add optional parameters based on task type
339
+ if (request.speed && !['mj_video', 'mj_video_hd', 'mj_omni_reference'].includes(taskType)) {
340
+ payload.speed = request.speed;
341
+ }
342
+ if (request.variety !== undefined) {
343
+ payload.variety = request.variety;
344
+ }
345
+ if (request.stylization !== undefined) {
346
+ payload.stylization = request.stylization;
347
+ }
348
+ if (request.weirdness !== undefined) {
349
+ payload.weirdness = request.weirdness;
350
+ }
351
+ if (request.waterMark !== undefined) {
352
+ payload.waterMark = request.waterMark;
353
+ }
354
+ // Task-specific parameters
355
+ if (taskType === 'mj_omni_reference' && request.ow) {
356
+ payload.ow = request.ow;
357
+ }
358
+ if ((taskType === 'mj_video' || taskType === 'mj_video_hd')) {
359
+ payload.motion = request.motion || 'high';
360
+ if (request.videoBatchSize) {
361
+ payload.videoBatchSize = parseInt(request.videoBatchSize.toString());
362
+ }
363
+ }
364
+ return this.makeRequest('/mj/generate', 'POST', payload);
365
+ }
289
366
  async getVeo1080pVideo(taskId, index) {
290
367
  const params = new URLSearchParams({ taskId });
291
368
  if (index !== undefined) {
package/dist/types.d.ts CHANGED
@@ -542,6 +542,133 @@ export declare const QwenImageSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
542
542
  num_images?: "1" | "2" | "3" | "4" | undefined;
543
543
  sync_mode?: boolean | undefined;
544
544
  }>;
545
+ export declare const MidjourneyGenerateSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
546
+ prompt: z.ZodString;
547
+ taskType: z.ZodOptional<z.ZodEnum<["mj_txt2img", "mj_img2img", "mj_style_reference", "mj_omni_reference", "mj_video", "mj_video_hd"]>>;
548
+ fileUrl: z.ZodOptional<z.ZodString>;
549
+ fileUrls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
550
+ speed: z.ZodOptional<z.ZodEnum<["relaxed", "fast", "turbo"]>>;
551
+ aspectRatio: z.ZodOptional<z.ZodDefault<z.ZodEnum<["1:2", "9:16", "2:3", "3:4", "5:6", "6:5", "4:3", "3:2", "1:1", "16:9", "2:1"]>>>;
552
+ version: z.ZodOptional<z.ZodDefault<z.ZodEnum<["7", "6.1", "6", "5.2", "5.1", "niji6"]>>>;
553
+ variety: z.ZodOptional<z.ZodNumber>;
554
+ stylization: z.ZodOptional<z.ZodNumber>;
555
+ weirdness: z.ZodOptional<z.ZodNumber>;
556
+ ow: z.ZodOptional<z.ZodNumber>;
557
+ waterMark: z.ZodOptional<z.ZodString>;
558
+ enableTranslation: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
559
+ callBackUrl: z.ZodOptional<z.ZodString>;
560
+ videoBatchSize: z.ZodOptional<z.ZodDefault<z.ZodEnum<["1", "2", "4"]>>>;
561
+ motion: z.ZodOptional<z.ZodDefault<z.ZodEnum<["high", "low"]>>>;
562
+ high_definition_video: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
563
+ }, "strip", z.ZodTypeAny, {
564
+ prompt: string;
565
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
566
+ callBackUrl?: string | undefined;
567
+ enableTranslation?: boolean | undefined;
568
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
569
+ waterMark?: string | undefined;
570
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
571
+ fileUrl?: string | undefined;
572
+ fileUrls?: string[] | undefined;
573
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
574
+ variety?: number | undefined;
575
+ stylization?: number | undefined;
576
+ weirdness?: number | undefined;
577
+ ow?: number | undefined;
578
+ videoBatchSize?: "1" | "2" | "4" | undefined;
579
+ motion?: "high" | "low" | undefined;
580
+ high_definition_video?: boolean | undefined;
581
+ }, {
582
+ prompt: string;
583
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
584
+ callBackUrl?: string | undefined;
585
+ enableTranslation?: boolean | undefined;
586
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
587
+ waterMark?: string | undefined;
588
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
589
+ fileUrl?: string | undefined;
590
+ fileUrls?: string[] | undefined;
591
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
592
+ variety?: number | undefined;
593
+ stylization?: number | undefined;
594
+ weirdness?: number | undefined;
595
+ ow?: number | undefined;
596
+ videoBatchSize?: "1" | "2" | "4" | undefined;
597
+ motion?: "high" | "low" | undefined;
598
+ high_definition_video?: boolean | undefined;
599
+ }>, {
600
+ prompt: string;
601
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
602
+ callBackUrl?: string | undefined;
603
+ enableTranslation?: boolean | undefined;
604
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
605
+ waterMark?: string | undefined;
606
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
607
+ fileUrl?: string | undefined;
608
+ fileUrls?: string[] | undefined;
609
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
610
+ variety?: number | undefined;
611
+ stylization?: number | undefined;
612
+ weirdness?: number | undefined;
613
+ ow?: number | undefined;
614
+ videoBatchSize?: "1" | "2" | "4" | undefined;
615
+ motion?: "high" | "low" | undefined;
616
+ high_definition_video?: boolean | undefined;
617
+ }, {
618
+ prompt: string;
619
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
620
+ callBackUrl?: string | undefined;
621
+ enableTranslation?: boolean | undefined;
622
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
623
+ waterMark?: string | undefined;
624
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
625
+ fileUrl?: string | undefined;
626
+ fileUrls?: string[] | undefined;
627
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
628
+ variety?: number | undefined;
629
+ stylization?: number | undefined;
630
+ weirdness?: number | undefined;
631
+ ow?: number | undefined;
632
+ videoBatchSize?: "1" | "2" | "4" | undefined;
633
+ motion?: "high" | "low" | undefined;
634
+ high_definition_video?: boolean | undefined;
635
+ }>, {
636
+ prompt: string;
637
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
638
+ callBackUrl?: string | undefined;
639
+ enableTranslation?: boolean | undefined;
640
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
641
+ waterMark?: string | undefined;
642
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
643
+ fileUrl?: string | undefined;
644
+ fileUrls?: string[] | undefined;
645
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
646
+ variety?: number | undefined;
647
+ stylization?: number | undefined;
648
+ weirdness?: number | undefined;
649
+ ow?: number | undefined;
650
+ videoBatchSize?: "1" | "2" | "4" | undefined;
651
+ motion?: "high" | "low" | undefined;
652
+ high_definition_video?: boolean | undefined;
653
+ }, {
654
+ prompt: string;
655
+ aspectRatio?: "1:1" | "9:16" | "16:9" | "3:4" | "4:3" | "3:2" | "2:3" | "1:2" | "5:6" | "6:5" | "2:1" | undefined;
656
+ callBackUrl?: string | undefined;
657
+ enableTranslation?: boolean | undefined;
658
+ speed?: "turbo" | "relaxed" | "fast" | undefined;
659
+ waterMark?: string | undefined;
660
+ taskType?: "mj_txt2img" | "mj_img2img" | "mj_style_reference" | "mj_omni_reference" | "mj_video" | "mj_video_hd" | undefined;
661
+ fileUrl?: string | undefined;
662
+ fileUrls?: string[] | undefined;
663
+ version?: "6" | "7" | "6.1" | "5.2" | "5.1" | "niji6" | undefined;
664
+ variety?: number | undefined;
665
+ stylization?: number | undefined;
666
+ weirdness?: number | undefined;
667
+ ow?: number | undefined;
668
+ videoBatchSize?: "1" | "2" | "4" | undefined;
669
+ motion?: "high" | "low" | undefined;
670
+ high_definition_video?: boolean | undefined;
671
+ }>;
545
672
  export type NanoBananaGenerateRequest = z.infer<typeof NanoBananaGenerateSchema>;
546
673
  export type NanaBananaEditRequest = z.infer<typeof NanoBananaEditSchema>;
547
674
  export type NanoBananaUpscaleRequest = z.infer<typeof NanoBananaUpscaleSchema>;
@@ -554,6 +681,7 @@ export type RunwayAlephVideoRequest = z.infer<typeof RunwayAlephVideoSchema>;
554
681
  export type WanVideoRequest = z.infer<typeof WanVideoSchema>;
555
682
  export type ByteDanceSeedreamImageRequest = z.infer<typeof ByteDanceSeedreamImageSchema>;
556
683
  export type QwenImageRequest = z.infer<typeof QwenImageSchema>;
684
+ export type MidjourneyGenerateRequest = z.infer<typeof MidjourneyGenerateSchema>;
557
685
  export interface KieAiResponse<T = any> {
558
686
  code: number;
559
687
  msg: string;
@@ -569,7 +697,7 @@ export interface TaskResponse {
569
697
  export interface TaskRecord {
570
698
  id?: number;
571
699
  task_id: string;
572
- api_type: 'nano-banana' | 'nano-banana-edit' | 'nano-banana-upscale' | 'veo3' | 'suno' | 'elevenlabs-tts' | 'elevenlabs-sound-effects' | 'bytedance-seedance-video' | 'runway-aleph-video' | 'wan-video' | 'bytedance-seedream-image' | 'qwen-image';
700
+ api_type: 'nano-banana' | 'nano-banana-edit' | 'nano-banana-upscale' | 'veo3' | 'suno' | 'elevenlabs-tts' | 'elevenlabs-sound-effects' | 'bytedance-seedance-video' | 'runway-aleph-video' | 'wan-video' | 'bytedance-seedream-image' | 'qwen-image' | 'midjourney';
573
701
  status: 'pending' | 'processing' | 'completed' | 'failed';
574
702
  created_at: string;
575
703
  updated_at: string;
package/dist/types.js CHANGED
@@ -253,3 +253,71 @@ export const QwenImageSchema = z.object({
253
253
  message: "Invalid parameters for detected mode",
254
254
  path: []
255
255
  });
256
+ export const MidjourneyGenerateSchema = z.object({
257
+ prompt: z.string().min(1).max(2000),
258
+ taskType: z.enum([
259
+ 'mj_txt2img', 'mj_img2img', 'mj_style_reference', 'mj_omni_reference',
260
+ 'mj_video', 'mj_video_hd'
261
+ ]).optional(), // Auto-detected if not provided
262
+ fileUrl: z.string().url().optional(), // Single image URL (legacy)
263
+ fileUrls: z.array(z.string().url()).max(10).optional(), // Array of image URLs (recommended)
264
+ speed: z.enum(['relaxed', 'fast', 'turbo']).optional(), // Not required for video/omni tasks
265
+ aspectRatio: z.enum([
266
+ '1:2', '9:16', '2:3', '3:4', '5:6', '6:5', '4:3', '3:2', '1:1', '16:9', '2:1'
267
+ ]).default('16:9').optional(),
268
+ version: z.enum(['7', '6.1', '6', '5.2', '5.1', 'niji6']).default('7').optional(),
269
+ variety: z.number().int().min(0).max(100).optional(), // Increment by 5
270
+ stylization: z.number().int().min(0).max(1000).optional(), // Suggested multiple of 50
271
+ weirdness: z.number().int().min(0).max(3000).optional(), // Suggested multiple of 100
272
+ ow: z.number().int().min(1).max(1000).optional(), // Omni intensity (only for mj_omni_reference)
273
+ waterMark: z.string().max(100).optional(),
274
+ enableTranslation: z.boolean().default(false).optional(),
275
+ callBackUrl: z.string().url().optional(),
276
+ // Video-specific parameters
277
+ videoBatchSize: z.enum(['1', '2', '4']).default('1').optional(), // Only for mj_video/mj_video_hd
278
+ motion: z.enum(['high', 'low']).default('high').optional(), // Required for video generation
279
+ high_definition_video: z.boolean().default(false).optional() // If true, use mj_video_hd instead of mj_video
280
+ }).refine((data) => {
281
+ // Check if callBackUrl is provided directly or via environment variable
282
+ const hasCallBackUrl = data.callBackUrl || process.env.KIE_AI_CALLBACK_URL;
283
+ if (!hasCallBackUrl) {
284
+ return false;
285
+ }
286
+ return true;
287
+ }, {
288
+ message: "callBackUrl is required (either directly or via KIE_AI_CALLBACK_URL environment variable)",
289
+ path: ["callBackUrl"]
290
+ }).refine((data) => {
291
+ // Auto-detect and validate task type based on parameters
292
+ const hasImage = data.fileUrl || (data.fileUrls && data.fileUrls.length > 0);
293
+ const isVideoMode = data.motion || data.videoBatchSize || data.high_definition_video;
294
+ const isOmniMode = data.taskType === 'mj_omni_reference' || data.ow;
295
+ const isStyleMode = data.taskType === 'mj_style_reference';
296
+ // If taskType is explicitly provided, validate it
297
+ if (data.taskType) {
298
+ // Video tasks require motion parameter
299
+ if ((data.taskType === 'mj_video' || data.taskType === 'mj_video_hd') && !data.motion) {
300
+ return false;
301
+ }
302
+ // Omni tasks require ow parameter
303
+ if (data.taskType === 'mj_omni_reference' && !data.ow) {
304
+ return false;
305
+ }
306
+ // Image tasks require image URL
307
+ if ((data.taskType === 'mj_img2img' || data.taskType === 'mj_style_reference' || data.taskType === 'mj_omni_reference') && !hasImage) {
308
+ return false;
309
+ }
310
+ // Video tasks require image URL
311
+ if ((data.taskType === 'mj_video' || data.taskType === 'mj_video_hd') && !hasImage) {
312
+ return false;
313
+ }
314
+ // Text-to-image should not have image URL
315
+ if (data.taskType === 'mj_txt2img' && hasImage) {
316
+ return false;
317
+ }
318
+ }
319
+ return true;
320
+ }, {
321
+ message: "Invalid combination of parameters for the detected task type",
322
+ path: []
323
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@felores/kie-ai-mcp-server",
3
- "version": "1.7.3",
4
- "description": "MCP server for Kie.ai APIs (Nano Banana image generation/editing, ByteDance Seedream V4 image generation/editing, Veo3 video generation, Suno music generation, and ElevenLabs text-to-speech)",
3
+ "version": "1.7.4",
4
+ "description": "MCP server for Kie.ai APIs (Nano Banana image generation/editing, ByteDance Seedream V4 image generation/editing, Veo3 video generation, Suno music generation, ElevenLabs text-to-speech, and Midjourney AI generation)",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "kie-ai-mcp-server": "dist/index.js"