sapiens-mcp 1.55.0 → 1.56.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 CHANGED
@@ -31,6 +31,7 @@ import { aula, aulaSchema } from "./tools/aula.js";
31
31
  import { support, supportSchema } from "./tools/support.js";
32
32
  import { atlas, atlasSchema } from "./tools/atlas.js";
33
33
  import { decupagem, decupagemSchema } from "./tools/decupagem.js";
34
+ import { publicidade, publicidadeSchema } from "./tools/publicidade.js";
34
35
  import { reference, referenceSchema } from "./tools/reference.js";
35
36
  import { trilhas, trilhasSchema } from "./tools/trilhas.js";
36
37
  import { semana, semanaSchema } from "./tools/semana.js";
@@ -182,6 +183,11 @@ export const TOOLS = {
182
183
  schema: atlasSchema,
183
184
  handler: atlas,
184
185
  },
186
+ sapiens_publicidade: {
187
+ description: "Acervo de publicidade da casa — campanha premiada e anúncio veiculando agora, guardados pra estudo (admin-only, não cobra Sinapse). Existe pra resolver o gargalo da curadoria: achar um comercial bom e precisar de terminal pra guardar significa que o acervo só cresce quando o dono está na máquina. Sub-actions: 'list' (o que já está no acervo, com filtro por trilha e setor; roda ANTES de guardar, pra não duplicar peça), 'save' (guarda uma peça por LINK do YouTube ou Vimeo, que têm embed oficial e não expiram), 'note' (escreve a leitura editorial numa peça já guardada — separado do save de propósito, porque a leitura vem depois de assistir). Duas trilhas: 'referencia' é campanha premiada, que mostra o teto do ofício, e 'replicavel' é anúncio veiculando agora, que mostra o degrau; uma sozinha mente. O setor sai do catálogo da casa e o servidor deduz pela marca quando não vem. NÃO guarda peça de Meta Ad Library nem do TikTok: aquelas servem por URL assinada que expira, então o vídeo precisa ser espelhado no CDN antes, e isso é do script apps/sapiens/scripts/ingest-ad-references.mjs. O membro vê o acervo em /dashboard/acervo?tab=referencias; a bancada de curadoria é /experimentos/ad-intel.",
188
+ schema: publicidadeSchema,
189
+ handler: publicidade,
190
+ },
185
191
  sapiens_decupagem: {
186
192
  description: "Acervo de Decupagens — a régua de linguagem cinematográfica das referências da casa (admin-only, não cobra Sinapse). O que MEDE é o motor LOCAL `python tools/decupagem/decupa.py \"<arquivo ou link do YouTube>\"` (Python + OpenCV + ffmpeg; não existe OpenCV em serverless, igual à produção dos Vídeos Programáticos). Esta tool é a outra ponta: sobe a ficha que o motor gerou e consulta o acervo. Sub-actions: 'list' (a régua de cada referência já decupada: planos, plano mediano, escola de corte, movimento de câmera vs sujeito, registro de luz, BPM, se o corte obedece ao som), 'get' (a ficha INTEIRA de um slug: plano a plano com o que está no quadro, luz, som, sincronia), 'save' (sobe fichas/<slug>/ficha.json inteiro, sem resumir; mesmo slug ATUALIZA em vez de duplicar), 'note' (anota a leitura editorial na ficha), 'delete'. Fluxo que fecha o ciclo: roda o motor → lê ficha.json → save → aparece no Lab /experimentos/decupagem e entra no comparador. O acervo vale pelo CONJUNTO: uma ficha é morna, vinte lado a lado são a biblioteca de gramática da casa. Antes de decupar referência nova, rode list pra não medir a mesma coisa duas vezes.",
187
193
  schema: decupagemSchema,
@@ -218,26 +224,26 @@ export const TOOLS = {
218
224
  // É a "skill que anda junto com o pacote": escrevo uma vez, vale pra todos os clients,
219
225
  // sem instalar nada. Cobre os tropeços reais (fluxo do musicator, model no vídeo, o
220
226
  // disjuntor anti-loop). Mantém curto de propósito: viaja em todo handshake.
221
- export const SAPIENS_INSTRUCTIONS = `Você opera o Sapiens Sintéticos (sapiensinteticos.com) NA CONTA de um usuário logado. Cada tool age de verdade na conta dele e muitas COBRAM Sinapses (o crédito da casa). Aja como operador, não no chute.
222
-
223
- AS SKILLS DA CASA (leia ANTES de operar, não improvise o fluxo):
224
- O passo a passo travado de cada fluxo mora na tool sapiens_skill, servida por este mesmo servidor: sem login, sem custo, sem rede. Ler a skill é mais barato que errar uma geração que cobra.
225
- - sapiens_skill action=list -> o índice (slug + quando usar cada uma).
226
- - sapiens_skill action=get name=<slug> -> a skill inteira.
227
- Slugs: ${skillMenuLine()}
228
- Puxe a skill ANTES de: gerar música ou efeito sonoro (musica), escolher modelo de vídeo (video), gerar imagem (imagem), criar personagem ou prompt de Midjourney (personagem), criar na identidade do usuário (studio), postar no Fórum ou no chat (forum-comunidade), redigir qualquer texto publicável (voz-da-casa), incorporar o Sintético (companhia), missão de Desafio (trilhas), montar currículo (curriculo), guardar obra ou ferramenta no acervo (repertorio). Perdido no começo: primeiros-passos.
229
- Cliente que lê resources MCP acha o MESMO conteúdo em skill://sapiens/<slug>/SKILL.md.
230
-
231
- REGRA DE OURO:
232
- - PRIMEIRO CONTATO ou "o que você faz?"/"como começo?"/"o que dá pra fazer?": chame sapiens_meta action=start e MOSTRE o resultado na sua voz. Sem login, ele ensina a conectar; logado, traz saldo + primeiros poderes com exemplos. É a porta de entrada: não despeje a lista inteira de tools, deixe o start guiar.
233
- - LOGO APÓS UM LOGIN BEM-SUCEDIDO (action=login retornou ok): chame action=start na sequência e mostre a porta de entrada. O recém-chegado não sabe o que pedir; não o deixe na tela em branco, guie a primeira jogada sem ele precisar perguntar.
234
- - Antes de gerar algo caro (imagem/música/vídeo), cheque saldo: sapiens_meta action=credits (ou subscription). Saldo baixo, avise o usuário antes. Vídeo é o mais caro da casa: confirme com ele antes de disparar.
235
- - REGRA DO TIMEOUT: geração SÍNCRONA pode estourar o teto de ~120s do cliente e voltar 'Timeout' MESMO tendo gerado e COBRADO. Nunca repita às cegas: confira antes onde o resultado cairia (a tabela de onde conferir está na skill 'primeiros-passos').
236
- - "sessionToken expirado" = refaça login: sapiens_meta action=login com o código de sapiensinteticos.com/conectar-claude.
237
- - sapiens_meta action=formats devolve os schemas por formato; action=whoami diz tier (user/admin) + saldo. sapiens_image e sapiens_video action=models trazem o catálogo com o preço ATUAL: consulte em vez de chutar custo.
238
-
239
- MODO COMPANHIA: sapiens_meta action=start e action=whoami podem trazer um bloco 'companion'. Quando vier companion.active=true, você INCORPORA aquele Sintético (a voz dele, o avatar, o oi dele) continuando a operar na conta e nas Sinapses do USUÁRIO. Puxe a skill 'companhia' antes de fazer isso. Se vier 'characterOffer', siga o que ele manda: são personagens que o usuário escreveu e que podem entrar em cena, e quem OFERECE é você, na hora em que a conversa encostar num deles. Só personagem de autoria dele; a alma de personagem alheio não sai por aqui.
240
-
227
+ export const SAPIENS_INSTRUCTIONS = `Você opera o Sapiens Sintéticos (sapiensinteticos.com) NA CONTA de um usuário logado. Cada tool age de verdade na conta dele e muitas COBRAM Sinapses (o crédito da casa). Aja como operador, não no chute.
228
+
229
+ AS SKILLS DA CASA (leia ANTES de operar, não improvise o fluxo):
230
+ O passo a passo travado de cada fluxo mora na tool sapiens_skill, servida por este mesmo servidor: sem login, sem custo, sem rede. Ler a skill é mais barato que errar uma geração que cobra.
231
+ - sapiens_skill action=list -> o índice (slug + quando usar cada uma).
232
+ - sapiens_skill action=get name=<slug> -> a skill inteira.
233
+ Slugs: ${skillMenuLine()}
234
+ Puxe a skill ANTES de: gerar música ou efeito sonoro (musica), escolher modelo de vídeo (video), gerar imagem (imagem), criar personagem ou prompt de Midjourney (personagem), criar na identidade do usuário (studio), postar no Fórum ou no chat (forum-comunidade), redigir qualquer texto publicável (voz-da-casa), incorporar o Sintético (companhia), missão de Desafio (trilhas), montar currículo (curriculo), guardar obra ou ferramenta no acervo (repertorio). Perdido no começo: primeiros-passos.
235
+ Cliente que lê resources MCP acha o MESMO conteúdo em skill://sapiens/<slug>/SKILL.md.
236
+
237
+ REGRA DE OURO:
238
+ - PRIMEIRO CONTATO ou "o que você faz?"/"como começo?"/"o que dá pra fazer?": chame sapiens_meta action=start e MOSTRE o resultado na sua voz. Sem login, ele ensina a conectar; logado, traz saldo + primeiros poderes com exemplos. É a porta de entrada: não despeje a lista inteira de tools, deixe o start guiar.
239
+ - LOGO APÓS UM LOGIN BEM-SUCEDIDO (action=login retornou ok): chame action=start na sequência e mostre a porta de entrada. O recém-chegado não sabe o que pedir; não o deixe na tela em branco, guie a primeira jogada sem ele precisar perguntar.
240
+ - Antes de gerar algo caro (imagem/música/vídeo), cheque saldo: sapiens_meta action=credits (ou subscription). Saldo baixo, avise o usuário antes. Vídeo é o mais caro da casa: confirme com ele antes de disparar.
241
+ - REGRA DO TIMEOUT: geração SÍNCRONA pode estourar o teto de ~120s do cliente e voltar 'Timeout' MESMO tendo gerado e COBRADO. Nunca repita às cegas: confira antes onde o resultado cairia (a tabela de onde conferir está na skill 'primeiros-passos').
242
+ - "sessionToken expirado" = refaça login: sapiens_meta action=login com o código de sapiensinteticos.com/conectar-claude.
243
+ - sapiens_meta action=formats devolve os schemas por formato; action=whoami diz tier (user/admin) + saldo. sapiens_image e sapiens_video action=models trazem o catálogo com o preço ATUAL: consulte em vez de chutar custo.
244
+
245
+ MODO COMPANHIA: sapiens_meta action=start e action=whoami podem trazer um bloco 'companion'. Quando vier companion.active=true, você INCORPORA aquele Sintético (a voz dele, o avatar, o oi dele) continuando a operar na conta e nas Sinapses do USUÁRIO. Puxe a skill 'companhia' antes de fazer isso. Se vier 'characterOffer', siga o que ele manda: são personagens que o usuário escreveu e que podem entrar em cena, e quem OFERECE é você, na hora em que a conversa encostar num deles. Só personagem de autoria dele; a alma de personagem alheio não sai por aqui.
246
+
241
247
  Voz da casa: 1ª pessoa, direto, anti-corporate, sem travessão. Pra bom entendedor, meia palavra basta. Texto que vai ser publicado pede a skill 'voz-da-casa' antes.`;
242
248
  // Annotations MCP: título humano + dica read-only. São HINTS (não-confiáveis por
243
249
  // spec): quem gateia de verdade continua o servidor (saldo, gate de admin,
@@ -307,6 +313,7 @@ const ADMIN_ONLY_TOOLS = new Set([
307
313
  "sapiens_aula",
308
314
  "sapiens_share",
309
315
  "sapiens_decupagem",
316
+ "sapiens_publicidade",
310
317
  ]);
311
318
  /**
312
319
  * Monta o payload do tools/list pro tier dado. Tier "user" esconde as
@@ -0,0 +1,114 @@
1
+ import { z } from "zod";
2
+ import { convexQuery, convexMutation, getSessionToken } from "../convexClient.js";
3
+ /**
4
+ * sapiens_publicidade — o acervo de publicidade da casa, pela porta do agente.
5
+ *
6
+ * Existe pra resolver um gargalo de curadoria, não pra expor mais um catálogo:
7
+ * achar um comercial bom e precisar de terminal pra guardar significa que o
8
+ * acervo só cresce quando o dono está na máquina. Aqui ele guarda de onde
9
+ * estiver, com o link e uma frase.
10
+ *
11
+ * O acervo tem duas trilhas e as duas ensinam coisas opostas: `referencia` é
12
+ * campanha premiada (o teto do ofício) e `replicavel` é anúncio veiculando
13
+ * agora (o degrau). O membro vê tudo em /dashboard/acervo?tab=referencias.
14
+ *
15
+ * ADMIN-ONLY de ponta a ponta: o Convex recusa quem não é dono em toda action,
16
+ * e a tool some do tools/list de membro. A curadoria é o valor deste acervo, e
17
+ * acervo que qualquer agente alimenta vira lista.
18
+ *
19
+ * O que esta tool NÃO faz: guardar peça de biblioteca de anúncio (Meta,
20
+ * TikTok). Aquelas servem por URL assinada que expira, então o vídeo precisa
21
+ * ser espelhado no CDN da casa antes de virar ficha, e isso é trabalho do
22
+ * script `apps/sapiens/scripts/ingest-ad-references.mjs`, com ffmpeg e
23
+ * browser. Link do YouTube e do Vimeo, que têm embed oficial, entram aqui.
24
+ */
25
+ export const publicidadeSchema = z.object({
26
+ action: z.enum(["list", "save", "note"]),
27
+ url: z
28
+ .string()
29
+ .optional()
30
+ .describe("Pra save: link do YouTube ou do Vimeo. Só essas duas, porque têm embed " +
31
+ "oficial que não expira. Peça de Meta Ad Library ou TikTok entra pelo " +
32
+ "script de ingestão da casa, não por aqui."),
33
+ titulo: z.string().optional().describe("Pra save: o nome da campanha."),
34
+ marca: z.string().optional().describe("Pra save: quem anuncia. Resolve o setor sozinho quando o setor não vem."),
35
+ trilha: z
36
+ .enum(["referencia", "replicavel"])
37
+ .optional()
38
+ .describe("Pra save: 'referencia' (campanha premiada, o teto do ofício) ou " +
39
+ "'replicavel' (anúncio veiculando agora). Default: referencia."),
40
+ setor: z
41
+ .string()
42
+ .optional()
43
+ .describe("Pra save/list: o setor do catálogo (Alimentação e bebida, IA e software, " +
44
+ "Moda e beleza...). Em save, sem isto o servidor deduz pela marca."),
45
+ ano: z.number().optional().describe("Pra save: ano da campanha."),
46
+ leitura: z
47
+ .string()
48
+ .optional()
49
+ .describe("Pra save/note: a leitura editorial. O que a peça faz que dá pra roubar, " +
50
+ "onde está o gancho, por que ela segura. É o que o acervo tem e uma " +
51
+ "busca no YouTube não tem."),
52
+ fonte: z
53
+ .enum(["youtube", "vimeo", "tiktok-library", "tiktok-creative-center", "meta-ad-library"])
54
+ .optional()
55
+ .describe("Pra note: a fonte da peça já guardada (vem do list)."),
56
+ externalId: z.string().optional().describe("Pra note: o id da peça na fonte (vem do list)."),
57
+ limite: z.number().optional().describe("Pra list: teto de fichas (default 60, máx 200)."),
58
+ });
59
+ export async function publicidade(args) {
60
+ const sessionToken = getSessionToken();
61
+ if (args.action === "list") {
62
+ const fichas = await convexQuery("adReferences:mcpListar", {
63
+ sessionToken,
64
+ ...(args.trilha ? { trilha: args.trilha } : {}),
65
+ ...(args.setor ? { setor: args.setor } : {}),
66
+ ...(args.limite ? { limite: args.limite } : {}),
67
+ });
68
+ const n = Array.isArray(fichas) ? fichas.length : 0;
69
+ const semLeitura = Array.isArray(fichas) ? fichas.filter((f) => !f.temLeitura).length : 0;
70
+ return {
71
+ count: n,
72
+ fichas,
73
+ note: n === 0
74
+ ? "Nada nesse recorte ainda."
75
+ : `${semLeitura} sem leitura escrita. A leitura é o que o acervo tem e uma busca no YouTube não tem: action=note fonte=<f> externalId=<id> leitura="...".`,
76
+ };
77
+ }
78
+ if (args.action === "save") {
79
+ if (!args.url)
80
+ throw new Error("sapiens_publicidade save: exige url.");
81
+ if (!args.titulo)
82
+ throw new Error("sapiens_publicidade save: exige titulo.");
83
+ const r = await convexMutation("adReferences:mcpGuardar", {
84
+ sessionToken,
85
+ url: args.url,
86
+ titulo: args.titulo,
87
+ ...(args.marca ? { marca: args.marca } : {}),
88
+ ...(args.trilha ? { trilha: args.trilha } : {}),
89
+ ...(args.setor ? { setor: args.setor } : {}),
90
+ ...(args.ano ? { ano: args.ano } : {}),
91
+ ...(args.leitura ? { leitura: args.leitura } : {}),
92
+ });
93
+ return {
94
+ ...r,
95
+ note: r?.novo
96
+ ? "Guardada. Aparece pro membro em /dashboard/acervo?tab=referencias."
97
+ : "Já estava no acervo; a ficha foi atualizada em vez de duplicar.",
98
+ };
99
+ }
100
+ if (args.action === "note") {
101
+ if (!args.fonte || !args.externalId) {
102
+ throw new Error("sapiens_publicidade note: exige fonte e externalId (vêm do list).");
103
+ }
104
+ if (!args.leitura)
105
+ throw new Error("sapiens_publicidade note: exige leitura.");
106
+ return await convexMutation("adReferences:mcpAnotar", {
107
+ sessionToken,
108
+ fonte: args.fonte,
109
+ externalId: args.externalId,
110
+ leitura: args.leitura,
111
+ });
112
+ }
113
+ throw new Error(`sapiens_publicidade: action desconhecida "${args.action}".`);
114
+ }
@@ -0,0 +1,114 @@
1
+ import { z } from "zod";
2
+ import { convexQuery, convexMutation, getSessionToken } from "../convexClient.js";
3
+ /**
4
+ * sapiens_referencia — o acervo de publicidade da casa, pela porta do agente.
5
+ *
6
+ * Existe pra resolver um gargalo de curadoria, não pra expor mais um catálogo:
7
+ * achar um comercial bom e precisar de terminal pra guardar significa que o
8
+ * acervo só cresce quando o dono está na máquina. Aqui ele guarda de onde
9
+ * estiver, com o link e uma frase.
10
+ *
11
+ * O acervo tem duas trilhas e as duas ensinam coisas opostas: `referencia` é
12
+ * campanha premiada (o teto do ofício) e `replicavel` é anúncio veiculando
13
+ * agora (o degrau). O membro vê tudo em /dashboard/acervo?tab=referencias.
14
+ *
15
+ * ADMIN-ONLY de ponta a ponta: o Convex recusa quem não é dono em toda action,
16
+ * e a tool some do tools/list de membro. A curadoria é o valor deste acervo, e
17
+ * acervo que qualquer agente alimenta vira lista.
18
+ *
19
+ * O que esta tool NÃO faz: guardar peça de biblioteca de anúncio (Meta,
20
+ * TikTok). Aquelas servem por URL assinada que expira, então o vídeo precisa
21
+ * ser espelhado no CDN da casa antes de virar ficha, e isso é trabalho do
22
+ * script `apps/sapiens/scripts/ingest-ad-references.mjs`, com ffmpeg e
23
+ * browser. Link do YouTube e do Vimeo, que têm embed oficial, entram aqui.
24
+ */
25
+ export const referenciaSchema = z.object({
26
+ action: z.enum(["list", "save", "note"]),
27
+ url: z
28
+ .string()
29
+ .optional()
30
+ .describe("Pra save: link do YouTube ou do Vimeo. Só essas duas, porque têm embed " +
31
+ "oficial que não expira. Peça de Meta Ad Library ou TikTok entra pelo " +
32
+ "script de ingestão da casa, não por aqui."),
33
+ titulo: z.string().optional().describe("Pra save: o nome da campanha."),
34
+ marca: z.string().optional().describe("Pra save: quem anuncia. Resolve o setor sozinho quando o setor não vem."),
35
+ trilha: z
36
+ .enum(["referencia", "replicavel"])
37
+ .optional()
38
+ .describe("Pra save: 'referencia' (campanha premiada, o teto do ofício) ou " +
39
+ "'replicavel' (anúncio veiculando agora). Default: referencia."),
40
+ setor: z
41
+ .string()
42
+ .optional()
43
+ .describe("Pra save/list: o setor do catálogo (Alimentação e bebida, IA e software, " +
44
+ "Moda e beleza...). Em save, sem isto o servidor deduz pela marca."),
45
+ ano: z.number().optional().describe("Pra save: ano da campanha."),
46
+ leitura: z
47
+ .string()
48
+ .optional()
49
+ .describe("Pra save/note: a leitura editorial. O que a peça faz que dá pra roubar, " +
50
+ "onde está o gancho, por que ela segura. É o que o acervo tem e uma " +
51
+ "busca no YouTube não tem."),
52
+ fonte: z
53
+ .enum(["youtube", "vimeo", "tiktok-library", "tiktok-creative-center", "meta-ad-library"])
54
+ .optional()
55
+ .describe("Pra note: a fonte da peça já guardada (vem do list)."),
56
+ externalId: z.string().optional().describe("Pra note: o id da peça na fonte (vem do list)."),
57
+ limite: z.number().optional().describe("Pra list: teto de fichas (default 60, máx 200)."),
58
+ });
59
+ export async function referencia(args) {
60
+ const sessionToken = getSessionToken();
61
+ if (args.action === "list") {
62
+ const fichas = await convexQuery("adReferences:mcpListar", {
63
+ sessionToken,
64
+ ...(args.trilha ? { trilha: args.trilha } : {}),
65
+ ...(args.setor ? { setor: args.setor } : {}),
66
+ ...(args.limite ? { limite: args.limite } : {}),
67
+ });
68
+ const n = Array.isArray(fichas) ? fichas.length : 0;
69
+ const semLeitura = Array.isArray(fichas) ? fichas.filter((f) => !f.temLeitura).length : 0;
70
+ return {
71
+ count: n,
72
+ fichas,
73
+ note: n === 0
74
+ ? "Nada nesse recorte ainda."
75
+ : `${semLeitura} sem leitura escrita. A leitura é o que o acervo tem e uma busca no YouTube não tem: action=note fonte=<f> externalId=<id> leitura="...".`,
76
+ };
77
+ }
78
+ if (args.action === "save") {
79
+ if (!args.url)
80
+ throw new Error("sapiens_referencia save: exige url.");
81
+ if (!args.titulo)
82
+ throw new Error("sapiens_referencia save: exige titulo.");
83
+ const r = await convexMutation("adReferences:mcpGuardar", {
84
+ sessionToken,
85
+ url: args.url,
86
+ titulo: args.titulo,
87
+ ...(args.marca ? { marca: args.marca } : {}),
88
+ ...(args.trilha ? { trilha: args.trilha } : {}),
89
+ ...(args.setor ? { setor: args.setor } : {}),
90
+ ...(args.ano ? { ano: args.ano } : {}),
91
+ ...(args.leitura ? { leitura: args.leitura } : {}),
92
+ });
93
+ return {
94
+ ...r,
95
+ note: r?.novo
96
+ ? "Guardada. Aparece pro membro em /dashboard/acervo?tab=referencias."
97
+ : "Já estava no acervo; a ficha foi atualizada em vez de duplicar.",
98
+ };
99
+ }
100
+ if (args.action === "note") {
101
+ if (!args.fonte || !args.externalId) {
102
+ throw new Error("sapiens_referencia note: exige fonte e externalId (vêm do list).");
103
+ }
104
+ if (!args.leitura)
105
+ throw new Error("sapiens_referencia note: exige leitura.");
106
+ return await convexMutation("adReferences:mcpAnotar", {
107
+ sessionToken,
108
+ fonte: args.fonte,
109
+ externalId: args.externalId,
110
+ leitura: args.leitura,
111
+ });
112
+ }
113
+ throw new Error(`sapiens_referencia: action desconhecida "${args.action}".`);
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sapiens-mcp",
3
- "version": "1.55.0",
3
+ "version": "1.56.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",