verbo-mcp-server 0.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,114 @@
1
+ # @verbo/mcp-server
2
+
3
+ AI-powered WhatsApp agent for developers. Set up your agent, connect WhatsApp, send messages, and manage conversations — all from Claude Code, Cursor, or any MCP client.
4
+
5
+ ## Quick Start
6
+
7
+ ### 1. Get your API key
8
+
9
+ Sign up at [verbolab.co/developers](https://verbolab.co/developers) and create an API key.
10
+
11
+ ### 2. Configure your MCP client
12
+
13
+ **Claude Code / Cursor** — add to `.mcp.json`:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "verbo": {
19
+ "command": "npx",
20
+ "args": ["@verbo/mcp-server"],
21
+ "env": {
22
+ "VERBO_API_KEY": "vb_live_..."
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ ### 3. Set up your agent
30
+
31
+ Just tell your AI assistant what you want. Example conversation:
32
+
33
+ ```
34
+ You: "Set up a Verbo agent for meusite.com.br"
35
+ → Crawls your site, extracts business info, FAQ, tone of voice
36
+
37
+ You: "Connect WhatsApp"
38
+ → Creates instance, gives you a URL to scan the QR code
39
+
40
+ You: "What's the setup status?"
41
+ → Shows checklist: account ✅, config ✅, whatsapp ✅, agent ✅
42
+
43
+ You: "Send a test message to +5511999999999: Oi, tudo bem?"
44
+ → Delivers via WhatsApp
45
+
46
+ You: "Disconnect WhatsApp"
47
+ → Frees your number immediately
48
+ ```
49
+
50
+ ## Available Tools
51
+
52
+ ### Setup
53
+
54
+ | Tool | Description |
55
+ |------|-------------|
56
+ | `verbo_setup_crawl` | Crawl a website to auto-configure the agent (name, FAQ, hours, tone) |
57
+ | `verbo_setup_connect` | Start WhatsApp connection — returns URL to scan QR code |
58
+ | `verbo_setup_status` | Check setup progress (account, config, whatsapp, agent) |
59
+ | `verbo_setup_disconnect` | Disconnect WhatsApp, free the phone number |
60
+
61
+ ### Operations
62
+
63
+ | Tool | Description |
64
+ |------|-------------|
65
+ | `verbo_send_message` | Send WhatsApp text or image message |
66
+ | `verbo_list_conversations` | List recent conversations (filter by status) |
67
+ | `verbo_get_conversation` | Get conversation details and messages |
68
+ | `verbo_agent_status` | Check WhatsApp connection + agent config |
69
+ | `verbo_configure_agent` | Update greeting, FAQ, business hours |
70
+
71
+ ## REST API
72
+
73
+ All tools are backed by a REST API you can call directly:
74
+
75
+ ```bash
76
+ # Crawl website to configure agent
77
+ curl -X POST https://verbolab.co/api/v1/setup/crawl \
78
+ -H "Authorization: Bearer vb_live_..." \
79
+ -H "Content-Type: application/json" \
80
+ -d '{"url": "meusite.com.br"}'
81
+
82
+ # Connect WhatsApp
83
+ curl -X POST https://verbolab.co/api/v1/setup/connect \
84
+ -H "Authorization: Bearer vb_live_..."
85
+
86
+ # Check setup status
87
+ curl https://verbolab.co/api/v1/setup/status \
88
+ -H "Authorization: Bearer vb_live_..."
89
+
90
+ # Send message
91
+ curl -X POST https://verbolab.co/api/v1/messages \
92
+ -H "Authorization: Bearer vb_live_..." \
93
+ -H "Content-Type: application/json" \
94
+ -d '{"to": "+5511999999999", "message": "Hello!"}'
95
+
96
+ # List conversations
97
+ curl https://verbolab.co/api/v1/conversations \
98
+ -H "Authorization: Bearer vb_live_..."
99
+
100
+ # Agent status
101
+ curl https://verbolab.co/api/v1/agent/status \
102
+ -H "Authorization: Bearer vb_live_..."
103
+
104
+ # Disconnect WhatsApp
105
+ curl -X POST https://verbolab.co/api/v1/setup/disconnect \
106
+ -H "Authorization: Bearer vb_live_..."
107
+ ```
108
+
109
+ ## Environment Variables
110
+
111
+ | Variable | Required | Description |
112
+ |----------|----------|-------------|
113
+ | `VERBO_API_KEY` | Yes | Your API key from verbolab.co/developers |
114
+ | `VERBO_API_URL` | No | Custom API URL (default: https://verbolab.co) |
@@ -0,0 +1,22 @@
1
+ export declare class VerboClient {
2
+ private baseUrl;
3
+ private apiKey;
4
+ constructor(apiKey: string, baseUrl?: string);
5
+ private request;
6
+ sendMessage(to: string, message: string, imageUrl?: string): Promise<unknown>;
7
+ listConversations(options?: {
8
+ status?: string;
9
+ limit?: number;
10
+ }): Promise<unknown>;
11
+ getConversation(id: string): Promise<unknown>;
12
+ getAgentStatus(): Promise<unknown>;
13
+ configureAgent(config: {
14
+ greetingMessage?: string;
15
+ faqData?: Record<string, string>[];
16
+ businessHours?: Record<string, unknown>;
17
+ }): Promise<unknown>;
18
+ setupCrawl(url: string): Promise<unknown>;
19
+ setupConnect(): Promise<unknown>;
20
+ setupStatus(): Promise<unknown>;
21
+ setupDisconnect(): Promise<unknown>;
22
+ }
package/dist/client.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ // packages/mcp-server/src/client.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.VerboClient = void 0;
5
+ class VerboClient {
6
+ baseUrl;
7
+ apiKey;
8
+ constructor(apiKey, baseUrl) {
9
+ this.apiKey = apiKey;
10
+ this.baseUrl = (baseUrl || "https://verbolab.co").replace(/\/$/, "");
11
+ }
12
+ async request(path, options = {}) {
13
+ const url = `${this.baseUrl}/api/v1${path}`;
14
+ const res = await fetch(url, {
15
+ ...options,
16
+ headers: {
17
+ "Authorization": `Bearer ${this.apiKey}`,
18
+ "Content-Type": "application/json",
19
+ ...options.headers,
20
+ },
21
+ });
22
+ const data = await res.json();
23
+ if (!res.ok) {
24
+ throw new Error(`Verbo API error (${res.status}): ${data.error || "Unknown error"}`);
25
+ }
26
+ return data;
27
+ }
28
+ async sendMessage(to, message, imageUrl) {
29
+ return this.request("/messages", {
30
+ method: "POST",
31
+ body: JSON.stringify({ to, message, imageUrl }),
32
+ });
33
+ }
34
+ async listConversations(options) {
35
+ const params = new URLSearchParams();
36
+ if (options?.status)
37
+ params.set("status", options.status);
38
+ if (options?.limit)
39
+ params.set("limit", String(options.limit));
40
+ const qs = params.toString();
41
+ return this.request(`/conversations${qs ? `?${qs}` : ""}`);
42
+ }
43
+ async getConversation(id) {
44
+ return this.request(`/conversations?id=${id}`);
45
+ }
46
+ async getAgentStatus() {
47
+ return this.request("/agent/status");
48
+ }
49
+ async configureAgent(config) {
50
+ return this.request("/agent/configure", {
51
+ method: "POST",
52
+ body: JSON.stringify(config),
53
+ });
54
+ }
55
+ async setupCrawl(url) {
56
+ return this.request("/setup/crawl", {
57
+ method: "POST",
58
+ body: JSON.stringify({ url }),
59
+ });
60
+ }
61
+ async setupConnect() {
62
+ return this.request("/setup/connect", {
63
+ method: "POST",
64
+ body: JSON.stringify({}),
65
+ });
66
+ }
67
+ async setupStatus() {
68
+ return this.request("/setup/status");
69
+ }
70
+ async setupDisconnect() {
71
+ return this.request("/setup/disconnect", {
72
+ method: "POST",
73
+ body: JSON.stringify({}),
74
+ });
75
+ }
76
+ }
77
+ exports.VerboClient = VerboClient;
78
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ // packages/mcp-server/src/index.ts
5
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
6
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
+ const client_js_1 = require("./client.js");
8
+ const tools_js_1 = require("./tools.js");
9
+ const setup_tools_js_1 = require("./setup-tools.js");
10
+ const apiKey = process.env.VERBO_API_KEY;
11
+ if (!apiKey) {
12
+ console.error("VERBO_API_KEY environment variable is required");
13
+ process.exit(1);
14
+ }
15
+ const baseUrl = process.env.VERBO_API_URL;
16
+ const client = new client_js_1.VerboClient(apiKey, baseUrl);
17
+ const server = new mcp_js_1.McpServer({
18
+ name: "Verbo",
19
+ version: "0.1.0",
20
+ });
21
+ for (const [name, tool] of Object.entries(tools_js_1.toolDefinitions)) {
22
+ server.tool(name, tool.description, tool.schema, async (args) => {
23
+ try {
24
+ const result = await (0, tools_js_1.executeTool)(client, name, args);
25
+ return { content: [{ type: "text", text: result }] };
26
+ }
27
+ catch (err) {
28
+ const message = err instanceof Error ? err.message : "Unknown error";
29
+ return {
30
+ content: [{ type: "text", text: `Error: ${message}` }],
31
+ isError: true,
32
+ };
33
+ }
34
+ });
35
+ }
36
+ for (const [name, tool] of Object.entries(setup_tools_js_1.setupToolDefinitions)) {
37
+ server.tool(name, tool.description, tool.schema, async (args) => {
38
+ try {
39
+ const result = await (0, setup_tools_js_1.executeSetupTool)(client, name, args);
40
+ return { content: [{ type: "text", text: result }] };
41
+ }
42
+ catch (err) {
43
+ const message = err instanceof Error ? err.message : "Unknown error";
44
+ return {
45
+ content: [{ type: "text", text: `Error: ${message}` }],
46
+ isError: true,
47
+ };
48
+ }
49
+ });
50
+ }
51
+ async function main() {
52
+ const transport = new stdio_js_1.StdioServerTransport();
53
+ await server.connect(transport);
54
+ }
55
+ main().catch((err) => {
56
+ console.error("Fatal:", err);
57
+ process.exit(1);
58
+ });
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ import { type VerboClient } from "./client.js";
3
+ export declare const setupToolDefinitions: {
4
+ readonly verbo_setup_crawl: {
5
+ readonly description: "Crawl a website to auto-configure the AI agent. Extracts business name, description, products, FAQ, hours, and tone of voice. Run this first after creating your account.";
6
+ readonly schema: {
7
+ readonly url: z.ZodString;
8
+ };
9
+ };
10
+ readonly verbo_setup_connect: {
11
+ readonly description: "Start WhatsApp connection. Creates the WhatsApp instance and returns a URL where the developer can scan the QR code in their browser. After scanning, the AI agent starts handling messages automatically.";
12
+ readonly schema: {};
13
+ };
14
+ readonly verbo_setup_status: {
15
+ readonly description: "Check the setup progress. Shows which steps are done (account, business config, WhatsApp, agent) and what to do next.";
16
+ readonly schema: {};
17
+ };
18
+ readonly verbo_setup_disconnect: {
19
+ readonly description: "Disconnect WhatsApp from the agent. Frees the phone number immediately so it can be used elsewhere. Use this when you're done testing or want to switch numbers.";
20
+ readonly schema: {};
21
+ };
22
+ };
23
+ export type SetupToolName = keyof typeof setupToolDefinitions;
24
+ export declare function executeSetupTool(client: VerboClient, name: string, args: Record<string, unknown>): Promise<string>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupToolDefinitions = void 0;
4
+ exports.executeSetupTool = executeSetupTool;
5
+ // packages/mcp-server/src/setup-tools.ts
6
+ const zod_1 = require("zod");
7
+ exports.setupToolDefinitions = {
8
+ verbo_setup_crawl: {
9
+ description: "Crawl a website to auto-configure the AI agent. Extracts business name, description, products, FAQ, hours, and tone of voice. Run this first after creating your account.",
10
+ schema: {
11
+ url: zod_1.z.string().describe("Website URL (e.g. meuemprego.com.br)"),
12
+ },
13
+ },
14
+ verbo_setup_connect: {
15
+ description: "Start WhatsApp connection. Creates the WhatsApp instance and returns a URL where the developer can scan the QR code in their browser. After scanning, the AI agent starts handling messages automatically.",
16
+ schema: {},
17
+ },
18
+ verbo_setup_status: {
19
+ description: "Check the setup progress. Shows which steps are done (account, business config, WhatsApp, agent) and what to do next.",
20
+ schema: {},
21
+ },
22
+ verbo_setup_disconnect: {
23
+ description: "Disconnect WhatsApp from the agent. Frees the phone number immediately so it can be used elsewhere. Use this when you're done testing or want to switch numbers.",
24
+ schema: {},
25
+ },
26
+ };
27
+ async function executeSetupTool(client, name, args) {
28
+ switch (name) {
29
+ case "verbo_setup_crawl": {
30
+ const result = await client.setupCrawl(args.url);
31
+ return JSON.stringify(result, null, 2);
32
+ }
33
+ case "verbo_setup_connect": {
34
+ const result = await client.setupConnect();
35
+ return JSON.stringify(result, null, 2);
36
+ }
37
+ case "verbo_setup_status": {
38
+ const result = await client.setupStatus();
39
+ return JSON.stringify(result, null, 2);
40
+ }
41
+ case "verbo_setup_disconnect": {
42
+ const result = await client.setupDisconnect();
43
+ return JSON.stringify(result, null, 2);
44
+ }
45
+ default:
46
+ return JSON.stringify({ error: `Unknown setup tool: ${name}` });
47
+ }
48
+ }
49
+ //# sourceMappingURL=setup-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-tools.js","sourceRoot":"","sources":["../src/setup-tools.ts"],"names":[],"mappings":";;;AA+BA,4CAyBC;AAxDD,yCAAyC;AACzC,6BAAwB;AAGX,QAAA,oBAAoB,GAAG;IAClC,iBAAiB,EAAE;QACjB,WAAW,EACT,2KAA2K;QAC7K,MAAM,EAAE;YACN,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;SACjE;KACF;IACD,mBAAmB,EAAE;QACnB,WAAW,EACT,4MAA4M;QAC9M,MAAM,EAAE,EAAE;KACX;IACD,kBAAkB,EAAE;QAClB,WAAW,EACT,uHAAuH;QACzH,MAAM,EAAE,EAAE;KACX;IACD,sBAAsB,EAAE;QACtB,WAAW,EACT,kKAAkK;QACpK,MAAM,EAAE,EAAE;KACX;CACO,CAAC;AAIJ,KAAK,UAAU,gBAAgB,CACpC,MAAmB,EACnB,IAAY,EACZ,IAA6B;IAE7B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAa,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,oBAAoB,CAAC,CAAC,CAAC;YAC1B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,wBAAwB,CAAC,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD;YACE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,IAAI,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ import { type VerboClient } from "./client.js";
3
+ export declare const toolDefinitions: {
4
+ readonly verbo_send_message: {
5
+ readonly description: "Enviar mensagem WhatsApp para um número. Suporta texto e imagem.";
6
+ readonly schema: {
7
+ readonly to: z.ZodString;
8
+ readonly message: z.ZodString;
9
+ readonly image_url: z.ZodOptional<z.ZodString>;
10
+ };
11
+ };
12
+ readonly verbo_list_conversations: {
13
+ readonly description: "Listar conversas recentes. Filtrável por status (open/closed).";
14
+ readonly schema: {
15
+ readonly status: z.ZodOptional<z.ZodEnum<{
16
+ open: "open";
17
+ closed: "closed";
18
+ }>>;
19
+ readonly limit: z.ZodOptional<z.ZodNumber>;
20
+ };
21
+ };
22
+ readonly verbo_get_conversation: {
23
+ readonly description: "Ver detalhes e mensagens de uma conversa específica.";
24
+ readonly schema: {
25
+ readonly conversation_id: z.ZodString;
26
+ };
27
+ };
28
+ readonly verbo_agent_status: {
29
+ readonly description: "Verificar status do agente: conexão WhatsApp, negócio configurado, etc.";
30
+ readonly schema: {};
31
+ };
32
+ readonly verbo_configure_agent: {
33
+ readonly description: "Configurar o comportamento do agente de atendimento. Define greeting, FAQ, horário.";
34
+ readonly schema: {
35
+ readonly greeting_message: z.ZodOptional<z.ZodString>;
36
+ readonly faq: z.ZodOptional<z.ZodArray<z.ZodObject<{
37
+ question: z.ZodString;
38
+ answer: z.ZodString;
39
+ }, z.core.$strip>>>;
40
+ readonly business_hours: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
41
+ };
42
+ };
43
+ };
44
+ export type ToolName = keyof typeof toolDefinitions;
45
+ export declare function executeTool(client: VerboClient, name: string, args: Record<string, unknown>): Promise<string>;
package/dist/tools.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolDefinitions = void 0;
4
+ exports.executeTool = executeTool;
5
+ // packages/mcp-server/src/tools.ts
6
+ const zod_1 = require("zod");
7
+ exports.toolDefinitions = {
8
+ verbo_send_message: {
9
+ description: "Enviar mensagem WhatsApp para um número. Suporta texto e imagem.",
10
+ schema: {
11
+ to: zod_1.z
12
+ .string()
13
+ .describe("Número de telefone (ex: +5511999999999)"),
14
+ message: zod_1.z.string().describe("Texto da mensagem"),
15
+ image_url: zod_1.z
16
+ .string()
17
+ .optional()
18
+ .describe("URL da imagem (opcional)"),
19
+ },
20
+ },
21
+ verbo_list_conversations: {
22
+ description: "Listar conversas recentes. Filtrável por status (open/closed).",
23
+ schema: {
24
+ status: zod_1.z
25
+ .enum(["open", "closed"])
26
+ .optional()
27
+ .describe("Filtrar por status"),
28
+ limit: zod_1.z
29
+ .number()
30
+ .optional()
31
+ .describe("Máximo de resultados (1-100, default 20)"),
32
+ },
33
+ },
34
+ verbo_get_conversation: {
35
+ description: "Ver detalhes e mensagens de uma conversa específica.",
36
+ schema: {
37
+ conversation_id: zod_1.z.string().describe("ID da conversa"),
38
+ },
39
+ },
40
+ verbo_agent_status: {
41
+ description: "Verificar status do agente: conexão WhatsApp, negócio configurado, etc.",
42
+ schema: {},
43
+ },
44
+ verbo_configure_agent: {
45
+ description: "Configurar o comportamento do agente de atendimento. Define greeting, FAQ, horário.",
46
+ schema: {
47
+ greeting_message: zod_1.z
48
+ .string()
49
+ .optional()
50
+ .describe("Mensagem de saudação para novos clientes"),
51
+ faq: zod_1.z
52
+ .array(zod_1.z.object({
53
+ question: zod_1.z.string(),
54
+ answer: zod_1.z.string(),
55
+ }))
56
+ .optional()
57
+ .describe("Perguntas frequentes"),
58
+ business_hours: zod_1.z
59
+ .record(zod_1.z.string(), zod_1.z.string())
60
+ .optional()
61
+ .describe("Horário de funcionamento (ex: { monday: '9:00-18:00' })"),
62
+ },
63
+ },
64
+ };
65
+ async function executeTool(client, name, args) {
66
+ switch (name) {
67
+ case "verbo_send_message": {
68
+ const result = await client.sendMessage(args.to, args.message, args.image_url);
69
+ return JSON.stringify(result, null, 2);
70
+ }
71
+ case "verbo_list_conversations": {
72
+ const result = await client.listConversations({
73
+ status: args.status,
74
+ limit: args.limit,
75
+ });
76
+ return JSON.stringify(result, null, 2);
77
+ }
78
+ case "verbo_get_conversation": {
79
+ const result = await client.getConversation(args.conversation_id);
80
+ return JSON.stringify(result, null, 2);
81
+ }
82
+ case "verbo_agent_status": {
83
+ const result = await client.getAgentStatus();
84
+ return JSON.stringify(result, null, 2);
85
+ }
86
+ case "verbo_configure_agent": {
87
+ const result = await client.configureAgent({
88
+ greetingMessage: args.greeting_message,
89
+ faqData: args.faq,
90
+ businessHours: args.business_hours,
91
+ });
92
+ return JSON.stringify(result, null, 2);
93
+ }
94
+ default:
95
+ return JSON.stringify({ error: `Unknown tool: ${name}` });
96
+ }
97
+ }
98
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "verbo-mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "Verbo MCP Server — AI WhatsApp agent for developers",
5
+ "bin": {
6
+ "verbo-mcp": "./dist/index.js"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch"
12
+ },
13
+ "dependencies": {
14
+ "@modelcontextprotocol/sdk": "^1.12.1",
15
+ "zod": "^4.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.8.3"
19
+ },
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "keywords": ["mcp", "whatsapp", "ai", "verbo", "claude"],
24
+ "license": "MIT"
25
+ }
package/src/client.ts ADDED
@@ -0,0 +1,90 @@
1
+ // packages/mcp-server/src/client.ts
2
+
3
+ export class VerboClient {
4
+ private baseUrl: string;
5
+ private apiKey: string;
6
+
7
+ constructor(apiKey: string, baseUrl?: string) {
8
+ this.apiKey = apiKey;
9
+ this.baseUrl = (baseUrl || "https://verbolab.co").replace(/\/$/, "");
10
+ }
11
+
12
+ private async request(path: string, options: RequestInit = {}): Promise<unknown> {
13
+ const url = `${this.baseUrl}/api/v1${path}`;
14
+ const res = await fetch(url, {
15
+ ...options,
16
+ headers: {
17
+ "Authorization": `Bearer ${this.apiKey}`,
18
+ "Content-Type": "application/json",
19
+ ...options.headers,
20
+ },
21
+ });
22
+
23
+ const data = await res.json();
24
+ if (!res.ok) {
25
+ throw new Error(
26
+ `Verbo API error (${res.status}): ${(data as { error?: string }).error || "Unknown error"}`
27
+ );
28
+ }
29
+ return data;
30
+ }
31
+
32
+ async sendMessage(to: string, message: string, imageUrl?: string) {
33
+ return this.request("/messages", {
34
+ method: "POST",
35
+ body: JSON.stringify({ to, message, imageUrl }),
36
+ });
37
+ }
38
+
39
+ async listConversations(options?: { status?: string; limit?: number }) {
40
+ const params = new URLSearchParams();
41
+ if (options?.status) params.set("status", options.status);
42
+ if (options?.limit) params.set("limit", String(options.limit));
43
+ const qs = params.toString();
44
+ return this.request(`/conversations${qs ? `?${qs}` : ""}`);
45
+ }
46
+
47
+ async getConversation(id: string) {
48
+ return this.request(`/conversations?id=${id}`);
49
+ }
50
+
51
+ async getAgentStatus() {
52
+ return this.request("/agent/status");
53
+ }
54
+
55
+ async configureAgent(config: {
56
+ greetingMessage?: string;
57
+ faqData?: Record<string, string>[];
58
+ businessHours?: Record<string, unknown>;
59
+ }) {
60
+ return this.request("/agent/configure", {
61
+ method: "POST",
62
+ body: JSON.stringify(config),
63
+ });
64
+ }
65
+
66
+ async setupCrawl(url: string) {
67
+ return this.request("/setup/crawl", {
68
+ method: "POST",
69
+ body: JSON.stringify({ url }),
70
+ });
71
+ }
72
+
73
+ async setupConnect() {
74
+ return this.request("/setup/connect", {
75
+ method: "POST",
76
+ body: JSON.stringify({}),
77
+ });
78
+ }
79
+
80
+ async setupStatus() {
81
+ return this.request("/setup/status");
82
+ }
83
+
84
+ async setupDisconnect() {
85
+ return this.request("/setup/disconnect", {
86
+ method: "POST",
87
+ body: JSON.stringify({}),
88
+ });
89
+ }
90
+ }
package/src/index.ts ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ // packages/mcp-server/src/index.ts
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { VerboClient } from "./client.js";
6
+ import { toolDefinitions, executeTool, type ToolName } from "./tools.js";
7
+ import { setupToolDefinitions, executeSetupTool } from "./setup-tools.js";
8
+
9
+ const apiKey = process.env.VERBO_API_KEY;
10
+ if (!apiKey) {
11
+ console.error("VERBO_API_KEY environment variable is required");
12
+ process.exit(1);
13
+ }
14
+
15
+ const baseUrl = process.env.VERBO_API_URL;
16
+ const client = new VerboClient(apiKey, baseUrl);
17
+
18
+ const server = new McpServer({
19
+ name: "Verbo",
20
+ version: "0.1.0",
21
+ });
22
+
23
+ for (const [name, tool] of Object.entries(toolDefinitions)) {
24
+ server.tool(name, tool.description, tool.schema, async (args: Record<string, unknown>) => {
25
+ try {
26
+ const result = await executeTool(
27
+ client,
28
+ name,
29
+ args as Record<string, unknown>,
30
+ );
31
+ return { content: [{ type: "text" as const, text: result }] };
32
+ } catch (err) {
33
+ const message =
34
+ err instanceof Error ? err.message : "Unknown error";
35
+ return {
36
+ content: [{ type: "text" as const, text: `Error: ${message}` }],
37
+ isError: true,
38
+ };
39
+ }
40
+ });
41
+ }
42
+
43
+ for (const [name, tool] of Object.entries(setupToolDefinitions)) {
44
+ server.tool(name, tool.description, tool.schema, async (args: Record<string, unknown>) => {
45
+ try {
46
+ const result = await executeSetupTool(client, name, args);
47
+ return { content: [{ type: "text" as const, text: result }] };
48
+ } catch (err) {
49
+ const message =
50
+ err instanceof Error ? err.message : "Unknown error";
51
+ return {
52
+ content: [{ type: "text" as const, text: `Error: ${message}` }],
53
+ isError: true,
54
+ };
55
+ }
56
+ });
57
+ }
58
+
59
+ async function main() {
60
+ const transport = new StdioServerTransport();
61
+ await server.connect(transport);
62
+ }
63
+
64
+ main().catch((err) => {
65
+ console.error("Fatal:", err);
66
+ process.exit(1);
67
+ });
@@ -0,0 +1,57 @@
1
+ // packages/mcp-server/src/setup-tools.ts
2
+ import { z } from "zod";
3
+ import { type VerboClient } from "./client.js";
4
+
5
+ export const setupToolDefinitions = {
6
+ verbo_setup_crawl: {
7
+ description:
8
+ "Crawl a website to auto-configure the AI agent. Extracts business name, description, products, FAQ, hours, and tone of voice. Run this first after creating your account.",
9
+ schema: {
10
+ url: z.string().describe("Website URL (e.g. meuemprego.com.br)"),
11
+ },
12
+ },
13
+ verbo_setup_connect: {
14
+ description:
15
+ "Start WhatsApp connection. Creates the WhatsApp instance and returns a URL where the developer can scan the QR code in their browser. After scanning, the AI agent starts handling messages automatically.",
16
+ schema: {},
17
+ },
18
+ verbo_setup_status: {
19
+ description:
20
+ "Check the setup progress. Shows which steps are done (account, business config, WhatsApp, agent) and what to do next.",
21
+ schema: {},
22
+ },
23
+ verbo_setup_disconnect: {
24
+ description:
25
+ "Disconnect WhatsApp from the agent. Frees the phone number immediately so it can be used elsewhere. Use this when you're done testing or want to switch numbers.",
26
+ schema: {},
27
+ },
28
+ } as const;
29
+
30
+ export type SetupToolName = keyof typeof setupToolDefinitions;
31
+
32
+ export async function executeSetupTool(
33
+ client: VerboClient,
34
+ name: string,
35
+ args: Record<string, unknown>,
36
+ ): Promise<string> {
37
+ switch (name) {
38
+ case "verbo_setup_crawl": {
39
+ const result = await client.setupCrawl(args.url as string);
40
+ return JSON.stringify(result, null, 2);
41
+ }
42
+ case "verbo_setup_connect": {
43
+ const result = await client.setupConnect();
44
+ return JSON.stringify(result, null, 2);
45
+ }
46
+ case "verbo_setup_status": {
47
+ const result = await client.setupStatus();
48
+ return JSON.stringify(result, null, 2);
49
+ }
50
+ case "verbo_setup_disconnect": {
51
+ const result = await client.setupDisconnect();
52
+ return JSON.stringify(result, null, 2);
53
+ }
54
+ default:
55
+ return JSON.stringify({ error: `Unknown setup tool: ${name}` });
56
+ }
57
+ }
package/src/tools.ts ADDED
@@ -0,0 +1,119 @@
1
+ // packages/mcp-server/src/tools.ts
2
+ import { z } from "zod";
3
+ import { type VerboClient } from "./client.js";
4
+
5
+ export const toolDefinitions = {
6
+ verbo_send_message: {
7
+ description:
8
+ "Enviar mensagem WhatsApp para um número. Suporta texto e imagem.",
9
+ schema: {
10
+ to: z
11
+ .string()
12
+ .describe("Número de telefone (ex: +5511999999999)"),
13
+ message: z.string().describe("Texto da mensagem"),
14
+ image_url: z
15
+ .string()
16
+ .optional()
17
+ .describe("URL da imagem (opcional)"),
18
+ },
19
+ },
20
+ verbo_list_conversations: {
21
+ description:
22
+ "Listar conversas recentes. Filtrável por status (open/closed).",
23
+ schema: {
24
+ status: z
25
+ .enum(["open", "closed"])
26
+ .optional()
27
+ .describe("Filtrar por status"),
28
+ limit: z
29
+ .number()
30
+ .optional()
31
+ .describe("Máximo de resultados (1-100, default 20)"),
32
+ },
33
+ },
34
+ verbo_get_conversation: {
35
+ description:
36
+ "Ver detalhes e mensagens de uma conversa específica.",
37
+ schema: {
38
+ conversation_id: z.string().describe("ID da conversa"),
39
+ },
40
+ },
41
+ verbo_agent_status: {
42
+ description:
43
+ "Verificar status do agente: conexão WhatsApp, negócio configurado, etc.",
44
+ schema: {},
45
+ },
46
+ verbo_configure_agent: {
47
+ description:
48
+ "Configurar o comportamento do agente de atendimento. Define greeting, FAQ, horário.",
49
+ schema: {
50
+ greeting_message: z
51
+ .string()
52
+ .optional()
53
+ .describe("Mensagem de saudação para novos clientes"),
54
+ faq: z
55
+ .array(
56
+ z.object({
57
+ question: z.string(),
58
+ answer: z.string(),
59
+ }),
60
+ )
61
+ .optional()
62
+ .describe("Perguntas frequentes"),
63
+ business_hours: z
64
+ .record(z.string(), z.string())
65
+ .optional()
66
+ .describe(
67
+ "Horário de funcionamento (ex: { monday: '9:00-18:00' })",
68
+ ),
69
+ },
70
+ },
71
+ } as const;
72
+
73
+ export type ToolName = keyof typeof toolDefinitions;
74
+
75
+ export async function executeTool(
76
+ client: VerboClient,
77
+ name: string,
78
+ args: Record<string, unknown>,
79
+ ): Promise<string> {
80
+ switch (name) {
81
+ case "verbo_send_message": {
82
+ const result = await client.sendMessage(
83
+ args.to as string,
84
+ args.message as string,
85
+ args.image_url as string | undefined,
86
+ );
87
+ return JSON.stringify(result, null, 2);
88
+ }
89
+ case "verbo_list_conversations": {
90
+ const result = await client.listConversations({
91
+ status: args.status as string | undefined,
92
+ limit: args.limit as number | undefined,
93
+ });
94
+ return JSON.stringify(result, null, 2);
95
+ }
96
+ case "verbo_get_conversation": {
97
+ const result = await client.getConversation(
98
+ args.conversation_id as string,
99
+ );
100
+ return JSON.stringify(result, null, 2);
101
+ }
102
+ case "verbo_agent_status": {
103
+ const result = await client.getAgentStatus();
104
+ return JSON.stringify(result, null, 2);
105
+ }
106
+ case "verbo_configure_agent": {
107
+ const result = await client.configureAgent({
108
+ greetingMessage: args.greeting_message as string | undefined,
109
+ faqData: args.faq as Record<string, string>[] | undefined,
110
+ businessHours: args.business_hours as
111
+ | Record<string, unknown>
112
+ | undefined,
113
+ });
114
+ return JSON.stringify(result, null, 2);
115
+ }
116
+ default:
117
+ return JSON.stringify({ error: `Unknown tool: ${name}` });
118
+ }
119
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "declaration": true,
12
+ "sourceMap": true
13
+ },
14
+ "include": ["src"]
15
+ }