sapiens-mcp 1.11.2 → 1.13.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/character.js +191 -0
- package/dist/tools/gallery.js +15 -2
- package/dist/tools/image.js +5 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import { video, videoSchema } from "./tools/video.js";
|
|
|
21
21
|
import { write, writeSchema } from "./tools/write.js";
|
|
22
22
|
import { stockAudio, stockAudioSchema } from "./tools/stockAudio.js";
|
|
23
23
|
import { brand, brandSchema } from "./tools/brand.js";
|
|
24
|
+
import { character, characterSchema } from "./tools/character.js";
|
|
24
25
|
import { describeConvexError } from "./convexClient.js";
|
|
25
26
|
const TOOLS = {
|
|
26
27
|
sapiens_pipeline: {
|
|
@@ -44,7 +45,7 @@ const TOOLS = {
|
|
|
44
45
|
handler: repertorio,
|
|
45
46
|
},
|
|
46
47
|
sapiens_gallery: {
|
|
47
|
-
description: "Browse das imagens geradas pelo user (nanoBanana). Sub-actions: list (últimas N imagens, com prompt/model/url), get (1 imagem com metadados, opcionalmente base64). Use pra reusar imagem como referência (passe o imageId em sapiens_image mode=edit ou mode=variation)
|
|
48
|
+
description: "Browse e publicação das imagens geradas pelo user (nanoBanana). Sub-actions: list (últimas N imagens, com prompt/model/url + isPublic), get (1 imagem com metadados, opcionalmente base64), publish (torna a PRÓPRIA imagem pública: entra na galeria pública + feed Pinterest, e ganha página indexável /imagem/<id> se o modelo não for degen — devolve publicPageUrl), unpublish (volta a privada). Use list/get pra reusar imagem como referência (passe o imageId em sapiens_image mode=edit ou mode=variation) ou pra mostrar pro user o que ele já tem; publish quando o user quer divulgar a imagem dele.",
|
|
48
49
|
schema: gallerySchema,
|
|
49
50
|
handler: gallery,
|
|
50
51
|
},
|
|
@@ -113,8 +114,13 @@ const TOOLS = {
|
|
|
113
114
|
schema: brandSchema,
|
|
114
115
|
handler: brand,
|
|
115
116
|
},
|
|
117
|
+
sapiens_character: {
|
|
118
|
+
description: "Personagens (character sheets) do Sapiens — a tabela `influencers`: personagem reutilizável com imagens (pra character-lock em geração) + alma (systemPrompt), tudo amarrado à conta do dono do token (sem admin). Sub-actions: list_public (catálogo global de personagens públicos do Explorar; cada um traz mainImageUrl/imageUrls usáveis direto como referenceImageUrls em sapiens_image; sem custo, sem login), get (detalhe de 1 por characterId — público+ativo qualquer um vê, draft/privado só o dono; systemPrompt só volta pro dono), list_mine (os personagens do próprio user, inclui drafts/privados), create (cria rascunho na conta: name + gender + opcional title/systemPrompt), add_image (adiciona imagem ao próprio personagem via imageUrl público OU sourceImageId da galeria; 1ª vira principal), set_card (edita alma/título/nome do próprio), activate (publica, sai de draft, exige ≥1 imagem), set_visibility (isPublic true=Explorar+slug / false=privado). Fluxo de criação: create → add_image (1+) → set_card (opcional) → activate → set_visibility isPublic=true. Pra usar um personagem público como referência numa geração, pegue mainImageUrl em list_public/get e passe em sapiens_image referenceImageUrls.",
|
|
119
|
+
schema: characterSchema,
|
|
120
|
+
handler: character,
|
|
121
|
+
},
|
|
116
122
|
};
|
|
117
|
-
const server = new Server({ name: "mcp-sapiens", version: "1.
|
|
123
|
+
const server = new Server({ name: "mcp-sapiens", version: "1.13.0" }, { capabilities: { tools: {} } });
|
|
118
124
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
119
125
|
tools: Object.entries(TOOLS).map(([name, t]) => ({
|
|
120
126
|
name,
|
|
@@ -147,4 +153,4 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
147
153
|
});
|
|
148
154
|
const transport = new StdioServerTransport();
|
|
149
155
|
await server.connect(transport);
|
|
150
|
-
console.error("mcp-sapiens v1.
|
|
156
|
+
console.error("mcp-sapiens v1.13.0 rodando via stdio (19 tools)");
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { convexQuery, convexMutation, getSessionToken } from "../convexClient.js";
|
|
3
|
+
/**
|
|
4
|
+
* sapiens_character — personagens (character sheets) do Sapiens.
|
|
5
|
+
*
|
|
6
|
+
* "Character" aqui é a tabela `influencers`: personagem reutilizável com
|
|
7
|
+
* imagens (pra character-lock em geração) + alma (systemPrompt). Tudo amarrado
|
|
8
|
+
* à conta do dono do sessionToken. Sem nada de admin.
|
|
9
|
+
*
|
|
10
|
+
* Sub-actions:
|
|
11
|
+
* - list_public: catálogo global de personagens públicos (Explorar). Cada um
|
|
12
|
+
* traz mainImageUrl/imageUrls usáveis como referência em
|
|
13
|
+
* sapiens_image (referenceImageUrls). Sem custo.
|
|
14
|
+
* - get: detalhe de 1 personagem por id. Público+ativo: qualquer um.
|
|
15
|
+
* Draft/privado: só o dono. systemPrompt só volta pro dono.
|
|
16
|
+
* - list_mine: os personagens do próprio user (inclui drafts/privados).
|
|
17
|
+
* - create: cria um personagem (rascunho) na conta. name + gender.
|
|
18
|
+
* - add_image: adiciona imagem ao próprio personagem (imageUrl direto ou
|
|
19
|
+
* sourceImageId da galeria). 1ª imagem vira a principal.
|
|
20
|
+
* - set_card: edita a alma (systemPrompt), título e/ou nome do próprio.
|
|
21
|
+
* - activate: publica (sai de draft). Exige ≥1 imagem.
|
|
22
|
+
* - set_visibility: público (entra no Explorar, ganha slug) ou privado.
|
|
23
|
+
*
|
|
24
|
+
* Fluxo típico de criação: create → add_image (1+) → set_card (opcional) →
|
|
25
|
+
* activate → set_visibility isPublic=true.
|
|
26
|
+
*/
|
|
27
|
+
export const characterSchema = z.object({
|
|
28
|
+
action: z.enum([
|
|
29
|
+
"list_public",
|
|
30
|
+
"get",
|
|
31
|
+
"list_mine",
|
|
32
|
+
"create",
|
|
33
|
+
"add_image",
|
|
34
|
+
"set_card",
|
|
35
|
+
"activate",
|
|
36
|
+
"set_visibility",
|
|
37
|
+
]),
|
|
38
|
+
characterId: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("ID do personagem (influencers:_id). Obrigatório em get/add_image/set_card/activate/set_visibility. Descubra via list_public ou list_mine."),
|
|
42
|
+
limit: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Pra list_public: quantos retornar (default 40, max 100)."),
|
|
47
|
+
name: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Pra create (obrigatório) ou set_card (renomear): nome do personagem."),
|
|
51
|
+
gender: z
|
|
52
|
+
.string()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Pra create: 'masculino' | 'feminino' | 'nao-binario'. Default 'nao-binario'."),
|
|
55
|
+
title: z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("Pra create/set_card: subtítulo curto (ex: 'A guia do Sapiens')."),
|
|
59
|
+
systemPrompt: z
|
|
60
|
+
.string()
|
|
61
|
+
.optional()
|
|
62
|
+
.describe("Pra create/set_card: a 'alma' do personagem (personalidade, jeito de falar, contexto). Usado no chat e como guia de geração."),
|
|
63
|
+
imageUrl: z
|
|
64
|
+
.string()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Pra add_image: URL pública da imagem (Bunny CDN / Convex storage). Use a `url` que sapiens_image/sapiens_gallery devolvem."),
|
|
67
|
+
sourceImageId: z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("Pra add_image: alternativa ao imageUrl — ID de imagem da SUA galeria (generatedImages:_id, via sapiens_gallery action=list). O backend resolve a url e confere que é sua."),
|
|
71
|
+
isMain: z
|
|
72
|
+
.boolean()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Pra add_image: marca esta como a imagem principal (avatar). 1ª imagem já vira main sozinha."),
|
|
75
|
+
isPublic: z
|
|
76
|
+
.boolean()
|
|
77
|
+
.optional()
|
|
78
|
+
.describe("Pra set_visibility: true = público no Explorar (gera slug), false = privado."),
|
|
79
|
+
});
|
|
80
|
+
export async function character(args) {
|
|
81
|
+
// -------- list_public: catálogo global (sessionToken opcional, marca `mine`) --------
|
|
82
|
+
if (args.action === "list_public") {
|
|
83
|
+
let sessionToken;
|
|
84
|
+
try {
|
|
85
|
+
sessionToken = getSessionToken();
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
sessionToken = undefined; // catálogo público funciona sem login
|
|
89
|
+
}
|
|
90
|
+
return await convexQuery("influencers:mcpListPublicCharacters", {
|
|
91
|
+
sessionToken,
|
|
92
|
+
limit: args.limit,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// -------- get: detalhe de 1 personagem --------
|
|
96
|
+
if (args.action === "get") {
|
|
97
|
+
if (!args.characterId) {
|
|
98
|
+
throw new Error("action=get exige characterId (pegue via list_public ou list_mine).");
|
|
99
|
+
}
|
|
100
|
+
let sessionToken;
|
|
101
|
+
try {
|
|
102
|
+
sessionToken = getSessionToken();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
sessionToken = undefined;
|
|
106
|
+
}
|
|
107
|
+
const res = await convexQuery("influencers:mcpGetCharacter", {
|
|
108
|
+
sessionToken,
|
|
109
|
+
characterId: args.characterId,
|
|
110
|
+
});
|
|
111
|
+
if (!res) {
|
|
112
|
+
throw new Error(`Personagem "${args.characterId}" não encontrado (ou é privado de outro user).`);
|
|
113
|
+
}
|
|
114
|
+
return res;
|
|
115
|
+
}
|
|
116
|
+
// -------- list_mine: personagens do próprio user (inclui drafts) --------
|
|
117
|
+
if (args.action === "list_mine") {
|
|
118
|
+
const sessionToken = getSessionToken();
|
|
119
|
+
return await convexQuery("influencers:mcpListMyCharacters", { sessionToken });
|
|
120
|
+
}
|
|
121
|
+
// -------- create: novo rascunho na conta --------
|
|
122
|
+
if (args.action === "create") {
|
|
123
|
+
if (!args.name || !args.name.trim()) {
|
|
124
|
+
throw new Error("action=create exige 'name'.");
|
|
125
|
+
}
|
|
126
|
+
const sessionToken = getSessionToken();
|
|
127
|
+
return await convexMutation("influencers:mcpCreateCharacter", {
|
|
128
|
+
sessionToken,
|
|
129
|
+
name: args.name,
|
|
130
|
+
gender: args.gender,
|
|
131
|
+
title: args.title,
|
|
132
|
+
systemPrompt: args.systemPrompt,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// -------- add_image: imagem no próprio personagem --------
|
|
136
|
+
if (args.action === "add_image") {
|
|
137
|
+
if (!args.characterId)
|
|
138
|
+
throw new Error("action=add_image exige characterId.");
|
|
139
|
+
if (!args.imageUrl && !args.sourceImageId) {
|
|
140
|
+
throw new Error("action=add_image exige 'imageUrl' ou 'sourceImageId'.");
|
|
141
|
+
}
|
|
142
|
+
const sessionToken = getSessionToken();
|
|
143
|
+
return await convexMutation("influencers:mcpAddCharacterImage", {
|
|
144
|
+
sessionToken,
|
|
145
|
+
characterId: args.characterId,
|
|
146
|
+
imageUrl: args.imageUrl,
|
|
147
|
+
sourceImageId: args.sourceImageId,
|
|
148
|
+
isMain: args.isMain,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// -------- set_card: alma/título/nome do próprio personagem --------
|
|
152
|
+
if (args.action === "set_card") {
|
|
153
|
+
if (!args.characterId)
|
|
154
|
+
throw new Error("action=set_card exige characterId.");
|
|
155
|
+
if (args.systemPrompt === undefined && args.title === undefined && args.name === undefined) {
|
|
156
|
+
throw new Error("action=set_card precisa de pelo menos um: systemPrompt, title ou name.");
|
|
157
|
+
}
|
|
158
|
+
const sessionToken = getSessionToken();
|
|
159
|
+
return await convexMutation("influencers:mcpSetCharacterCard", {
|
|
160
|
+
sessionToken,
|
|
161
|
+
characterId: args.characterId,
|
|
162
|
+
systemPrompt: args.systemPrompt,
|
|
163
|
+
title: args.title,
|
|
164
|
+
name: args.name,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// -------- activate: publica (sai de draft, exige ≥1 imagem) --------
|
|
168
|
+
if (args.action === "activate") {
|
|
169
|
+
if (!args.characterId)
|
|
170
|
+
throw new Error("action=activate exige characterId.");
|
|
171
|
+
const sessionToken = getSessionToken();
|
|
172
|
+
return await convexMutation("influencers:mcpActivateCharacter", {
|
|
173
|
+
sessionToken,
|
|
174
|
+
characterId: args.characterId,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// -------- set_visibility: público (Explorar) ou privado --------
|
|
178
|
+
if (args.action === "set_visibility") {
|
|
179
|
+
if (!args.characterId)
|
|
180
|
+
throw new Error("action=set_visibility exige characterId.");
|
|
181
|
+
if (args.isPublic === undefined) {
|
|
182
|
+
throw new Error("action=set_visibility exige isPublic (true=público, false=privado).");
|
|
183
|
+
}
|
|
184
|
+
const sessionToken = getSessionToken();
|
|
185
|
+
return await convexMutation("influencers:mcpSetCharacterVisibility", {
|
|
186
|
+
sessionToken,
|
|
187
|
+
characterId: args.characterId,
|
|
188
|
+
isPublic: args.isPublic,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
package/dist/tools/gallery.js
CHANGED
|
@@ -8,9 +8,10 @@ import { convexAction, getSessionToken } from "../convexClient.js";
|
|
|
8
8
|
* - Listar imagens recentes do user (pra reusar como referenceImage)
|
|
9
9
|
* - Pegar bytes de uma imagem pra mostrar inline no Claude
|
|
10
10
|
* - Descobrir imageId pra passar como sourceImageId em sapiens_image edit/variation
|
|
11
|
+
* - Publicar/despublicar a própria imagem (galeria pública + feed Pinterest)
|
|
11
12
|
*/
|
|
12
13
|
export const gallerySchema = z.object({
|
|
13
|
-
action: z.enum(["list", "get"]),
|
|
14
|
+
action: z.enum(["list", "get", "publish", "unpublish"]),
|
|
14
15
|
limit: z
|
|
15
16
|
.number()
|
|
16
17
|
.int()
|
|
@@ -25,7 +26,7 @@ export const gallerySchema = z.object({
|
|
|
25
26
|
imageId: z
|
|
26
27
|
.string()
|
|
27
28
|
.optional()
|
|
28
|
-
.describe("generatedImages:_id (obrigatório pra action=get)"),
|
|
29
|
+
.describe("generatedImages:_id (obrigatório pra action=get/publish/unpublish)"),
|
|
29
30
|
includeBase64: z
|
|
30
31
|
.boolean()
|
|
31
32
|
.optional()
|
|
@@ -54,4 +55,16 @@ export async function gallery(args) {
|
|
|
54
55
|
includeBase64: args.includeBase64 ?? false,
|
|
55
56
|
});
|
|
56
57
|
}
|
|
58
|
+
// publish/unpublish: liga/desliga isPublic na própria imagem. Public = entra
|
|
59
|
+
// na galeria pública + feed Pinterest (e /imagem/<id> se não for degen).
|
|
60
|
+
if (args.action === "publish" || args.action === "unpublish") {
|
|
61
|
+
if (!args.imageId) {
|
|
62
|
+
throw new Error(`action=${args.action} exige imageId. Use action=list pra descobrir.`);
|
|
63
|
+
}
|
|
64
|
+
return await convexAction("desktopMcp:gallerySetPublic", {
|
|
65
|
+
sessionToken,
|
|
66
|
+
imageId: args.imageId,
|
|
67
|
+
isPublic: args.action === "publish",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
57
70
|
}
|
package/dist/tools/image.js
CHANGED
|
@@ -8,6 +8,9 @@ const MODELS = [
|
|
|
8
8
|
"nano-banana-2", // gemini-3.1-flash-image-preview (V2, Flash 3.1) · 450 + adder · COM refs · DEFAULT
|
|
9
9
|
"gpt-image-2-low", // Azure gpt-image-2 quality=low · 250
|
|
10
10
|
"gpt-image-2-high", // Azure gpt-image-2 quality=high · 800
|
|
11
|
+
// xAI Grok Imagine. Moderação frouxa (+18), aceita refs (img2img) + aspect.
|
|
12
|
+
"grok-2-image", // grok-imagine-image · 450 + adder 2K · COM refs
|
|
13
|
+
"grok-2-image-quality", // grok-imagine-image-quality, mais fiel pra character lock · 900 + adder 2K · COM refs
|
|
11
14
|
// Degen (uncensored, gate +18 na galeria). WaveSpeed = rápido (6-25s):
|
|
12
15
|
"wavespeed-chroma", // Chroma uncensored fotorrealista · 600
|
|
13
16
|
"wavespeed-flux2", // Flux.2 Klein 9B · 600
|
|
@@ -24,7 +27,7 @@ export const imageSchema = z.object({
|
|
|
24
27
|
model: z
|
|
25
28
|
.enum(MODELS)
|
|
26
29
|
.optional()
|
|
27
|
-
.describe("Default 'nano-banana-2' (Flash 3.1 com refs). 'nano-banana-max' (Pro 3) = qualidade alta. 'gpt-image-2-low/high' = Azure. DEGEN (uncensored, gate +18): 'wavespeed-chroma' (fotorrealista rápido), 'wavespeed-flux2' (Flux.2 Klein), 'wavespeed-flux-nsfw' (flux+LoRA NSFW) = WaveSpeed rápido; 'civitai-wai-illustrious'/'civitai-nova-anime-xl' (anime), 'civitai-pony-v6' (Pony V6 XL, base nº1) = Civitai sdcpp rápido."),
|
|
30
|
+
.describe("Default 'nano-banana-2' (Flash 3.1 com refs). 'nano-banana-max' (Pro 3) = qualidade alta. 'gpt-image-2-low/high' = Azure. 'grok-2-image'/'grok-2-image-quality' = xAI Grok Imagine (moderação frouxa +18, aceita refs e aspect; quality é mais fiel pra character lock). DEGEN (uncensored, gate +18): 'wavespeed-chroma' (fotorrealista rápido), 'wavespeed-flux2' (Flux.2 Klein), 'wavespeed-flux-nsfw' (flux+LoRA NSFW) = WaveSpeed rápido; 'civitai-wai-illustrious'/'civitai-nova-anime-xl' (anime), 'civitai-pony-v6' (Pony V6 XL, base nº1) = Civitai sdcpp rápido."),
|
|
28
31
|
aspectRatio: z
|
|
29
32
|
.enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"])
|
|
30
33
|
.optional()
|
|
@@ -41,7 +44,7 @@ export const imageSchema = z.object({
|
|
|
41
44
|
referenceImageUrls: z
|
|
42
45
|
.array(z.string())
|
|
43
46
|
.optional()
|
|
44
|
-
.describe("URLs públicas (Convex storage / Bunny CDN / Wikimedia) usadas como reference images. Trava character/style entre múltiplas gerações. Requer model com supportsReferences=true (nano-banana-2
|
|
47
|
+
.describe("URLs públicas (Convex storage / Bunny CDN / Wikimedia) usadas como reference images. Trava character/style entre múltiplas gerações. Requer model com supportsReferences=true (nano-banana-2, gpt-image-2-* ou grok-2-image*)."),
|
|
45
48
|
brandSlug: z
|
|
46
49
|
.string()
|
|
47
50
|
.optional()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.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": {
|