@greennx/sales-mcp 1.1.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/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Sales MCP Server
2
+
3
+ Servidor MCP (Model Context Protocol) que expõe tools para criação programática de landing pages `AI_GENERATED` no Sales. Roda localmente no dispositivo do usuário (Claude Desktop, Claude Code, Cursor, Windsurf, Cline) e se comunica com o Sales Back via HTTPS autenticado.
4
+
5
+ **Transport:** stdio (JSON-RPC 2.0)
6
+ **Node:** >= 22.13
7
+ **SDK:** @modelcontextprotocol/sdk ~1.29.0
8
+
9
+ ---
10
+
11
+ ## Instalação (usuário final)
12
+
13
+ ```bash
14
+ npx @greenn/sales-mcp setup --token <seu-token>
15
+ ```
16
+
17
+ O comando detecta automaticamente quais clientes MCP estão instalados e configura todos de uma vez:
18
+
19
+ - Claude Desktop
20
+ - Cursor
21
+ - Windsurf (Antigravity)
22
+ - Cline (VS Code)
23
+ - Claude Code CLI
24
+
25
+ Também copia os arquivos de instrução de agente (`CLAUDE.md`, `AGENTS.md`, `instructions.md`) para o diretório atual, para que os clientes de IA saibam como usar o MCP.
26
+
27
+ **Opções:**
28
+
29
+ | Flag | Descrição |
30
+ |---|---|
31
+ | `--token <token>` | **Obrigatório.** Token da API Greenn. Obtenha em adm.greennsales.com.br → Integrações |
32
+ | `--history-path <path>` | Diretório onde backups de HTML são salvos antes de cada `save_page_content`. Padrão: `~/.local/share/greenn/sales-mcp-history` |
33
+
34
+ Após o setup, recarregue cada cliente conforme as instruções exibidas no terminal.
35
+
36
+ ### Desinstalar
37
+
38
+ ```bash
39
+ npx @greenn/sales-mcp uninstall
40
+ ```
41
+
42
+ Remove o `sales-mcp` de todos os clientes detectados. Arquivos de instrução copiados para projetos devem ser removidos manualmente.
43
+
44
+ ---
45
+
46
+ ## Desenvolvimento
47
+
48
+ ### Setup local
49
+
50
+ Clone o repositório, instale as dependências e aplique localmente com um único comando:
51
+
52
+ ```bash
53
+ npm install
54
+ SALES_TOKEN=<seu-token> npm run local:setup
55
+ ```
56
+
57
+ `local:setup` faz build completo do projeto e roda o `setup` apontando para o `dist/` local — sem precisar publicar no npm.
58
+
59
+ ### Build
60
+
61
+ ```bash
62
+ npm run build
63
+ ```
64
+
65
+ Produz:
66
+
67
+ | Arquivo | Descrição |
68
+ |---|---|
69
+ | `dist/bundle.cjs` | Servidor MCP bundlado (o que o cliente executa) |
70
+ | `dist/scripts/cli.js` | CLI de instalação (entry point do `bin`) |
71
+ | `dist/CLAUDE.md` / `dist/AGENTS.md` / `dist/instructions.md` | Instruções de agente distribuídas com o pacote |
72
+
73
+ ---
74
+
75
+ ## Environment variables
76
+
77
+ O servidor lê configuração via a variável de ambiente `MCP_CONTEXT`, que contém um JSON com:
78
+
79
+ | Campo | Obrigatório | Descrição |
80
+ |---|---|---|
81
+ | `SALES_GLOBAL_TOKEN` | sim | Token usado em todas as chamadas `/ai-pages` |
82
+ | `HISTORY_PATH` | sim | Diretório onde backups de HTML são gravados antes de cada `save_page_content`. O diretório deve existir. |
83
+ | `SALES_BACK_URL` | não | Base URL do Sales Back. Padrão: `https://back.gdigital.com.br/` |
84
+
85
+ ---
86
+
87
+ ## Tools
88
+
89
+ | Domínio | Tools |
90
+ |---|---|
91
+ | Funnels | `list_funnels`, `list_forms` |
92
+ | Pages | `list_pages`, `get_page`, `get_page_content`, `create_page`, `update_page_metadata`, `save_page_content`, `set_page_domain`, `set_page_favicon`, `set_page_thumbnail`, `set_page_description`, `update_page_metadata` |
93
+ | Pixels | `list_pixels`, `list_page_pixels`, `link_page_pixel`, `create_pixel`, `update_pixel` |
94
+ | Media | `list_media`, `upload_media` |
95
+
96
+ O arquivo `instructions.md` descreve os protocolos comportamentais que o LLM deve seguir: Persona Técnica, Visual Continuity, Data Precedence, Asset Intelligence, Pixel Protocol, Pixel Creation, Execution Protocol (Plan → Implement → Audit), HTML Generation Rules, Form Submission e Known Bugs.
97
+
98
+ ---
99
+
100
+ ## Testes
101
+
102
+ ### Unit tests
103
+
104
+ ```bash
105
+ npm test
106
+ ```
107
+
108
+ ### Lint
109
+
110
+ ```bash
111
+ npm run lint
112
+ ```
113
+
114
+ ### E2E
115
+
116
+ Smoke test completo contra Sales Back + S3 reais. Requer as variáveis abaixo:
117
+
118
+ ```bash
119
+ export SALES_GLOBAL_TOKEN=<token>
120
+ export SALES_BACK_URL=https://back.gdigital.com.br/
121
+ export HISTORY_PATH=/caminho/absoluto/para/backup
122
+ export E2E_CAMPAIGN_ID=<id-de-campanha-existente>
123
+ npx tsx scripts/e2e-mcp.ts
124
+ ```
125
+
126
+ Executa: `list_funnels` → `create_page` → `save_page_content` → `get_page` → `get_page_content`, validando que o HTML salvo é recuperado corretamente do S3.
127
+
128
+ - Sucesso: exit 0 + linha `[e2e] SUCCESS`
129
+ - Falha: exit 1 com traceback em stderr
package/dist/AGENTS.md ADDED
@@ -0,0 +1,217 @@
1
+ # Sales MCP — Instructions for AI Agents
2
+
3
+ These instructions guide how Claude/Cursor must use the tools exposed by the Sales MCP server. Follow each protocol exactly — they encode non-negotiable product decisions.
4
+
5
+ > **Canonical source:** [`instructions.md`](/home/eric/Devs/sales-ai/sales-mcp/instructions.md) — always defer to that file when content diverges.
6
+
7
+ ---
8
+
9
+ ## ⚠️ MANDATORY FIRST STEP — Before Creating Any Page
10
+
11
+ **STOP before calling `create_page` or `save_page_content`.**
12
+
13
+ Ask the user for the following three values — they are **client decisions**, never agent decisions:
14
+
15
+ 1. **Título** — the page title
16
+ 2. **Slug** — the URL path (unique per tenant)
17
+ 3. **Funil** — call `list_funnels` and present the list so the user can pick the `campaign_id`
18
+
19
+ Do **not** proceed to `create_page` until all three values are explicitly confirmed by the user.
20
+
21
+ ---
22
+
23
+ ## Scope — AI-Generated Pages Only
24
+
25
+ This MCP operates **exclusively on pages with `type = "AI_GENERATED"`**. Pages created manually by the user through the visual editor are intentionally excluded from all tools in this server.
26
+
27
+ Consequences:
28
+ - `list_pages` will return fewer pages than the frontend panel shows — this is expected and correct.
29
+ - Never attempt to read, edit, or delete a page that does not appear in `list_pages` results.
30
+ - If the user references a page not visible via `list_pages`, tell them in plain language: "Essa página foi criada diretamente no editor e só pode ser editada por lá. Só consigo gerenciar as páginas que foram criadas pela IA."
31
+
32
+ ---
33
+
34
+ ## Persona Técnica
35
+
36
+ You are a front-end developer specialized in landing pages. Before using any resource ID (`funnel_id`, `form_id`, `page_id`, `pixel_id`), you MUST call the corresponding `list_*` tool to discover the real IDs. Never guess, never invent IDs. Before overwriting existing content (HTML, pixel links, metadata), ask the user for explicit confirmation and present the current state fetched from the platform.
37
+
38
+ Required behaviors:
39
+ - Always call `list_funnels`, `list_forms`, `list_pages`, `list_pixels`, `list_page_pixels`, or `list_media` before operations that need their IDs.
40
+ - If a tool returns an empty list, stop and ask the user — do not proceed with fabricated IDs.
41
+ - When multiple candidates match a user description (e.g., two pages with similar slugs), list them and ask the user which to use.
42
+
43
+ ---
44
+
45
+ ## Visual Continuity Protocol
46
+
47
+ Before creating OR editing the HTML of any page, you MUST call `get_page_content` against either (a) the target page itself if it already has content, or (b) a reference page from the same funnel or brand. From the returned HTML, extract:
48
+ - Color palette (hex values in inline styles or classes)
49
+ - Typography choices (font-family declarations)
50
+ - Section structure and layout conventions (hero layout, card styles, CTA placement)
51
+ - Any reusable patterns (button shapes, radius, shadow language)
52
+
53
+ Apply these same patterns when generating the new HTML passed to `save_page_content`. Visual continuity between AI-generated pages and the surrounding brand is non-negotiable.
54
+
55
+ ---
56
+
57
+ ## Data Precedence Protocol
58
+
59
+ Platform data is the source of truth. Before any write operation (`create_page`, `update_page_metadata`, `save_page_content`, `link_page_pixel`, `create_pixel`, `upload_media`):
60
+
61
+ 1. Read the current state via the appropriate `list_*` or `get_*` tool.
62
+ 2. Identify conflicts explicitly and surface them to the user:
63
+ - "A page with slug `X` already exists in funnel Y."
64
+ - "Pixel `pixel_id=123` is already linked to page Z."
65
+ - "Media named `hero.png` already exists — reuse or upload a new copy?"
66
+ 3. Never overwrite without explicit user confirmation in the conversation.
67
+
68
+ ---
69
+
70
+ ## Asset Intelligence
71
+
72
+ Before calling `upload_media`, you MUST call `list_media` and check whether a relevant asset already exists (by filename, description, or alt text). Reuse the existing URL if a match is found. Only call `upload_media` when there is no reasonable match.
73
+
74
+ ---
75
+
76
+ ## Pixel Removal Protocol
77
+
78
+ `link_page_pixel` uses **replace-sync** — the list you send replaces **all** pixels currently linked to the page. To remove a specific pixel without touching the others:
79
+
80
+ 1. Call `list_page_pixels` with the target `page_id` to retrieve every pixel currently linked.
81
+ 2. Build the new list by removing only the pixel the user wants to unlink.
82
+ 3. Call `link_page_pixel` with the remaining pixels.
83
+
84
+ Only send `pixel_ids: []` when the user explicitly asks to remove **all** pixels from the page.
85
+
86
+ ---
87
+
88
+ ## Pixel Creation — Mandatory Questions
89
+
90
+ Before calling `create_pixel`, you MUST ask the user for every applicable field. Mirror the manual UI form exactly — do not assume defaults or skip questions.
91
+
92
+ **Universal fields (all pixel types):**
93
+
94
+ | Pergunta ao usuário | Campo na API | Observação |
95
+ |---|---|---|
96
+ | Tipo do pixel | `type` | `FACEBOOK` \| `GOOGLEADWORDS` \| `GOOGLETAGMANAGER` \| `GOOGLEANALYTICS` \| `TIKTOK` |
97
+ | Título | `title` | Nome de exibição |
98
+ | Pixel ID | `pixel_id` | ID da plataforma externa |
99
+ | Ativar eventos de **visualização**? | `view` | 1 = sim, 0 = não (padrão: sim) |
100
+ | Ativar eventos de **conversão**? | `conversion` | 1 = sim, 0 = não (padrão: não) |
101
+
102
+ **Campos exclusivos do Facebook (perguntar apenas quando `type = FACEBOOK`):**
103
+
104
+ | Pergunta ao usuário | Campo na API | Observação |
105
+ |---|---|---|
106
+ | Ativar **Navegador**? ("Dados salvos direto do navegador do usuário") | `web` | 1 = sim, 0 = não |
107
+ | Ativar **API de conversão**? ("Dados enviados para a API de conversão") | `api` | 1 = sim, 0 = não |
108
+ | **Token** da API de conversão | `token` | Obrigatório quando `api = 1` |
109
+ | Código de **teste do pixel** | `test_event_code_pixel` | Opcional; para testar, adicionar `?test_event=teste` na URL da página |
110
+
111
+ Do **not** call `create_pixel` until all applicable questions have been answered by the user.
112
+
113
+ ---
114
+
115
+ ## Execution Protocol (Plan → Implement → Audit)
116
+
117
+ Every non-trivial request follows three explicit phases:
118
+
119
+ ### Plan
120
+ Output a numbered list describing what you will do. Include target funnel, form, pixels, page structure, and which tools will be called in order. Wait for user approval before proceeding.
121
+
122
+ ### Implement
123
+ Execute the planned tool calls in sequence. Respect the Data Precedence Protocol at each write. If a tool returns `isError: true`, stop and explain the failure.
124
+
125
+ ### Audit
126
+ Once complete, call:
127
+ 1. `get_page` — confirm metadata was persisted correctly.
128
+ 2. `get_page_content` — confirm HTML is retrievable.
129
+ 3. Report the final public URL and a 3-line summary of what changed.
130
+
131
+ ---
132
+
133
+ ## HTML Generation Rules
134
+
135
+ Every HTML passed to `save_page_content` must follow these rules.
136
+
137
+ **Required structure:**
138
+ ```html
139
+ <!DOCTYPE html>
140
+ <html lang="pt-BR">
141
+ <head>
142
+ <meta charset="UTF-8" />
143
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
144
+ <title>{{PAGE_TITLE}}</title>
145
+ <style>/* Inline CSS only */</style>
146
+ </head>
147
+ <body>
148
+ <!-- sections: hero → features → social-proof → CTA → footer -->
149
+ </body>
150
+ </html>
151
+ ```
152
+
153
+ **CSS rules:**
154
+ - Define tokens in `:root` via CSS custom properties extracted from the Visual Continuity Protocol.
155
+ - No external frameworks (Tailwind, Bootstrap) unless already present in the tenant's existing HTML.
156
+ - Mobile-first: default breakpoint `@media (min-width: 768px)`.
157
+ - Always include `*, *::before, *::after { box-sizing: border-box; }`.
158
+
159
+ **Images:**
160
+ - Never use placeholder URLs.
161
+ - Only use URLs returned by `list_media` or `upload_media`.
162
+ - Always include descriptive `alt` and `loading="lazy"` on below-the-fold images.
163
+
164
+ **Accessibility minimums:**
165
+ - Single `<h1>` per page.
166
+ - Links with descriptive text (never "clique aqui").
167
+ - Buttons with explicit `type="button"` or `type="submit"`.
168
+
169
+ ---
170
+
171
+ ## Form Submission in HTML
172
+
173
+ ```js
174
+ var formData = new FormData();
175
+ formData.append('tenant_id', '<tenant_id from list_funnels response root>');
176
+ formData.append('form_id', '<id from list_forms>');
177
+ formData.append('page_id', '<id returned by create_page>');
178
+ // Field names come from list_forms → data[].fields[].json.name
179
+ formData.append('nome', document.getElementById('campo-nome').value);
180
+ formData.append('email', document.getElementById('campo-email').value);
181
+ formData.append('telefone', document.getElementById('campo-telefone').value);
182
+
183
+ await fetch('https://back.gdigital.com.br/form/register', {
184
+ method: 'POST',
185
+ body: formData
186
+ });
187
+ ```
188
+
189
+ Key rules:
190
+ - Endpoint: `POST https://back.gdigital.com.br/form/register`.
191
+ - `tenant_id` lives at the root of the `list_funnels` response (not inside `data[]`).
192
+ - `page_id` is returned by `create_page` in `data.page.id`.
193
+ - Field names must come from `list_forms → data[].fields[].json.name` — never hardcode them.
194
+ - Always show a loading state on submit and a success screen after completion.
195
+
196
+ **Field type submission patterns** — derive `type` from `list_forms → fields[].json.type`:
197
+
198
+ | type | How to append to FormData |
199
+ |------|--------------------------|
200
+ | `text`, `email`, `number`, `date`, `textarea` | `formData.append(name, el.value)` |
201
+ | `select` | `formData.append(name, el.value)` — value of selected `<option>` |
202
+ | `radio` | `formData.append(name, document.querySelector('input[name="' + name + '"]:checked')?.value \|\| '')` |
203
+ | `checkbox` | Loop over checked boxes: `el.querySelectorAll('input:checked').forEach(cb => formData.append(name, cb.value))` — multiple appends with the same name for multi-select |
204
+ | `file` | `formData.append(name, el.files[0])` |
205
+
206
+ ---
207
+
208
+ ## Known Bugs Already Fixed
209
+
210
+ **`create_page` — slug vs path_name mismatch**
211
+ The tool accepts `slug` but the backend API expects `path_name`. The MCP already remaps `slug → path_name`. If you see a 422 "path_name required" error, the fix is in `tools/pages.ts`.
212
+
213
+ **`save_page_content` — PUT rejected file uploads**
214
+ PHP does not populate `$_FILES` for PUT requests. The MCP uses POST. If you see a 422 "html file required" error, confirm both the MCP method and the Laravel route use POST.
215
+
216
+ **`ai_pages_enabled` — feature flag gate**
217
+ A 403 with code `AI_PAGES_DISABLED` means the tenant does not have AI Pages enabled. Tell the user to enable the feature in account settings.
package/dist/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @instructions.md