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.
- package/dist/index.js +103 -5
- 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(
|
|
598
|
-
reference_audios: z.array(z.string().min(1)).max(
|
|
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.
|
|
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": {
|