@botozap/mcp 0.1.0 → 0.2.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.
Files changed (44) hide show
  1. package/README.md +111 -43
  2. package/dist/event-bus.d.ts +14 -0
  3. package/dist/event-bus.js +128 -0
  4. package/dist/event-bus.js.map +1 -0
  5. package/dist/http.d.ts +31 -0
  6. package/dist/http.js +280 -0
  7. package/dist/http.js.map +1 -0
  8. package/dist/index.js +47 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/register.d.ts +18 -4
  11. package/dist/register.js +82 -17
  12. package/dist/register.js.map +1 -1
  13. package/dist/resources/events.d.ts +12 -0
  14. package/dist/resources/events.js +192 -0
  15. package/dist/resources/events.js.map +1 -0
  16. package/dist/schemas.d.ts +4405 -0
  17. package/dist/schemas.js +332 -0
  18. package/dist/schemas.js.map +1 -0
  19. package/dist/server.d.ts +7 -0
  20. package/dist/server.js +13 -2
  21. package/dist/server.js.map +1 -1
  22. package/dist/tools/contacts.d.ts +1 -1
  23. package/dist/tools/contacts.js +8 -6
  24. package/dist/tools/contacts.js.map +1 -1
  25. package/dist/tools/conversations.js +17 -3
  26. package/dist/tools/conversations.js.map +1 -1
  27. package/dist/tools/customers.d.ts +1 -1
  28. package/dist/tools/customers.js +11 -9
  29. package/dist/tools/customers.js.map +1 -1
  30. package/dist/tools/media.d.ts +94 -0
  31. package/dist/tools/media.js +90 -2
  32. package/dist/tools/media.js.map +1 -1
  33. package/dist/tools/messages.js +5 -4
  34. package/dist/tools/messages.js.map +1 -1
  35. package/dist/tools/misc.js +3 -2
  36. package/dist/tools/misc.js.map +1 -1
  37. package/dist/tools/phone-numbers.js +4 -3
  38. package/dist/tools/phone-numbers.js.map +1 -1
  39. package/dist/tools/templates.js +4 -3
  40. package/dist/tools/templates.js.map +1 -1
  41. package/dist/tools/webhooks.d.ts +1 -1
  42. package/dist/tools/webhooks.js +10 -8
  43. package/dist/tools/webhooks.js.map +1 -1
  44. package/package.json +4 -2
@@ -0,0 +1,192 @@
1
+ import { ErrorCode, McpError, SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ export const EVENTS_URI_TEMPLATE = "botozap://events{?after,limit}";
4
+ const DEFAULT_LIMIT = 100;
5
+ /**
6
+ * Tail de baixa latência ativo somente enquanto o cliente stdio mantém uma
7
+ * assinatura. A notification é apenas um sinal; o payload continua vindo do
8
+ * resource, que relê o stream durável da API pelo cursor informado na URI.
9
+ */
10
+ class EventSubscriptions {
11
+ server;
12
+ client;
13
+ pollIntervalMs;
14
+ maxSubscriptions;
15
+ subscriptions = new Map();
16
+ pollAbortController;
17
+ timer;
18
+ polling = false;
19
+ signalPending = false;
20
+ closed = false;
21
+ unsubscribeEventSignal;
22
+ constructor(server, client, pollIntervalMs, maxSubscriptions, eventSignal) {
23
+ this.server = server;
24
+ this.client = client;
25
+ this.pollIntervalMs = pollIntervalMs;
26
+ this.maxSubscriptions = maxSubscriptions;
27
+ this.unsubscribeEventSignal = eventSignal?.subscribe(() => {
28
+ this.signalPending = true;
29
+ this.schedule(0);
30
+ });
31
+ }
32
+ subscribe(uri) {
33
+ const { after } = parseEventsUri(uri);
34
+ if (!this.subscriptions.has(uri)) {
35
+ if (this.subscriptions.size >= this.maxSubscriptions) {
36
+ throw new McpError(ErrorCode.InvalidRequest, `Limite de assinaturas de Eventos atingido (${this.maxSubscriptions}).`);
37
+ }
38
+ this.subscriptions.set(uri, { cursor: after });
39
+ }
40
+ this.schedule(0);
41
+ }
42
+ unsubscribe(uri) {
43
+ parseEventsUri(uri);
44
+ if (this.subscriptions.delete(uri) && this.polling) {
45
+ this.pollAbortController?.abort();
46
+ if (this.subscriptions.size > 0)
47
+ this.signalPending = true;
48
+ }
49
+ if (this.subscriptions.size === 0 && this.timer) {
50
+ clearTimeout(this.timer);
51
+ this.timer = undefined;
52
+ this.signalPending = false;
53
+ }
54
+ }
55
+ close() {
56
+ this.closed = true;
57
+ this.subscriptions.clear();
58
+ this.unsubscribeEventSignal?.();
59
+ this.pollAbortController?.abort();
60
+ if (this.timer)
61
+ clearTimeout(this.timer);
62
+ this.timer = undefined;
63
+ }
64
+ schedule(delayMs) {
65
+ if (this.closed || this.subscriptions.size === 0) {
66
+ return;
67
+ }
68
+ if (this.polling)
69
+ return;
70
+ if (this.timer) {
71
+ if (delayMs > 0)
72
+ return;
73
+ clearTimeout(this.timer);
74
+ this.timer = undefined;
75
+ }
76
+ this.timer = setTimeout(() => {
77
+ this.timer = undefined;
78
+ void this.poll();
79
+ }, delayMs);
80
+ this.timer.unref?.();
81
+ }
82
+ async poll() {
83
+ if (this.closed || this.polling || this.subscriptions.size === 0)
84
+ return;
85
+ this.polling = true;
86
+ this.signalPending = false;
87
+ const abortController = new AbortController();
88
+ this.pollAbortController = abortController;
89
+ try {
90
+ for (const [uri, subscription] of [...this.subscriptions]) {
91
+ try {
92
+ const page = await this.client.events.list({
93
+ after: subscription.cursor,
94
+ limit: DEFAULT_LIMIT,
95
+ signal: abortController.signal,
96
+ });
97
+ // A assinatura pode ter sido cancelada enquanto o fetch estava no ar.
98
+ if (this.closed || this.subscriptions.get(uri) !== subscription)
99
+ continue;
100
+ if (page.data.length === 0)
101
+ continue;
102
+ await this.server.server.sendResourceUpdated({ uri });
103
+ subscription.cursor = page.paging.cursor;
104
+ if (page.paging.has_more)
105
+ this.signalPending = true;
106
+ }
107
+ catch {
108
+ // Falhas transitórias não encerram a sessão MCP. A leitura explícita
109
+ // continua expondo o erro estruturado do SDK ao cliente.
110
+ }
111
+ }
112
+ }
113
+ finally {
114
+ if (this.pollAbortController === abortController) {
115
+ this.pollAbortController = undefined;
116
+ }
117
+ this.polling = false;
118
+ this.schedule(this.signalPending ? 0 : this.pollIntervalMs);
119
+ }
120
+ }
121
+ }
122
+ export function registerEventResources(server, client, options) {
123
+ const subscriptions = new EventSubscriptions(server, client, Math.max(1, options.pollIntervalMs), Math.max(1, options.maxSubscriptions ?? 8), options.eventSignal);
124
+ server.registerResource("events", new ResourceTemplate(EVENTS_URI_TEMPLATE, { list: undefined }), {
125
+ title: "Eventos do WhatsApp",
126
+ description: "Stream durável de Eventos da Conta e ambiente autenticados, lido em ordem crescente pelo cursor `after`.",
127
+ mimeType: "application/json",
128
+ }, async (uri) => {
129
+ const params = parseEventsUri(uri.href);
130
+ const page = await client.events.list(params);
131
+ return {
132
+ contents: [
133
+ {
134
+ uri: uri.href,
135
+ mimeType: "application/json",
136
+ text: JSON.stringify(page),
137
+ },
138
+ ],
139
+ };
140
+ });
141
+ server.server.setRequestHandler(SubscribeRequestSchema, (request) => {
142
+ subscriptions.subscribe(request.params.uri);
143
+ return {};
144
+ });
145
+ server.server.setRequestHandler(UnsubscribeRequestSchema, (request) => {
146
+ subscriptions.unsubscribe(request.params.uri);
147
+ return {};
148
+ });
149
+ return () => subscriptions.close();
150
+ }
151
+ function parseEventsUri(uri) {
152
+ let parsed;
153
+ try {
154
+ parsed = new URL(uri);
155
+ }
156
+ catch {
157
+ throw invalidUri();
158
+ }
159
+ const keys = [...parsed.searchParams.keys()];
160
+ const hasUnknownParam = keys.some((key) => key !== "after" && key !== "limit");
161
+ const hasDuplicateParam = parsed.searchParams.getAll("after").length > 1 ||
162
+ parsed.searchParams.getAll("limit").length > 1;
163
+ if (parsed.protocol !== "botozap:" ||
164
+ parsed.hostname !== "events" ||
165
+ parsed.port !== "" ||
166
+ parsed.pathname !== "" ||
167
+ parsed.username !== "" ||
168
+ parsed.password !== "" ||
169
+ parsed.hash !== "" ||
170
+ hasUnknownParam ||
171
+ hasDuplicateParam) {
172
+ throw invalidUri();
173
+ }
174
+ const after = parsed.searchParams.get("after") ?? "0";
175
+ const afterNumber = Number(after);
176
+ if (!/^\d+$/.test(after) || !Number.isSafeInteger(afterNumber) || afterNumber < 0) {
177
+ throw invalidUri();
178
+ }
179
+ const rawLimit = parsed.searchParams.get("limit");
180
+ const limit = rawLimit === null ? DEFAULT_LIMIT : Number(rawLimit);
181
+ if ((rawLimit !== null && !/^\d+$/.test(rawLimit)) ||
182
+ !Number.isSafeInteger(limit) ||
183
+ limit < 1 ||
184
+ limit > 100) {
185
+ throw invalidUri();
186
+ }
187
+ return { after, limit };
188
+ }
189
+ function invalidUri() {
190
+ return new McpError(ErrorCode.InvalidParams, "URI de Eventos inválida. Use botozap://events?after=<cursor>&limit=<1..100>.");
191
+ }
192
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/resources/events.ts"],"names":[],"mappings":"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"}