sapiens-mcp 1.26.3 → 1.27.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 +9 -3
- package/dist/tools/instagram.js +98 -0
- package/dist/tools/video.js +29 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { article, articleSchema } from "./tools/article.js";
|
|
|
13
13
|
import { quotePop, quotePopSchema } from "./tools/quotePop.js";
|
|
14
14
|
import { search, searchSchema } from "./tools/search.js";
|
|
15
15
|
import { studios, studiosSchema } from "./tools/studios.js";
|
|
16
|
+
import { instagram, instagramSchema } from "./tools/instagram.js";
|
|
16
17
|
import { persona, personaSchema } from "./tools/persona.js";
|
|
17
18
|
import { helen, helenSchema } from "./tools/helen.js";
|
|
18
19
|
import { musicator, musicatorSchema } from "./tools/musicator.js";
|
|
@@ -148,6 +149,11 @@ const TOOLS = {
|
|
|
148
149
|
schema: forumSchema,
|
|
149
150
|
handler: forum,
|
|
150
151
|
},
|
|
152
|
+
sapiens_instagram: {
|
|
153
|
+
description: "Auto-DM do Instagram da casa (o 'ManyChat próprio') — ADMIN-ONLY (dono). Quem manda DM ou comenta keyword num post do @sapiensinteticos recebe resposta automática; aqui você OPERA esse motor. Sub-actions: 'rules' (lista regras: keyword, resposta, variações, eco público, escopo por post, disparos), 'rule_upsert' (cria/edita regra; ruleId presente = edita; keyword+reply obrigatórios fora do fallback; replyVariants/echoVariants rodam em round-robin pra não repetir; mediaId escopa a regra num post; isFallback responde DM sem keyword 1x/24h por pessoa), 'rule_delete' (apaga por ruleId), 'inbox' (conversas recentes; cada uma com canReply = janela de 24h da Meta aberta ou não), 'thread' (mensagens de uma conversa por igUserId), 'send' (responde na mão pela janela de 24h; fora dela a Meta recusa). Comentário só dispara regra de KEYWORD (fallback nunca), com eco público opcional ('te respondi no direct!'). Limites da API: não dá pra iniciar conversa, só reagir; janela de 24h pra responder DM.",
|
|
154
|
+
schema: instagramSchema,
|
|
155
|
+
handler: instagram,
|
|
156
|
+
},
|
|
151
157
|
sapiens_aula: {
|
|
152
158
|
description: "Aula (deck da Mentoria OPS, servido em /aulas/<slug>) — ADMIN-ONLY (aula é conteúdo de mentor, não de aluno; aluno leva 'restrito ao dono'). Cria e edita aula direto no Convex, sem o script migrate-aulas-to-convex.mjs. Sub-actions: 'list' (slug/título/data/slideCount/voiceWarnings/url), 'get' (1 aula completa por slug, pra editar local), 'upsert' (cria se não existe, senão patch; por slug kebab-case). O `aula` do upsert é o objeto completo: title (obrig) + slides[] (≥1) + subtitle/data/duration/tag/mentorAgenda opcionais. Slides são { type, ...campos }: cover, cover-image/section-image/content-image (imageUrl), agenda (items[]), content (body markdown/HTML + list[]/listType), two-col (cols[]), quote, callout (tone tip|warn|note), comic (panels[]), pause, close (items[]). O servidor re-linta a voz e grava voiceWarnings (1ª pessoa, anti-corporate, SEM travessão). A rota /aulas/<slug> serve sob demanda; slug novo aparece sem rebuild.",
|
|
153
159
|
schema: aulaSchema,
|
|
@@ -198,7 +204,7 @@ Música (sapiens_musicator) é fluxo de 4 passos, EM ORDEM:
|
|
|
198
204
|
4. get passe o trackId e fique polando o status até 'ready' (ou 'failed').
|
|
199
205
|
Pular pro lyrics/render sem create, ou sem os campos, sempre falha.
|
|
200
206
|
|
|
201
|
-
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality | omni. Sem model, falha de cara. O 'omni' (Gemini Omni) gera clipe de 10s 720p com áudio nativo a partir de TEXTO (não aceita imagem/vídeo do user, ignora duração/resolução) e EDITA os próprios vídeos: passe editOfImageId com o imageId de um vídeo Omni já gerado e o prompt vira instrução de edição sobre a MESMA cena (troca item/personagem, preserva câmera e ambiente; cada edição debita como geração nova). É o caminho pra variações com continuidade: gera a base uma vez, edita N vezes. Vídeo é o mais caro: confirme com o usuário antes. Vitrine dos demos (sem custo): sapiens_video action=demos lista seus demo films com slug; action=showcase (slug + showcase=true/false + showcaseTag + showcaseOrder) cura o mini-cinema da /conectar-claude. FILMES DA CASA (Estúdio de Vídeo, tela /experimentos/films): são OUTRA coisa, três kinds na tabela videoSpecs: demo (UI clonada + câmera), aula-tour (telas reais + narração) e essay (fita-ensaio abstrata: partícula/tinta vira símbolo, com a logo explodindo no fim; narração da casa OPCIONAL, sai em 16:9 ou 9:16 vertical, e o filme final é limpo, sem rótulos de produção). Eles NÃO são gerados por este MCP: o user monta o spec na tela e um agente local (Claude Code, skill /film) produz o mp4 no repo da casa. Se o user pedir 'fita-ensaio' ou 'demo film' aqui, aponte pra tela e pro agente local.
|
|
207
|
+
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality | omni. Sem model, falha de cara. O 'omni' (Gemini Omni) gera clipe de 10s 720p com áudio nativo a partir de TEXTO (não aceita imagem/vídeo do user, ignora duração/resolução) e EDITA os próprios vídeos: passe editOfImageId com o imageId de um vídeo Omni já gerado e o prompt vira instrução de edição sobre a MESMA cena (troca item/personagem, preserva câmera e ambiente; cada edição debita como geração nova). É o caminho pra variações com continuidade: gera a base uma vez, edita N vezes. Vídeo é o mais caro: confirme com o usuário antes. action=shadows (ADMIN, 200 Sinapses/segundo, refund na falha): passa videoUrl (URL pública) + title (+ durationSec se souber, pra cobrar proporcional; sem ela, flat ~2000) e o servidor extrai a SOMBRA (mapa de profundidade) do vídeo e guarda no Acervo (Corpo) como deepshadow reutilizável (driving pro Shot Mimic/Kling Motion). Vitrine dos demos (sem custo): sapiens_video action=demos lista seus demo films com slug; action=showcase (slug + showcase=true/false + showcaseTag + showcaseOrder) cura o mini-cinema da /conectar-claude. FILMES DA CASA (Estúdio de Vídeo, tela /experimentos/films): são OUTRA coisa, três kinds na tabela videoSpecs: demo (UI clonada + câmera), aula-tour (telas reais + narração) e essay (fita-ensaio abstrata: partícula/tinta vira símbolo, com a logo explodindo no fim; narração da casa OPCIONAL, sai em 16:9 ou 9:16 vertical, e o filme final é limpo, sem rótulos de produção). Eles NÃO são gerados por este MCP: o user monta o spec na tela e um agente local (Claude Code, skill /film) produz o mp4 no repo da casa. Se o user pedir 'fita-ensaio' ou 'demo film' aqui, aponte pra tela e pro agente local.
|
|
202
208
|
|
|
203
209
|
Imagem (sapiens_image) action=generate: prompt + model + aspectRatio. Referência via referenceImageUrls (galeria/Acervo/personagens) e/ou sourceImageIds. templateSlug aplica um super-prompt travado da casa.
|
|
204
210
|
|
|
@@ -220,7 +226,7 @@ Mídia no Fórum (PADRÃO, faça sempre assim): a peça vai EMBEDADA num card es
|
|
|
220
226
|
Trilhas e Ritos de Fogo (sapiens_trilhas): 'list'/'get' pra navegar as trilhas; 'list_challenges' mostra os Ritos ativos + seu status; 'claim_mission' (missionId + proofText) envia a prova pra revisão do dono — o crédito em Sinapses sai na aprovação dele, não na hora. Não prometa Sinapse na hora do claim.
|
|
221
227
|
|
|
222
228
|
Voz da casa: 1ª pessoa, direto, anti-corporate, sem travessão. Pra bom entendedor, meia palavra basta.`;
|
|
223
|
-
const server = new Server({ name: "mcp-sapiens", version: "1.
|
|
229
|
+
const server = new Server({ name: "mcp-sapiens", version: "1.27.0" }, { capabilities: { tools: {} }, instructions: SAPIENS_INSTRUCTIONS });
|
|
224
230
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
225
231
|
tools: Object.entries(TOOLS).map(([name, t]) => ({
|
|
226
232
|
name,
|
|
@@ -253,4 +259,4 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
253
259
|
});
|
|
254
260
|
const transport = new StdioServerTransport();
|
|
255
261
|
await server.connect(transport);
|
|
256
|
-
console.error("mcp-sapiens v1.
|
|
262
|
+
console.error("mcp-sapiens v1.27.0 rodando via stdio (27 tools)");
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { convexAction, convexMutation, convexQuery, getSessionToken } from "../convexClient.js";
|
|
3
|
+
/**
|
|
4
|
+
* sapiens_instagram — o "ManyChat da casa" via MCP. ADMIN-ONLY (requireMcpAdmin
|
|
5
|
+
* no Convex): opera o auto-DM do Instagram da casa (regras de resposta
|
|
6
|
+
* automática, inbox das conversas, resposta manual pela janela de 24h).
|
|
7
|
+
* Espelha a UI /dashboard/admin/instagram; backend em convex/instagramDm.ts.
|
|
8
|
+
*
|
|
9
|
+
* Sub-actions:
|
|
10
|
+
* - rules: lista as regras (keyword, variações, escopo por post, disparos)
|
|
11
|
+
* - rule_upsert: cria/edita regra (ruleId presente = edita)
|
|
12
|
+
* - rule_delete: apaga regra por ruleId
|
|
13
|
+
* - inbox: threads recentes com a janela de 24h de cada (canReply)
|
|
14
|
+
* - thread: mensagens de uma conversa (igUserId do inbox)
|
|
15
|
+
* - send: responde uma conversa na mão (só com a janela aberta)
|
|
16
|
+
*/
|
|
17
|
+
export const instagramSchema = z.object({
|
|
18
|
+
action: z.enum(["rules", "rule_upsert", "rule_delete", "inbox", "thread", "send"]),
|
|
19
|
+
ruleId: z.string().optional().describe("Id da regra (rule_upsert pra editar, rule_delete)."),
|
|
20
|
+
keyword: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Keyword da regra (substring case-insensitive no texto da DM/comentário). Obrigatória em regra não-fallback."),
|
|
24
|
+
reply: z.string().optional().describe("Resposta na DM (obrigatória no rule_upsert)."),
|
|
25
|
+
replyVariants: z
|
|
26
|
+
.array(z.string())
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Variações da resposta; presentes, rodam em round-robin no lugar da reply."),
|
|
29
|
+
commentEcho: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Eco público no comentário depois da DM ('te respondi no direct!'). Só p/ comentário."),
|
|
33
|
+
echoVariants: z.array(z.string()).optional().describe("Variações do eco público (round-robin)."),
|
|
34
|
+
mediaId: z
|
|
35
|
+
.string()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Escopo por post: id de mídia do Instagram; a regra só casa comentário DESSE post."),
|
|
38
|
+
isFallback: z
|
|
39
|
+
.boolean()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Fallback: responde DM sem keyword (1x/24h por pessoa). Nunca dispara em comentário."),
|
|
42
|
+
active: z.boolean().optional().describe("Regra ativa (default true)."),
|
|
43
|
+
priority: z.number().optional().describe("Menor casa primeiro (default 100)."),
|
|
44
|
+
igUserId: z.string().optional().describe("IGSID da contraparte (vem do inbox). Pra thread e send."),
|
|
45
|
+
text: z.string().optional().describe("Texto da resposta manual (send)."),
|
|
46
|
+
limit: z.number().optional().describe("Máx de itens (inbox default 30, thread default 40)."),
|
|
47
|
+
});
|
|
48
|
+
function need(value, name) {
|
|
49
|
+
if (value === undefined || value === null) {
|
|
50
|
+
throw new Error(`Faltando arg "${name}" pra essa action.`);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
export async function instagram(args) {
|
|
55
|
+
const sessionToken = getSessionToken();
|
|
56
|
+
switch (args.action) {
|
|
57
|
+
case "rules":
|
|
58
|
+
return await convexQuery("instagramDm:mcpListRules", { sessionToken });
|
|
59
|
+
case "rule_upsert": {
|
|
60
|
+
const reply = need(args.reply, "reply");
|
|
61
|
+
return await convexMutation("instagramDm:mcpUpsertRule", {
|
|
62
|
+
sessionToken,
|
|
63
|
+
ruleId: args.ruleId,
|
|
64
|
+
keyword: args.keyword,
|
|
65
|
+
reply,
|
|
66
|
+
replyVariants: args.replyVariants,
|
|
67
|
+
commentEcho: args.commentEcho,
|
|
68
|
+
echoVariants: args.echoVariants,
|
|
69
|
+
mediaId: args.mediaId,
|
|
70
|
+
isFallback: args.isFallback,
|
|
71
|
+
active: args.active,
|
|
72
|
+
priority: args.priority,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
case "rule_delete":
|
|
76
|
+
return await convexMutation("instagramDm:mcpRemoveRule", {
|
|
77
|
+
sessionToken,
|
|
78
|
+
ruleId: need(args.ruleId, "ruleId"),
|
|
79
|
+
});
|
|
80
|
+
case "inbox":
|
|
81
|
+
return await convexQuery("instagramDm:mcpListThreads", {
|
|
82
|
+
sessionToken,
|
|
83
|
+
limit: args.limit,
|
|
84
|
+
});
|
|
85
|
+
case "thread":
|
|
86
|
+
return await convexQuery("instagramDm:mcpThreadMessages", {
|
|
87
|
+
sessionToken,
|
|
88
|
+
igUserId: need(args.igUserId, "igUserId"),
|
|
89
|
+
limit: args.limit,
|
|
90
|
+
});
|
|
91
|
+
case "send":
|
|
92
|
+
return await convexAction("instagramDm:mcpSendDm", {
|
|
93
|
+
sessionToken,
|
|
94
|
+
igUserId: need(args.igUserId, "igUserId"),
|
|
95
|
+
text: need(args.text, "text"),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/tools/video.js
CHANGED
|
@@ -13,6 +13,9 @@ import { convexAction, convexQuery, convexMutation, getSessionToken } from "../c
|
|
|
13
13
|
* - showcase: põe/tira um demo film (por slug) da vitrine /conectar-claude, com
|
|
14
14
|
* chip (showcaseTag) e ordem (showcaseOrder). Só entra na vitrine
|
|
15
15
|
* pública se for a conta da casa. Sem custo.
|
|
16
|
+
* - shadows: (ADMIN) extrai a SOMBRA (mapa de profundidade) de um vídeo por
|
|
17
|
+
* URL e guarda no Acervo (Corpo) como deepshadow reutilizável.
|
|
18
|
+
* 200 Sinapses/segundo (durationSec; sem ela, flat 2000). Refund se falhar.
|
|
16
19
|
*
|
|
17
20
|
* Modelos (action=create):
|
|
18
21
|
* - sapiens-video-seedance Seedance 2.0 — cena com áudio nativo, 4-15s, 480/720/1080p (t2v/i2v)
|
|
@@ -46,7 +49,16 @@ const VIDEO_MODELS = [
|
|
|
46
49
|
"sapiens-video-omni",
|
|
47
50
|
];
|
|
48
51
|
export const videoSchema = z.object({
|
|
49
|
-
action: z.enum(["create", "generate", "demos", "showcase"]),
|
|
52
|
+
action: z.enum(["create", "generate", "demos", "showcase", "shadows"]),
|
|
53
|
+
// --- action=shadows (deepshadows: extrai o mapa de profundidade de um vídeo) ---
|
|
54
|
+
videoUrl: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("action=shadows: URL pública (http/https) do vídeo-fonte. O servidor extrai a SOMBRA (depth) e guarda no Acervo (Corpo). ADMIN, 200 Sinapses/segundo (refund na falha)."),
|
|
58
|
+
title: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("action=shadows: nome do deepshadow (vira o slug no Acervo; re-extrair o mesmo título sobrescreve). Mín. 3 chars."),
|
|
50
62
|
// --- action=showcase (curadoria da vitrine /conectar-claude) ---
|
|
51
63
|
slug: z
|
|
52
64
|
.string()
|
|
@@ -78,7 +90,8 @@ export const videoSchema = z.object({
|
|
|
78
90
|
.number()
|
|
79
91
|
.optional()
|
|
80
92
|
.describe("action=create (modelos WaveSpeed): duração em segundos. Seedance/Shot Mimic 4-15, Kling 3-15, WAN 5/10. " +
|
|
81
|
-
"Sem isso usa a config mais barata. O preço escala com a duração."
|
|
93
|
+
"Sem isso usa a config mais barata. O preço escala com a duração. " +
|
|
94
|
+
"action=shadows: duração do vídeo-fonte, se souber (cobra 200/s; sem ela, flat ~2000)."),
|
|
82
95
|
resolution: z
|
|
83
96
|
.enum(["480p", "720p", "1080p"])
|
|
84
97
|
.optional()
|
|
@@ -181,6 +194,20 @@ export async function video(args) {
|
|
|
181
194
|
editOfImageId: args.editOfImageId,
|
|
182
195
|
});
|
|
183
196
|
}
|
|
197
|
+
if (args.action === "shadows") {
|
|
198
|
+
if (!args.videoUrl) {
|
|
199
|
+
throw new Error("action=shadows exige videoUrl (URL pública do vídeo-fonte).");
|
|
200
|
+
}
|
|
201
|
+
if (!args.title || args.title.trim().length < 3) {
|
|
202
|
+
throw new Error("action=shadows exige title (mín. 3 chars; vira o slug do deepshadow).");
|
|
203
|
+
}
|
|
204
|
+
return await convexAction("mcpExtrasActions:mcpExtractShadows", {
|
|
205
|
+
sessionToken,
|
|
206
|
+
videoUrl: args.videoUrl,
|
|
207
|
+
title: args.title,
|
|
208
|
+
durationSec: args.durationSec,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
184
211
|
if (args.action === "generate") {
|
|
185
212
|
if (!args.imageId) {
|
|
186
213
|
throw new Error("action=generate exige imageId (vídeo já criado no site).");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|