beplus-mcp 0.9.0 → 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 +103 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -424,7 +424,8 @@ 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",
@@ -519,13 +520,34 @@ function registerGenerationTools(server, client, cfg) {
519
520
  output_format: z.enum(["png", "jpeg", "webp"]).optional().describe("Formato de sa\xEDda (gpt-image-2). Padr\xE3o png."),
520
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."),
521
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."),
522
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.')
523
539
  }
524
540
  },
525
541
  async (args) => {
526
542
  try {
527
543
  const isGoogle = args.model.startsWith("google/");
544
+ const isMidjourney = args.model === "midjourney";
528
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;
529
551
  const input = compact({
530
552
  prompt: args.prompt,
531
553
  aspect_ratio: args.aspect_ratio ?? (isGoogle ? DEFAULTS.imageAspect : void 0),
@@ -534,12 +556,26 @@ function registerGenerationTools(server, client, cfg) {
534
556
  google_search: args.google_search,
535
557
  image_search: args.image_search,
536
558
  size: args.size,
537
- quality: args.quality,
559
+ quality: isMidjourney ? args.mj_quality : args.quality,
538
560
  background: args.background,
539
561
  moderation: args.moderation,
540
562
  output_format: args.output_format,
541
563
  output_compression: args.output_compression,
542
- 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
543
579
  });
544
580
  const start = await client.startGeneration(
545
581
  compact({ model: args.model, input, project: args.project ?? cfg.activeProject ?? void 0 })
@@ -575,6 +611,63 @@ ${footer}` }, ...blocks]
575
611
  }
576
612
  }
577
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
+ );
578
671
  server.registerTool(
579
672
  "generate_video",
580
673
  {
@@ -594,8 +687,8 @@ ${footer}` }, ...blocks]
594
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)."),
595
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)."),
596
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."),
597
- 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."),
598
- 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)."),
599
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."),
600
693
  character_orientation: z.string().optional().describe("Orienta\xE7\xE3o do personagem (alguns modelos Kling via Replicate)."),
601
694
  keep_original_sound: z.boolean().optional().describe("Manter o som original do v\xEDdeo de refer\xEAncia (alguns modelos Kling)."),
@@ -606,6 +699,11 @@ ${footer}` }, ...blocks]
606
699
  },
607
700
  async (args) => {
608
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
+ }
609
707
  const firstFrame = await resolveRef(cfg, args.first_frame_image ?? args.reference_image);
610
708
  const endImage = await resolveRef(cfg, args.last_frame_image);
611
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.9.0",
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": {