@codespar/mcp-zenvia 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/dist/index.js +181 -0
- package/package.json +30 -0
- package/src/index.ts +194 -0
- package/tsconfig.json +13 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server for Zenvia — multi-channel messaging (SMS, WhatsApp, RCS).
|
|
4
|
+
*
|
|
5
|
+
* Tools:
|
|
6
|
+
* - send_sms: Send an SMS message
|
|
7
|
+
* - send_whatsapp: Send a WhatsApp message
|
|
8
|
+
* - send_rcs: Send an RCS message
|
|
9
|
+
* - get_message_status: Get message delivery status
|
|
10
|
+
* - list_channels: List available messaging channels
|
|
11
|
+
* - create_subscription: Create a webhook subscription for events
|
|
12
|
+
* - list_contacts: List contacts
|
|
13
|
+
* - send_template: Send a WhatsApp template message
|
|
14
|
+
*
|
|
15
|
+
* Environment:
|
|
16
|
+
* ZENVIA_API_TOKEN — API token from https://app.zenvia.com/
|
|
17
|
+
*/
|
|
18
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
19
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
+
const API_TOKEN = process.env.ZENVIA_API_TOKEN || "";
|
|
22
|
+
const BASE_URL = "https://api.zenvia.com/v2";
|
|
23
|
+
async function zenviaRequest(method, path, body) {
|
|
24
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
25
|
+
method,
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
"X-API-TOKEN": API_TOKEN,
|
|
29
|
+
},
|
|
30
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const err = await res.text();
|
|
34
|
+
throw new Error(`Zenvia API ${res.status}: ${err}`);
|
|
35
|
+
}
|
|
36
|
+
return res.json();
|
|
37
|
+
}
|
|
38
|
+
const server = new Server({ name: "mcp-zenvia", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
39
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
40
|
+
tools: [
|
|
41
|
+
{
|
|
42
|
+
name: "send_sms",
|
|
43
|
+
description: "Send an SMS message",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
from: { type: "string", description: "Sender ID" },
|
|
48
|
+
to: { type: "string", description: "Recipient phone number with country code (e.g. 5511999999999)" },
|
|
49
|
+
text: { type: "string", description: "Message text" },
|
|
50
|
+
},
|
|
51
|
+
required: ["from", "to", "text"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "send_whatsapp",
|
|
56
|
+
description: "Send a WhatsApp message",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
from: { type: "string", description: "Sender ID (WhatsApp channel)" },
|
|
61
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
62
|
+
text: { type: "string", description: "Message text" },
|
|
63
|
+
},
|
|
64
|
+
required: ["from", "to", "text"],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "send_rcs",
|
|
69
|
+
description: "Send an RCS (Rich Communication Services) message",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
from: { type: "string", description: "Sender ID (RCS channel)" },
|
|
74
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
75
|
+
text: { type: "string", description: "Message text" },
|
|
76
|
+
},
|
|
77
|
+
required: ["from", "to", "text"],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "get_message_status",
|
|
82
|
+
description: "Get message delivery status by ID",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
id: { type: "string", description: "Message ID" },
|
|
87
|
+
},
|
|
88
|
+
required: ["id"],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "list_channels",
|
|
93
|
+
description: "List available messaging channels",
|
|
94
|
+
inputSchema: { type: "object", properties: {} },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "create_subscription",
|
|
98
|
+
description: "Create a webhook subscription for message events",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
url: { type: "string", description: "Webhook URL to receive events" },
|
|
103
|
+
channel: { type: "string", enum: ["sms", "whatsapp", "rcs"], description: "Channel to subscribe to" },
|
|
104
|
+
eventType: { type: "string", enum: ["MESSAGE", "MESSAGE_STATUS"], description: "Event type" },
|
|
105
|
+
},
|
|
106
|
+
required: ["url", "channel", "eventType"],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "list_contacts",
|
|
111
|
+
description: "List contacts from the contact base",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: "object",
|
|
114
|
+
properties: {
|
|
115
|
+
page: { type: "number", description: "Page number" },
|
|
116
|
+
size: { type: "number", description: "Page size" },
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "send_template",
|
|
122
|
+
description: "Send a WhatsApp template message (pre-approved)",
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: "object",
|
|
125
|
+
properties: {
|
|
126
|
+
from: { type: "string", description: "Sender ID (WhatsApp channel)" },
|
|
127
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
128
|
+
templateId: { type: "string", description: "Approved template ID" },
|
|
129
|
+
fields: {
|
|
130
|
+
type: "object",
|
|
131
|
+
description: "Template variable values (key-value map)",
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
required: ["from", "to", "templateId"],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
}));
|
|
139
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
140
|
+
const { name, arguments: args } = request.params;
|
|
141
|
+
try {
|
|
142
|
+
switch (name) {
|
|
143
|
+
case "send_sms":
|
|
144
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/sms/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
145
|
+
case "send_whatsapp":
|
|
146
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/whatsapp/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
147
|
+
case "send_rcs":
|
|
148
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/rcs/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
149
|
+
case "get_message_status":
|
|
150
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", `/reports/${args?.id}`), null, 2) }] };
|
|
151
|
+
case "list_channels":
|
|
152
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", "/channels"), null, 2) }] };
|
|
153
|
+
case "create_subscription":
|
|
154
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/subscriptions", { webhook: { url: args?.url }, criteria: { channel: args?.channel }, eventType: args?.eventType }), null, 2) }] };
|
|
155
|
+
case "list_contacts": {
|
|
156
|
+
const params = new URLSearchParams();
|
|
157
|
+
if (args?.page)
|
|
158
|
+
params.set("page", String(args.page));
|
|
159
|
+
if (args?.size)
|
|
160
|
+
params.set("size", String(args.size));
|
|
161
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", `/contacts?${params}`), null, 2) }] };
|
|
162
|
+
}
|
|
163
|
+
case "send_template":
|
|
164
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/whatsapp/messages", { from: args?.from, to: args?.to, contents: [{ type: "template", templateId: args?.templateId, fields: args?.fields || {} }] }), null, 2) }] };
|
|
165
|
+
default:
|
|
166
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
async function main() {
|
|
174
|
+
if (!API_TOKEN) {
|
|
175
|
+
console.error("ZENVIA_API_TOKEN environment variable is required");
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
const transport = new StdioServerTransport();
|
|
179
|
+
await server.connect(transport);
|
|
180
|
+
}
|
|
181
|
+
main().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codespar/mcp-zenvia",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Zenvia — SMS, WhatsApp, RCS messaging and templates",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-zenvia": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^25.5.0",
|
|
19
|
+
"typescript": "^5.8.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"zenvia",
|
|
25
|
+
"sms",
|
|
26
|
+
"whatsapp",
|
|
27
|
+
"rcs",
|
|
28
|
+
"brazil"
|
|
29
|
+
]
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Server for Zenvia — multi-channel messaging (SMS, WhatsApp, RCS).
|
|
5
|
+
*
|
|
6
|
+
* Tools:
|
|
7
|
+
* - send_sms: Send an SMS message
|
|
8
|
+
* - send_whatsapp: Send a WhatsApp message
|
|
9
|
+
* - send_rcs: Send an RCS message
|
|
10
|
+
* - get_message_status: Get message delivery status
|
|
11
|
+
* - list_channels: List available messaging channels
|
|
12
|
+
* - create_subscription: Create a webhook subscription for events
|
|
13
|
+
* - list_contacts: List contacts
|
|
14
|
+
* - send_template: Send a WhatsApp template message
|
|
15
|
+
*
|
|
16
|
+
* Environment:
|
|
17
|
+
* ZENVIA_API_TOKEN — API token from https://app.zenvia.com/
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
21
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
22
|
+
import {
|
|
23
|
+
CallToolRequestSchema,
|
|
24
|
+
ListToolsRequestSchema,
|
|
25
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
26
|
+
|
|
27
|
+
const API_TOKEN = process.env.ZENVIA_API_TOKEN || "";
|
|
28
|
+
const BASE_URL = "https://api.zenvia.com/v2";
|
|
29
|
+
|
|
30
|
+
async function zenviaRequest(method: string, path: string, body?: unknown): Promise<unknown> {
|
|
31
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
32
|
+
method,
|
|
33
|
+
headers: {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
"X-API-TOKEN": API_TOKEN,
|
|
36
|
+
},
|
|
37
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const err = await res.text();
|
|
41
|
+
throw new Error(`Zenvia API ${res.status}: ${err}`);
|
|
42
|
+
}
|
|
43
|
+
return res.json();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const server = new Server(
|
|
47
|
+
{ name: "mcp-zenvia", version: "0.1.0" },
|
|
48
|
+
{ capabilities: { tools: {} } }
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
52
|
+
tools: [
|
|
53
|
+
{
|
|
54
|
+
name: "send_sms",
|
|
55
|
+
description: "Send an SMS message",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
from: { type: "string", description: "Sender ID" },
|
|
60
|
+
to: { type: "string", description: "Recipient phone number with country code (e.g. 5511999999999)" },
|
|
61
|
+
text: { type: "string", description: "Message text" },
|
|
62
|
+
},
|
|
63
|
+
required: ["from", "to", "text"],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "send_whatsapp",
|
|
68
|
+
description: "Send a WhatsApp message",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
from: { type: "string", description: "Sender ID (WhatsApp channel)" },
|
|
73
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
74
|
+
text: { type: "string", description: "Message text" },
|
|
75
|
+
},
|
|
76
|
+
required: ["from", "to", "text"],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "send_rcs",
|
|
81
|
+
description: "Send an RCS (Rich Communication Services) message",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
from: { type: "string", description: "Sender ID (RCS channel)" },
|
|
86
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
87
|
+
text: { type: "string", description: "Message text" },
|
|
88
|
+
},
|
|
89
|
+
required: ["from", "to", "text"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "get_message_status",
|
|
94
|
+
description: "Get message delivery status by ID",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
id: { type: "string", description: "Message ID" },
|
|
99
|
+
},
|
|
100
|
+
required: ["id"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "list_channels",
|
|
105
|
+
description: "List available messaging channels",
|
|
106
|
+
inputSchema: { type: "object", properties: {} },
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "create_subscription",
|
|
110
|
+
description: "Create a webhook subscription for message events",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
url: { type: "string", description: "Webhook URL to receive events" },
|
|
115
|
+
channel: { type: "string", enum: ["sms", "whatsapp", "rcs"], description: "Channel to subscribe to" },
|
|
116
|
+
eventType: { type: "string", enum: ["MESSAGE", "MESSAGE_STATUS"], description: "Event type" },
|
|
117
|
+
},
|
|
118
|
+
required: ["url", "channel", "eventType"],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "list_contacts",
|
|
123
|
+
description: "List contacts from the contact base",
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: {
|
|
127
|
+
page: { type: "number", description: "Page number" },
|
|
128
|
+
size: { type: "number", description: "Page size" },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "send_template",
|
|
134
|
+
description: "Send a WhatsApp template message (pre-approved)",
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: "object",
|
|
137
|
+
properties: {
|
|
138
|
+
from: { type: "string", description: "Sender ID (WhatsApp channel)" },
|
|
139
|
+
to: { type: "string", description: "Recipient phone number with country code" },
|
|
140
|
+
templateId: { type: "string", description: "Approved template ID" },
|
|
141
|
+
fields: {
|
|
142
|
+
type: "object",
|
|
143
|
+
description: "Template variable values (key-value map)",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
required: ["from", "to", "templateId"],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
}));
|
|
151
|
+
|
|
152
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
153
|
+
const { name, arguments: args } = request.params;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
switch (name) {
|
|
157
|
+
case "send_sms":
|
|
158
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/sms/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
159
|
+
case "send_whatsapp":
|
|
160
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/whatsapp/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
161
|
+
case "send_rcs":
|
|
162
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/rcs/messages", { from: args?.from, to: args?.to, contents: [{ type: "text", text: args?.text }] }), null, 2) }] };
|
|
163
|
+
case "get_message_status":
|
|
164
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", `/reports/${args?.id}`), null, 2) }] };
|
|
165
|
+
case "list_channels":
|
|
166
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", "/channels"), null, 2) }] };
|
|
167
|
+
case "create_subscription":
|
|
168
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/subscriptions", { webhook: { url: args?.url }, criteria: { channel: args?.channel }, eventType: args?.eventType }), null, 2) }] };
|
|
169
|
+
case "list_contacts": {
|
|
170
|
+
const params = new URLSearchParams();
|
|
171
|
+
if (args?.page) params.set("page", String(args.page));
|
|
172
|
+
if (args?.size) params.set("size", String(args.size));
|
|
173
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("GET", `/contacts?${params}`), null, 2) }] };
|
|
174
|
+
}
|
|
175
|
+
case "send_template":
|
|
176
|
+
return { content: [{ type: "text", text: JSON.stringify(await zenviaRequest("POST", "/channels/whatsapp/messages", { from: args?.from, to: args?.to, contents: [{ type: "template", templateId: args?.templateId, fields: args?.fields || {} }] }), null, 2) }] };
|
|
177
|
+
default:
|
|
178
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
179
|
+
}
|
|
180
|
+
} catch (err) {
|
|
181
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
async function main() {
|
|
186
|
+
if (!API_TOKEN) {
|
|
187
|
+
console.error("ZENVIA_API_TOKEN environment variable is required");
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const transport = new StdioServerTransport();
|
|
191
|
+
await server.connect(transport);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main().catch(console.error);
|
package/tsconfig.json
ADDED