sapiens-mcp 1.77.0 → 1.78.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/registry.js +7 -1
- package/dist/skills.js +0 -1
- package/dist/tools/distribution.js +56 -0
- package/dist/tools/gallery.js +1 -1
- package/dist/tools/instagram.js +2 -1
- package/dist/tools/meta.js +5 -4
- package/dist/tools/shareDrop.js +1 -1
- package/dist/tools/sintetico.js +1 -1
- package/dist/tools/studios.js +1 -1
- package/package.json +1 -1
package/dist/registry.js
CHANGED
|
@@ -48,6 +48,12 @@ import { skillMenuLine } from "./skills.js";
|
|
|
48
48
|
* pelos DOIS transportes: o stdio (index.ts, pacote npm/npx) e o remoto
|
|
49
49
|
* streamable HTTP (remote.ts, rota /api/mcp do site). Mexeu aqui, mexeu nos
|
|
50
50
|
* dois ao mesmo tempo — é o ponto.
|
|
51
|
+
*
|
|
52
|
+
* Tool nova ou removida aqui: atualize junto o EXPECTED_TOOLS de
|
|
53
|
+
* test/server.test.mjs e as contagens fixas de test/remote.test.mjs e
|
|
54
|
+
* test/remote-protect.test.mjs (admin e user), senão o gate de teste do
|
|
55
|
+
* release.sh fica vermelho e parece culpa da mudança seguinte (origem:
|
|
56
|
+
* 07c9c77c5).
|
|
51
57
|
*/
|
|
52
58
|
export const TOOLS = {
|
|
53
59
|
sapiens_pipeline: {
|
|
@@ -206,7 +212,7 @@ export const TOOLS = {
|
|
|
206
212
|
handler: trilhas,
|
|
207
213
|
},
|
|
208
214
|
sapiens_distribution: {
|
|
209
|
-
description: "Despachar peças (Distribution Workflow) — a peça pronta entra na FILA com canal, copy e a aba de quem ela é. ADMIN-ONLY: despacho depende de rede conectada e hoje só a casa tem. NADA aqui posta em rede nenhuma; quem despacha é a tela em /experimentos/distribution-workflow, que é onde a conta conectada mora. A ABA (`voice`) responde de quem é a peça: sapiens (a casa), helen-ailith, borderless, ou o slug de um personagem seu — slug livre, então personagem novo ganha aba sozinho na primeira peça dele, sem deploy. Em queue, aba ausente = o servidor deriva do personagem da peça e cai em sapiens quando não há. Sub-actions: queue (põe na fila: title e channel obrigatórios, mais copy/hashtags/assetUrl/notes; num canal do Instagram, format instagram_story faz a peça sair como STORY: uma mídia só, sem legenda nem link, some em 24h). Em queue, DOIS campos que parecem opcionais e não são: `lang` diz em que língua a copy já está, e sem ele canal de rede internacional reescreve a sua copy sozinho, dois segundos depois, na voz da casa; `assetPageAssetId` é o imageId da obra da casa, e sem ele a peça só encontra a obra se a assetUrl bater letra a letra, então versão web de um master nasce órfã de ficha, list (o que está na fila, filtrável por status e por aba), voices (as abas que existem hoje com a contagem de cada uma), status (move a peça de lane: fila, agendado, postado, descartado; postado aceita postUrl e fecha o rastro, agendado aceita scheduledFor em ms), sign (liga ou desliga a ASSINATURA da peça, imagem e vídeo do CDN da casa, com o carimbo da LINHAGEM de quem assina: sint.fyi/<endereço dela> no canto e o fecho de 2s no vídeo, ou a marca própria dela sem nada da casa; itemId, e signed com true de default; o carimbo da casa é recusado em peça +18 e praça adulta, a marca própria passa; o carimbo leva uns 30s e até lá a peça não sai; em queue, signed:true já enfileira assinada), bio (lê ou troca a BIO de uma conta da casa no Bluesky, channel bluesky ou bluesky-2 a bluesky-5: sem texto só lê; bioLine acrescenta uma linha no fim sem mexer no resto e não repete linha que já está lá; bio reescreve a inteira; teto de 256; ESTA sub-action muda o perfil público na hora, e bio não aceita hiperlink, o endereço aparece escrito), lineages (o CADASTRO das linhagens, o mesmo da aba Teia: de cada personagem, produto e da casa, a mãe no Bluesky onde a peça nasce, as contas próprias, as galerias que a mãe alimenta sozinha, as fichas e o post do dia, mais as regras que a teia desdobra e as vagas de conta ainda sem dona), lineage-new (nasce uma linhagem: nome obrigatório, grupo, artigo, lang; nasce sem mãe, então nada viaja sozinho até o lineage-save dar a mãe), lineage-save (slug e só o que muda: mae, contas rede->canal, galerias, fichaIds, rotina, contaNaCasa, assinatura {estilo casa|propria|nenhuma, marca, padrao}; o servidor recusa conta que já é de outra linhagem e canal de outra rede, e a vaga assumida ganha o nome da linhagem), lineage-archive (slug + arquivada). Sem custo em Sinapses: isto organiza, não gera. A copy segue a voz de QUEM ASSINA a peça, que não é sempre a voz da casa: peça da Helen fala como a Helen. E a peça sai pela CONTA de quem assina ela: conta extra da mesma rede é um canal próprio (bluesky-2 é outra conta no Bluesky, instagram-pro outra no Instagram), então case o canal com a aba antes de despachar.",
|
|
215
|
+
description: "Despachar peças (Distribution Workflow) — a peça pronta entra na FILA com canal, copy e a aba de quem ela é. ADMIN-ONLY: despacho depende de rede conectada e hoje só a casa tem. NADA aqui posta em rede nenhuma; quem despacha é a tela em /experimentos/distribution-workflow, que é onde a conta conectada mora. A ABA (`voice`) responde de quem é a peça: sapiens (a casa), helen-ailith, borderless, ou o slug de um personagem seu — slug livre, então personagem novo ganha aba sozinho na primeira peça dele, sem deploy. Em queue, aba ausente = o servidor deriva do personagem da peça e cai em sapiens quando não há. Sub-actions: queue (põe na fila: title e channel obrigatórios, mais copy/hashtags/assetUrl/notes; replyText é o comentário que sai junto do post, onde vai o link, e só o X (resposta no fio) e a Página do LinkedIn (primeiro comentário) publicam, o resto recusa; num canal do Instagram, format instagram_story faz a peça sair como STORY: uma mídia só, sem legenda nem link, some em 24h). Em queue, DOIS campos que parecem opcionais e não são: `lang` diz em que língua a copy já está, e sem ele canal de rede internacional reescreve a sua copy sozinho, dois segundos depois, na voz da casa; `assetPageAssetId` é o imageId da obra da casa, e sem ele a peça só encontra a obra se a assetUrl bater letra a letra, então versão web de um master nasce órfã de ficha, list (o que está na fila, filtrável por status e por aba), voices (as abas que existem hoje com a contagem de cada uma), status (move a peça de lane: fila, agendado, postado, descartado; postado aceita postUrl e fecha o rastro, agendado aceita scheduledFor em ms), sign (liga ou desliga a ASSINATURA da peça, imagem e vídeo do CDN da casa, com o carimbo da LINHAGEM de quem assina: sint.fyi/<endereço dela> no canto e o fecho de 2s no vídeo, ou a marca própria dela sem nada da casa; itemId, e signed com true de default; o carimbo da casa é recusado em peça +18 e praça adulta, a marca própria passa; o carimbo leva uns 30s e até lá a peça não sai; em queue, signed:true já enfileira assinada), bio (lê ou troca a BIO de uma conta da casa no Bluesky, channel bluesky ou bluesky-2 a bluesky-5: sem texto só lê; bioLine acrescenta uma linha no fim sem mexer no resto e não repete linha que já está lá; bio reescreve a inteira; teto de 256; ESTA sub-action muda o perfil público na hora, e bio não aceita hiperlink, o endereço aparece escrito), lineages (o CADASTRO das linhagens, o mesmo da aba Teia: de cada personagem, produto e da casa, a mãe no Bluesky onde a peça nasce, as contas próprias, as galerias que a mãe alimenta sozinha, as fichas e o post do dia, mais as regras que a teia desdobra e as vagas de conta ainda sem dona), lineage-new (nasce uma linhagem: nome obrigatório, grupo, artigo, lang; nasce sem mãe, então nada viaja sozinho até o lineage-save dar a mãe), lineage-save (slug e só o que muda: mae, contas rede->canal, galerias, fichaIds, rotina, contaNaCasa, assinatura {estilo casa|propria|nenhuma, marca, padrao}; o servidor recusa conta que já é de outra linhagem e canal de outra rede, e a vaga assumida ganha o nome da linhagem), lineage-archive (slug + arquivada), garimpo (o ACERVO em famílias pra escolher o que vai pra fila: só as candidatas saem, a versão velha de um corte ou upscale vem marcada como substituída, as irmãs da mesma ideia vêm agrupadas pra escolha no olho, e cada família diz por onde já saiu; paraCanal tira o que já foi pro canal pedido, soResumo conta sem listar, página por cursor em antesDe; o passo a passo é a skill distribuir). Sem custo em Sinapses: isto organiza, não gera. A copy segue a voz de QUEM ASSINA a peça, que não é sempre a voz da casa: peça da Helen fala como a Helen. E a peça sai pela CONTA de quem assina ela: conta extra da mesma rede é um canal próprio (bluesky-2 é outra conta no Bluesky, instagram-pro outra no Instagram), então case o canal com a aba antes de despachar.",
|
|
210
216
|
schema: distributionSchema,
|
|
211
217
|
handler: distribution,
|
|
212
218
|
},
|
package/dist/skills.js
CHANGED
|
@@ -60,7 +60,6 @@ Não despeje a lista inteira de tools. O start guia.
|
|
|
60
60
|
| imagem | \`sapiens_gallery action=list\` |
|
|
61
61
|
| artigo do perfil | \`sapiens_write action=list\` |
|
|
62
62
|
| carrossel | \`sapiens_pipeline action=list_carousels\` |
|
|
63
|
-
| pipeline | /dashboard/admin/content |
|
|
64
63
|
|
|
65
64
|
**2. Disjuntor anti-loop.** Três falhas seguidas no MESMO tool fazem o cliente marcar o servidor como "unreachable" por ~56s. Parece que "o MCP caiu", mas foi argumento faltando. Quando um tool volta erro de validação ("exige X", "falta Y"), LEIA o erro e refaça a chamada COM o que falta. Nunca repita a chamada idêntica que falhou.
|
|
66
65
|
|
|
@@ -33,6 +33,11 @@ import { convexQuery, convexMutation, convexAction, describeConvexError, getSess
|
|
|
33
33
|
* a mãe no Bluesky, as contas próprias, as galerias que a mãe alimenta, as
|
|
34
34
|
* fichas e o post do dia. É ele que decide por qual conta cada peça sai e
|
|
35
35
|
* o que viaja sozinho depois.
|
|
36
|
+
* - garimpo: o ACERVO em famílias, pra escolher o que vai pra fila. Versão
|
|
37
|
+
* velha (o original de um corte, o take de um vídeo montado) sai marcada
|
|
38
|
+
* como substituída; irmãs (a mesma ideia gerada de novo) vêm agrupadas pra
|
|
39
|
+
* escolha no olho; e cada família diz por onde já saiu. Página por cursor,
|
|
40
|
+
* cortando só num buraco de uma hora entre peças.
|
|
36
41
|
*
|
|
37
42
|
* Sem custo em Sinapses: isto organiza, não gera.
|
|
38
43
|
*/
|
|
@@ -141,6 +146,7 @@ export const distributionSchema = z.object({
|
|
|
141
146
|
"lineage-new",
|
|
142
147
|
"lineage-save",
|
|
143
148
|
"lineage-archive",
|
|
149
|
+
"garimpo",
|
|
144
150
|
]),
|
|
145
151
|
title: z
|
|
146
152
|
.string()
|
|
@@ -154,6 +160,10 @@ export const distributionSchema = z.object({
|
|
|
154
160
|
.string()
|
|
155
161
|
.optional()
|
|
156
162
|
.describe("queue: a legenda pronta pra colar, na voz de quem assina a peça. Sem em-dash."),
|
|
163
|
+
replyText: z
|
|
164
|
+
.string()
|
|
165
|
+
.optional()
|
|
166
|
+
.describe("queue: o COMENTÁRIO que sai junto do post, pra onde vai o link (a copy fica sem ele e fecha apontando pro comentário). Só dois lugares publicam: o X pelo Buffer (x-buffer, x-buffer-2..4) e o X da API própria (x), como resposta no mesmo fio, teto 280; e a Página do LinkedIn pelo Buffer (linkedin-page, linkedin-page-2), como primeiro comentário, teto 1250. Threads (threads, threads-pro, threads-3..5), LinkedIn Perfil (linkedin) e o resto NÃO publicam comentário: lá o link mora na própria copy. O servidor recusa a peça com replyText num canal que não publica, e recusa o comentário acima do teto com a contagem; nada é cortado calado."),
|
|
157
167
|
hashtags: z.array(z.string()).optional().describe("queue: sem o #, o servidor limpa."),
|
|
158
168
|
assetUrl: z
|
|
159
169
|
.string()
|
|
@@ -293,6 +303,33 @@ export const distributionSchema = z.object({
|
|
|
293
303
|
.boolean()
|
|
294
304
|
.optional()
|
|
295
305
|
.describe("lineage-archive: true arquiva, false devolve. A casa e o dono não se arquivam."),
|
|
306
|
+
antesDe: z
|
|
307
|
+
.number()
|
|
308
|
+
.optional()
|
|
309
|
+
.describe("garimpo: o cursor, o `proximoCursor` da página anterior. Ausente = a página mais recente do acervo."),
|
|
310
|
+
limite: z
|
|
311
|
+
.number()
|
|
312
|
+
.int()
|
|
313
|
+
.min(1)
|
|
314
|
+
.max(150)
|
|
315
|
+
.optional()
|
|
316
|
+
.describe("garimpo: peças por página, default 60. A página estica até achar um buraco de uma hora entre duas peças, pra sessão de criação nunca partir ao meio."),
|
|
317
|
+
skill: z
|
|
318
|
+
.string()
|
|
319
|
+
.optional()
|
|
320
|
+
.describe("garimpo: só famílias em que alguma peça saiu desta skill (ex: amiga, camarim, clipe)."),
|
|
321
|
+
kind: z
|
|
322
|
+
.enum(["image", "video", "all"])
|
|
323
|
+
.optional()
|
|
324
|
+
.describe("garimpo: só famílias com candidata desta mídia. Default all."),
|
|
325
|
+
paraCanal: z
|
|
326
|
+
.enum(CHANNELS)
|
|
327
|
+
.optional()
|
|
328
|
+
.describe("garimpo: o canal pra onde a leva vai (a mãe da linhagem, em geral). Tira as famílias que já tiveram peça ali em qualquer lane, descartada inclusive: o dono já decidiu sobre elas naquele canal."),
|
|
329
|
+
soResumo: z
|
|
330
|
+
.boolean()
|
|
331
|
+
.optional()
|
|
332
|
+
.describe("garimpo: só a contagem (famílias, candidatas, versões antigas, escolhas pro olho, inéditas, por voz), sem as famílias. É a varredura do inventário: repita com o proximoCursor até ele voltar null."),
|
|
296
333
|
});
|
|
297
334
|
/** O recado que volta pro agente depois de ligar ou desligar a assinatura. */
|
|
298
335
|
function recadoDaAssinatura(signed, r) {
|
|
@@ -328,6 +365,7 @@ export async function distribution(args) {
|
|
|
328
365
|
title: args.title,
|
|
329
366
|
channel: args.channel,
|
|
330
367
|
copy: args.copy,
|
|
368
|
+
replyText: args.replyText,
|
|
331
369
|
hashtags: args.hashtags,
|
|
332
370
|
assetUrl: args.assetUrl,
|
|
333
371
|
assetKind: args.assetKind,
|
|
@@ -398,6 +436,24 @@ export async function distribution(args) {
|
|
|
398
436
|
if (args.action === "voices") {
|
|
399
437
|
return await convexQuery("distributionMcp:mcpVoices", { sessionToken });
|
|
400
438
|
}
|
|
439
|
+
if (args.action === "garimpo") {
|
|
440
|
+
const r = await convexQuery("distributionMcp:mcpGarimpo", {
|
|
441
|
+
sessionToken,
|
|
442
|
+
antesDe: args.antesDe,
|
|
443
|
+
limite: args.limite,
|
|
444
|
+
voz: args.voice,
|
|
445
|
+
skill: args.skill,
|
|
446
|
+
kind: args.kind,
|
|
447
|
+
paraCanal: args.paraCanal,
|
|
448
|
+
soResumo: args.soResumo,
|
|
449
|
+
});
|
|
450
|
+
return {
|
|
451
|
+
...r,
|
|
452
|
+
instruction: args.soResumo
|
|
453
|
+
? "Contagem desta página. Pra varrer o acervo inteiro, chame de novo com antesDe=proximoCursor até ele voltar null e some os resumos. A soma é aproximada pra cima: o still de um vídeo feito dias depois conta na família do vídeo e de novo na página dele."
|
|
454
|
+
: "Cada família é UMA peça da casa, com as versões e as alternativas dela. Só `candidatas` podem sair: membro com `substituidaPor` é versão velha (o original de um corte, o take de um vídeo montado) e nunca vai pra fila. Cada grupo de `escolhaPorOlho` é a mesma ideia gerada mais de uma vez: sai UMA, escolhida olhando as peças, nunca a primeira da lista nem duas do grupo. Laço `sequencia` é o edit que continua a peça (a careta depois da pergunta): não é alternativa, as duas valem, juntas no mesmo post ou uma depois da outra. Laço `cena` liga a mesma cena em outra mídia ou outro nível (o vídeo que nasceu do still, o edit +18 da base vestida): cada uma serve a sua praça, nunca as duas na mesma mãe. `serieCom` aponta famílias do mesmo lugar em outro momento: não cabem na mesma leva. `jaSaiuEm` diz onde a família já está (fila, agendado ou postado). Página seguinte: antesDe=proximoCursor; peça que já apareceu numa página (mesmo id de membro) não conta de novo. Com extrasEsgotado=true, alguma família pode ter vindo sem a versão nova: peça a página com limite menor. O passo a passo da escolha e da copy é a skill distribuir.",
|
|
455
|
+
};
|
|
456
|
+
}
|
|
401
457
|
if (args.action === "status") {
|
|
402
458
|
if (!args.itemId)
|
|
403
459
|
throw new Error("action=status exige itemId.");
|
package/dist/tools/gallery.js
CHANGED
|
@@ -63,7 +63,7 @@ export const gallerySchema = z.object({
|
|
|
63
63
|
.positive()
|
|
64
64
|
.max(100)
|
|
65
65
|
.optional()
|
|
66
|
-
.describe("Default 20. Max 100. Só pra action=list."),
|
|
66
|
+
.describe("Default 20. Max 100. Só pra action=list. Sem offset: com filtro de model ou skill a busca varre só as últimas 200 peças. Pra achar o imageId de peça que não é de hoje, use sapiens_reference action=browse bucket=history term=<palavra> (paginado, devolve o imageId) ou sapiens_reference action=resolve handle=img_xxx."),
|
|
67
67
|
model: z
|
|
68
68
|
.string()
|
|
69
69
|
.optional()
|
package/dist/tools/instagram.js
CHANGED
|
@@ -5,7 +5,8 @@ import { need } from "../schema.js";
|
|
|
5
5
|
* sapiens_instagram — o "ManyChat da casa" via MCP. ADMIN-ONLY (requireMcpAdmin
|
|
6
6
|
* no Convex): opera o auto-DM do Instagram da casa (regras de resposta
|
|
7
7
|
* automática, inbox das conversas, resposta manual pela janela de 24h).
|
|
8
|
-
* Espelha
|
|
8
|
+
* Espelha as regras em /experimentos/distribution-workflow?tab=autodm e o inbox
|
|
9
|
+
* em /dashboard/admin/sapiens-leads/instagram; backend em convex/instagramDm.ts.
|
|
9
10
|
*
|
|
10
11
|
* Sub-actions:
|
|
11
12
|
* - rules: lista as regras (keyword, variações, escopo por post, disparos)
|
package/dist/tools/meta.js
CHANGED
|
@@ -430,8 +430,8 @@ export async function meta(args) {
|
|
|
430
430
|
desktopLogin: `${APP_URL}/desktop-login`,
|
|
431
431
|
dashboard: `${APP_URL}/dashboard`,
|
|
432
432
|
adminCuration: `${APP_URL}/dashboard/admin/blog/sapiens-curation`,
|
|
433
|
-
adminPopArticles: `${APP_URL}/dashboard/admin/
|
|
434
|
-
adminPipeline: `${APP_URL}/
|
|
433
|
+
adminPopArticles: `${APP_URL}/dashboard/admin/blog?type=pop-article`,
|
|
434
|
+
adminPipeline: `${APP_URL}/experimentos/content-pipeline`,
|
|
435
435
|
};
|
|
436
436
|
}
|
|
437
437
|
// version: qual versão do sapiens-mcp está rodando AGORA (lida do package.json
|
|
@@ -577,8 +577,9 @@ export async function meta(args) {
|
|
|
577
577
|
}
|
|
578
578
|
const sessionToken = getSessionToken();
|
|
579
579
|
if (args.action === "whoami") {
|
|
580
|
-
// mcpGetMySubscription usa
|
|
581
|
-
//
|
|
580
|
+
// mcpGetMySubscription usa requireMcpSession sem admin (qualquer logado
|
|
581
|
+
// com token de acesso cheio; chave da voz e OAuth de parceira não passam),
|
|
582
|
+
// então whoami funciona pra user E admin e reporta o tier pro Claude.
|
|
582
583
|
const sub = await convexQuery("mcpExtras:mcpGetMySubscription", {
|
|
583
584
|
sessionToken,
|
|
584
585
|
});
|
package/dist/tools/shareDrop.js
CHANGED
|
@@ -8,7 +8,7 @@ import { need } from "../schema.js";
|
|
|
8
8
|
* Sobe um HTML single-file e recebe o link curto sint.fyi/s/<code>. O ponto:
|
|
9
9
|
* PUBLICAR um artefato e depois RE-PUBLICAR no MESMO link quantas vezes quiser
|
|
10
10
|
* (action=update com o code) — edita aqui no Claude, joga pro ar, atualiza o
|
|
11
|
-
* mesmo arquivo. Espelha
|
|
11
|
+
* mesmo arquivo. Espelha o painel /dashboard/admin/share-drop e o CLI
|
|
12
12
|
* share-drop-sync, mas sem admin key: identidade vem do sessionToken.
|
|
13
13
|
*
|
|
14
14
|
* O HTML entra por `html` (string, funciona no stdio E no remoto) ou por
|
package/dist/tools/sintetico.js
CHANGED
|
@@ -260,7 +260,7 @@ export async function sintetico(args) {
|
|
|
260
260
|
});
|
|
261
261
|
return {
|
|
262
262
|
...res,
|
|
263
|
-
note: "Proposta do seu Reflexo (grátis). Pra gerar a cara dele: action=reflexo_generate. Pra CONSAGRAR e criar o Sintético de fato é na web (/experimentos/
|
|
263
|
+
note: "Proposta do seu Reflexo (grátis). Pra gerar a cara dele: action=reflexo_generate. Pra CONSAGRAR e criar o Sintético de fato é na web (/experimentos/identity-workflow, passo final), ato deliberado, fora do MCP.",
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
266
|
// -------- reflexo_generate: gera a imagem do Reflexo (cobra 450) --------
|
package/dist/tools/studios.js
CHANGED
|
@@ -199,7 +199,7 @@ export async function studios(args) {
|
|
|
199
199
|
// tivermos lookup slug-by-id.
|
|
200
200
|
return {
|
|
201
201
|
url: slug ? `${APP}/articles/${slug}` : null,
|
|
202
|
-
admin: `${APP}/
|
|
202
|
+
admin: `${APP}/experimentos/content-pipeline`,
|
|
203
203
|
note: slug
|
|
204
204
|
? "URL pública. Pra ver versões anteriores, use sapiens_pipeline list_versions."
|
|
205
205
|
: "publishableId lookup ainda não suportado v1.3. Passe slug.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.78.0",
|
|
4
4
|
"mcpName": "com.sapiensinteticos/sapiens",
|
|
5
5
|
"description": "MCP server pra operar o Sapiens Sintéticos (sapiensinteticos.com) pelo Claude Code: gerar imagem, escrever artigo, voz, música e mais, na sua conta. Login pelo código de sapiensinteticos.com/conectar-claude.",
|
|
6
6
|
"type": "module",
|