beplus-mcp 0.8.1 → 0.10.0

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.
Files changed (2) hide show
  1. package/dist/index.js +104 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -424,11 +424,13 @@ async function buildImageBlocks(urls, cfg) {
424
424
  var IMAGE_MODELS = [
425
425
  "google/nano-banana-2",
426
426
  "google/nano-banana-pro",
427
- "openai/gpt-image-2"
427
+ "openai/gpt-image-2",
428
+ "midjourney"
428
429
  ];
429
430
  var VIDEO_MODELS = [
430
431
  "bytedance/seedance-2.0",
431
432
  "bytedance/seedance-2.0-fast",
433
+ "bytedance/seedance-2.0-mini",
432
434
  "kwaivgi/kling-v2.5-turbo-pro",
433
435
  "kwaivgi/kling-v2.6",
434
436
  "kwaivgi/kling-v2.6-motion-control",
@@ -518,13 +520,34 @@ function registerGenerationTools(server, client, cfg) {
518
520
  output_format: z.enum(["png", "jpeg", "webp"]).optional().describe("Formato de sa\xEDda (gpt-image-2). Padr\xE3o png."),
519
521
  output_compression: z.number().int().min(0).max(100).optional().describe("Compress\xE3o 0-100 (gpt-image-2, s\xF3 jpeg/webp). Padr\xE3o 90."),
520
522
  seed: z.number().int().optional(),
523
+ // ── Midjourney (model="midjourney") — params completos ──
524
+ version: z.enum(["8.1", "7", "6.1", "6", "niji-7", "niji-6"]).optional().describe("Midjourney: vers\xE3o (padr\xE3o 8.1). --oref (character_reference) for\xE7a V7; --cref for\xE7a V6; anime = niji-7."),
525
+ style_raw: z.boolean().optional().describe('Midjourney: --style raw (menos "opinativo").'),
526
+ stylize: z.number().int().min(0).max(1e3).optional().describe("Midjourney: --stylize 0-1000 (for\xE7a est\xE9tica). Padr\xE3o 100."),
527
+ chaos: z.number().int().min(0).max(100).optional().describe("Midjourney: --chaos 0-100 (variedade das 4)."),
528
+ weird: z.number().int().min(0).max(3e3).optional().describe("Midjourney: --weird 0-3000 (estranheza)."),
529
+ exp: z.number().int().min(0).max(100).optional().describe("Midjourney: --exp 0-100 (est\xE9tica experimental, s\xF3 V7/V8.1). Recomendado 5-50."),
530
+ mj_quality: z.enum(["1", "2", "4"]).optional().describe("Midjourney: --quality (s\xF3 V7=1/2/4 e V6; V8.1 ignora). Padr\xE3o 1."),
531
+ tile: z.boolean().optional().describe("Midjourney: --tile (padr\xE3o repet\xEDvel)."),
532
+ negative_prompt: z.string().max(2e3).optional().describe("Midjourney: --no (o que evitar)."),
533
+ style_reference: z.string().optional().describe("Midjourney: --sref (URL/arquivo OU c\xF3digo de estilo) para refer\xEAncia de ESTILO."),
534
+ style_weight: z.number().int().min(0).max(1e3).optional().describe("Midjourney: --sw peso do style ref. Padr\xE3o 100."),
535
+ character_reference: z.string().optional().describe("Midjourney: refer\xEAncia de PERSONAGEM (URL/arquivo). v7 usa --oref, v6 usa --cref (autom\xE1tico)."),
536
+ character_weight: z.number().int().min(0).max(1e3).optional().describe("Midjourney: peso do character ref (--ow v7 / --cw v6)."),
537
+ image_weight: z.number().min(0).max(3).optional().describe("Midjourney: --iw peso das reference_images (image-prompts) 0-3. Padr\xE3o 1."),
521
538
  project: z.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.')
522
539
  }
523
540
  },
524
541
  async (args) => {
525
542
  try {
526
543
  const isGoogle = args.model.startsWith("google/");
544
+ const isMidjourney = args.model === "midjourney";
527
545
  const reference_images = await resolveRefs(cfg, args.reference_images);
546
+ let style_reference;
547
+ if (isMidjourney && args.style_reference) {
548
+ style_reference = /^\d+$/.test(args.style_reference.trim()) ? args.style_reference : (await resolveRefs(cfg, [args.style_reference]))?.[0];
549
+ }
550
+ const character_reference = isMidjourney && args.character_reference ? (await resolveRefs(cfg, [args.character_reference]))?.[0] : void 0;
528
551
  const input = compact({
529
552
  prompt: args.prompt,
530
553
  aspect_ratio: args.aspect_ratio ?? (isGoogle ? DEFAULTS.imageAspect : void 0),
@@ -533,12 +556,26 @@ function registerGenerationTools(server, client, cfg) {
533
556
  google_search: args.google_search,
534
557
  image_search: args.image_search,
535
558
  size: args.size,
536
- quality: args.quality,
559
+ quality: isMidjourney ? args.mj_quality : args.quality,
537
560
  background: args.background,
538
561
  moderation: args.moderation,
539
562
  output_format: args.output_format,
540
563
  output_compression: args.output_compression,
541
- seed: args.seed
564
+ seed: args.seed,
565
+ // Midjourney full-params
566
+ version: args.version,
567
+ style_raw: args.style_raw,
568
+ stylize: args.stylize,
569
+ chaos: args.chaos,
570
+ weird: args.weird,
571
+ exp: args.exp,
572
+ tile: args.tile,
573
+ negative_prompt: args.negative_prompt,
574
+ style_reference,
575
+ style_weight: args.style_weight,
576
+ character_reference,
577
+ character_weight: args.character_weight,
578
+ image_weight: args.image_weight
542
579
  });
543
580
  const start = await client.startGeneration(
544
581
  compact({ model: args.model, input, project: args.project ?? cfg.activeProject ?? void 0 })
@@ -574,6 +611,63 @@ ${footer}` }, ...blocks]
574
611
  }
575
612
  }
576
613
  );
614
+ server.registerTool(
615
+ "midjourney_action",
616
+ {
617
+ title: "Midjourney: a\xE7\xE3o (upscale/varia\xE7\xE3o/pan/zoom/inpaint)",
618
+ description: "Aplica uma A\xC7\xC3O sobre uma gera\xE7\xE3o Midjourney existente (as 4 imagens da grade). upsample = amplia 1 quadrante (index 1-4, 1 imagem); variation = varia 1 quadrante (index 1-4, nova grade de 4); pan = expande numa dire\xE7\xE3o; outpaint = zoom out; inpaint = repinta uma regi\xE3o (mask B/W). pan/outpaint/inpaint exigem um pai que J\xC1 seja um upsample. parent_job_id = id do job APIFrame da gera\xE7\xE3o pai (as a\xE7\xF5es EXPIRAM ap\xF3s um tempo \u2014 use em gera\xE7\xE3o RECENTE)." + TEAM_GATING_NOTE,
619
+ inputSchema: {
620
+ parent_job_id: z.string().min(1).describe("Id do job APIFrame da gera\xE7\xE3o Midjourney pai (metadata.apiframe_task_id)."),
621
+ action: z.enum(["upsample", "variation", "pan", "outpaint", "inpaint"]).describe("A\xE7\xE3o a aplicar."),
622
+ index: z.number().int().min(1).max(4).optional().describe("Quadrante 1-4 (upsample/variation)."),
623
+ direction: z.enum(["up", "down", "left", "right"]).optional().describe("Dire\xE7\xE3o (pan)."),
624
+ zoom_ratio: z.enum(["1.5", "2"]).optional().describe("Zoom out (outpaint)."),
625
+ mask: z.string().optional().describe("M\xE1scara base64 B/W PNG (inpaint) \u2014 \xE1rea branca = repintar."),
626
+ prompt: z.string().max(2e3).optional().describe("Prompt opcional (inpaint)."),
627
+ project: z.string().max(64).optional().describe("Projeto (uuid OU code curto).")
628
+ }
629
+ },
630
+ async (args) => {
631
+ try {
632
+ const input = compact({
633
+ mj_action: args.action,
634
+ parent_job_id: args.parent_job_id,
635
+ index: args.index,
636
+ direction: args.direction,
637
+ zoom_ratio: args.zoom_ratio ? Number(args.zoom_ratio) : void 0,
638
+ mask: args.mask,
639
+ prompt: args.prompt
640
+ });
641
+ const start = await client.startGeneration(
642
+ compact({ model: "midjourney", input, project: args.project ?? cfg.activeProject ?? void 0 })
643
+ );
644
+ if (!start.success || !start.generation_id) {
645
+ if (isTeamGatingError(start.message)) return errorResult(await buildPickProjectMessage(client));
646
+ return errorResult(start.message || "Falha ao iniciar a a\xE7\xE3o.");
647
+ }
648
+ const footer = costFooter(start, cfg);
649
+ const { settled, status } = await pollUntilDone(client, start.generation_id, IMAGE_BUDGET_MS);
650
+ if (!settled) {
651
+ return textResult(`\u23F3 A\xE7\xE3o ainda em processamento (id: ${start.generation_id}). Use check_generation.
652
+ ${footer}`);
653
+ }
654
+ if (status.status === "failed") {
655
+ return errorResult(`A\xE7\xE3o falhou: ${status.error_message || "erro"} \u2014 as a\xE7\xF5es do MJ expiram, o pai pode ter ficado velho.
656
+ ${footer}`);
657
+ }
658
+ const urls = outputUrls(status);
659
+ const blocks = await buildImageBlocks(urls, cfg);
660
+ const list = urls.map((u, i) => `${i + 1}. ${u}`).join("\n") || "(sem URLs)";
661
+ return { content: [{ type: "text", text: `\u2705 A\xE7\xE3o ${args.action} conclu\xEDda.
662
+ ${list}
663
+ ${footer}` }, ...blocks] };
664
+ } catch (e) {
665
+ const msg = e instanceof ApiError ? e.message : e instanceof Error ? e.message : "";
666
+ if (isTeamGatingError(msg)) return errorResult(await buildPickProjectMessage(client));
667
+ return errorResult(apiErrorToUserMessage(e));
668
+ }
669
+ }
670
+ );
577
671
  server.registerTool(
578
672
  "generate_video",
579
673
  {
@@ -593,8 +687,8 @@ ${footer}` }, ...blocks]
593
687
  first_frame_image: z.string().min(1).optional().describe("Imagem inicial (image-to-video / primeiro frame): URL p\xFAblica OU caminho local (sobe pro R2)."),
594
688
  last_frame_image: z.string().min(1).optional().describe("Imagem do \xFAltimo frame (Seedance/Kling): URL p\xFAblica OU caminho local (sobe pro R2)."),
595
689
  reference_images: z.array(z.string().min(1)).max(9).optional().describe("Imagens de refer\xEAncia (personagem/estilo) \u2014 omni/Seedance. URL p\xFAblica OU caminho local. At\xE9 9."),
596
- reference_videos: z.array(z.string().min(1)).max(4).optional().describe("V\xEDdeos de refer\xEAncia (Seedance reference_videos / Kling reference_video): URL OU caminho local."),
597
- reference_audios: z.array(z.string().min(1)).max(4).optional().describe("\xC1udios de refer\xEAncia (Seedance): URL p\xFAblica OU caminho local (sobe pro R2)."),
690
+ reference_videos: z.array(z.string().min(1)).max(3).optional().describe("V\xEDdeos de refer\xEAncia (Seedance reference_videos / Kling reference_video, m\xE1x 3): URL OU caminho local."),
691
+ reference_audios: z.array(z.string().min(1)).max(3).optional().describe("\xC1udios de refer\xEAncia (Seedance, m\xE1x 3): URL p\xFAblica OU caminho local (sobe pro R2)."),
598
692
  motion_video: z.string().min(1).optional().describe("V\xEDdeo de movimento/m\xE1scara din\xE2mica (kling-v2.6-motion-control): URL OU caminho local."),
599
693
  character_orientation: z.string().optional().describe("Orienta\xE7\xE3o do personagem (alguns modelos Kling via Replicate)."),
600
694
  keep_original_sound: z.boolean().optional().describe("Manter o som original do v\xEDdeo de refer\xEAncia (alguns modelos Kling)."),
@@ -605,6 +699,11 @@ ${footer}` }, ...blocks]
605
699
  },
606
700
  async (args) => {
607
701
  try {
702
+ if (args.model === "bytedance/seedance-2.0-mini" && args.resolution && args.resolution !== "480p" && args.resolution !== "720p") {
703
+ return errorResult(
704
+ `seedance-2.0-mini s\xF3 suporta 480p ou 720p (voc\xEA pediu ${args.resolution}). Use seedance-2.0 / seedance-2.0-fast para 1080p/2K.`
705
+ );
706
+ }
608
707
  const firstFrame = await resolveRef(cfg, args.first_frame_image ?? args.reference_image);
609
708
  const endImage = await resolveRef(cfg, args.last_frame_image);
610
709
  const referenceImages = await resolveRefs(cfg, args.reference_images);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beplus-mcp",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "Conector MCP da equipe BePlus — gere imagens/vídeos/áudio e consulte calls, projetos e clientes pela sua conta BePlus (diamantes, limites e histórico aplicados pela plataforma).",
5
5
  "type": "module",
6
6
  "bin": {