@mambalabsdev/mcp-sequencer-event-poller 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mamba Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,114 @@
1
- # Temporary Holding Version
1
+ # Sequencer Event Poller MCP Server
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![Smithery](https://smithery.ai/badge/mambabuilt/mcp-sequencer-event-poller)](https://smithery.ai/servers/mambabuilt/mcp-sequencer-event-poller) [![Glama score](https://glama.ai/mcp/servers/mambalabsdev/mcp-sequencer-event-poller/badges/score.svg)](https://glama.ai/mcp/servers/mambalabsdev/mcp-sequencer-event-poller) [![MCP Registry](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.modelcontextprotocol.io%2Fv0%2Fservers%3Fsearch%3Dcom.mambabuilt%252Fmcp-sequencer-event-poller%26limit%3D1&query=%24.servers%5B0%5D._meta%5B%22io.modelcontextprotocol.registry%2Fofficial%22%5D.status&label=mcp%20registry&color=blue)](https://registry.modelcontextprotocol.io/v0/servers?search=com.mambabuilt/mcp-sequencer-event-poller&limit=1) [![npm version](https://img.shields.io/npm/v/@mambalabsdev/mcp-sequencer-event-poller)](https://www.npmjs.com/package/@mambalabsdev/mcp-sequencer-event-poller) [![npm downloads](https://img.shields.io/npm/dm/@mambalabsdev/mcp-sequencer-event-poller)](https://www.npmjs.com/package/@mambalabsdev/mcp-sequencer-event-poller) [![license](https://img.shields.io/github/license/mambalabsdev/mcp-sequencer-event-poller)](https://github.com/mambalabsdev/mcp-sequencer-event-poller/blob/main/LICENSE) [![mcpservers.org](https://img.shields.io/badge/mcpservers.org-listed-blue)](https://mcpservers.org/servers/mambalabsdev/mcp-sequencer-event-poller)
4
+
5
+ An MCP server for the Mamba Labs Sequencer Event Poller actor on Apify. It reads replies, bounces, unsubscribes, meetings booked, interest changes, and LinkedIn replies from your own Instantly, Smartlead, HeyReach, and lemlist accounts, and returns one flat row per event.
6
+
7
+ ## What's Inside
8
+
9
+ - [What it does](#what-it-does)
10
+ - [Quick start](#quick-start)
11
+ - [Prerequisites](#prerequisites)
12
+ - [Example prompts](#example-prompts)
13
+ - [Tool](#tool)
14
+ - [Inputs](#inputs)
15
+ - [Pricing](#pricing)
16
+ - [Your keys](#your-keys)
17
+ - [Full actor documentation](#full-actor-documentation)
18
+ - [License](#license)
19
+
20
+ ## What it does
21
+
22
+ Pick a time window, for example the last 24 hours, and get every event from the sequencers you have keys for in one table: vendor, event type, when it happened, the lead's email, name, and company, the campaign, and the reply text where the vendor returns it. One free run summary row gives counts per vendor and event type and says whether each vendor was read, skipped, or refused the key. With only new events on, a scheduled run returns only events an earlier run has not returned.
23
+
24
+ The actor only reads. It never creates, edits, pauses, or sends anything in a sequencer, and it never creates a campaign.
25
+
26
+ All of the work runs on Apify. This package is a thin client that starts the actor run, waits for it, and hands back the dataset rows.
27
+
28
+ ## Quick start
29
+
30
+ You need Node.js 18 or newer and an Apify account with an API token.
31
+
32
+ Add this to your Claude Desktop config (`claude_desktop_config.json`), Cursor, or any MCP client:
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "mamba-sequencer-event-poller": {
38
+ "command": "npx",
39
+ "args": [
40
+ "-y",
41
+ "@mambalabsdev/mcp-sequencer-event-poller"
42
+ ],
43
+ "env": {
44
+ "APIFY_TOKEN": "your-apify-token",
45
+ "LEMLIST_API_KEY": "your-lemlist-key"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ Restart the client. The `poll_sequencer_events` tool appears.
53
+
54
+ ## Prerequisites
55
+
56
+ - Node.js 18 or newer.
57
+ - An Apify API token from [console.apify.com/account/integrations](https://console.apify.com/account/integrations), set as `APIFY_TOKEN`. The server lists its tool without a token; a call needs one.
58
+ - At least one of your own vendor keys: `INSTANTLY_API_KEY` (API v2, read scope; Instantly API access needs a paid Instantly plan), `SMARTLEAD_API_KEY`, `HEYREACH_API_KEY`, `LEMLIST_API_KEY`. With none set, a call returns one summary row that says no key was given.
59
+
60
+ ## Example prompts
61
+
62
+ - "Which leads replied in Smartlead or lemlist in the last 24 hours?"
63
+ - "List every bounce and unsubscribe across my sequencers this week."
64
+ - "Who replied on LinkedIn through HeyReach since Monday, and what did they say?"
65
+
66
+ ## Tool
67
+
68
+ `poll_sequencer_events`. One tool. Example arguments:
69
+
70
+ ```json
71
+ {
72
+ "since_hours": "24",
73
+ "event_types": ["reply", "linkedin_reply", "bounce", "meeting_booked"]
74
+ }
75
+ ```
76
+
77
+ ## Inputs
78
+
79
+ Every buyer facing input of the actor except the four vendor keys, which are read from this server's environment, never from tool arguments. Omitted inputs take the actor's own defaults. Numbers and yes or no options are sent as text ("24", "true"), which is what the actor accepts; a value that does not parse comes back as one free row that names the field.
80
+
81
+ | Input | Type | Required | Description |
82
+ |---|---|---|---|
83
+ | `since_hours` | string | no | Look back this many hours, 1 to 2160, as text such as "24". Default 24. |
84
+ | `since`, `until` | string | no | Optional exact window in UTC. |
85
+ | `event_types` | array | no | Any of reply, linkedin_reply, bounce, unsubscribe, meeting_booked, interested, not_interested, out_of_office, connection_accepted, open, click. |
86
+ | `only_new` | string | no | "true" or "false". Skip events an earlier run returned. Default true. |
87
+ | `state_key` | string | no | Name for the only new events memory. |
88
+ | `instantly_campaign_ids`, `smartlead_campaign_ids`, `heyreach_campaign_ids`, `lemlist_campaign_ids` | array | no | Read only these campaigns. |
89
+ | `max_pages_per_query` | string | no | Pages of 100 records per vendor query, 1 to 100, as text. Default 20. |
90
+ | `max_events` | string | no | Event rows per run, up to 50000, as text. Default 5000. |
91
+ | `max_charge_usd` | string | no | Optional cost cap for the run. |
92
+
93
+ ## Pricing
94
+
95
+ Pay per event on Apify, billed to your Apify account. Prices in USD.
96
+
97
+ | Event | Free plan | Bronze | Silver | Gold |
98
+ |---|---|---|---|---|
99
+ | `event-row`, per sequencer event | $0.008 | $0.0076 | $0.0072 | $0.0068 |
100
+ | `apify-actor-start`, per run start | $0.001 | $0.001 | $0.001 | $0.001 |
101
+
102
+ The run summary row and already delivered events are free. Mamba Labs pays the platform costs of the run.
103
+
104
+ ## Your keys
105
+
106
+ The actor stores no key. Each vendor key is your own: this server reads it from its environment and sends it in the run input of that run only. The vendor API calls run on your own vendor account, under that vendor's plan and rate limits.
107
+
108
+ ## Full actor documentation
109
+
110
+ [apify.com/mambalabs/sequencer-event-poller](https://apify.com/mambalabs/sequencer-event-poller)
111
+
112
+ ## License
113
+
114
+ MIT. See [LICENSE](LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,31 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ The latest published `1.x` release of
6
+ `@mambalabsdev/mcp-sequencer-event-poller` receives security updates.
7
+
8
+ | Version | Supported |
9
+ | ------- | ------------------ |
10
+ | 1.x | :white_check_mark: |
11
+ | < 1.0 | :x: |
12
+
13
+ ## Reporting a vulnerability
14
+
15
+ Please do not open a public GitHub issue for security reports.
16
+
17
+ Email security reports to **labs@mambamindsetgrowth.com** with:
18
+
19
+ - a description of the issue and its impact,
20
+ - steps to reproduce, and
21
+ - any relevant logs or proof of concept.
22
+
23
+ We aim to acknowledge reports within 3 business days and to provide a remediation
24
+ timeline after triage. Coordinated disclosure is appreciated.
25
+
26
+ ## Handling of credentials
27
+
28
+ This server reads an `APIFY_TOKEN` from the environment and uses it only to call
29
+ the Apify API on your behalf. The token is never logged or written to disk by this
30
+ package. Treat your `APIFY_TOKEN` as a secret and rotate it at
31
+ https://console.apify.com/account/integrations if you believe it has been exposed.
package/build/index.js ADDED
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { z } from "zod";
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
10
+ // Distinctive UA so Apify run meta.userAgent marks MCP-originated runs.
11
+ const USER_AGENT = `mambalabs-mcp ${pkg.name}@${pkg.version}`;
12
+ // Drop undefined values so optional inputs are not sent to the actor.
13
+ function compact(obj) {
14
+ const out = {};
15
+ for (const [k, v] of Object.entries(obj)) {
16
+ if (v !== undefined)
17
+ out[k] = v;
18
+ }
19
+ return out;
20
+ }
21
+ // How long the actor run itself is allowed to take, in seconds. Fleet standard
22
+ // (standing build rule 5, 2026-10-05). A large Instantly backfill is paced at
23
+ // about 3 s per request, so a long window can take several minutes.
24
+ const ACTOR_RUN_TIMEOUT_SECS = 1800;
25
+ // How long this wrapper waits for that run, in milliseconds. The actor's own
26
+ // timeout plus two minutes, so the run's own TIMED-OUT status is what the
27
+ // caller sees rather than the wrapper giving up first and reporting nothing.
28
+ const WRAPPER_WAIT_MS = (ACTOR_RUN_TIMEOUT_SECS + 120) * 1000;
29
+ const POLL_INTERVAL_MS = 3000;
30
+ const TERMINAL = new Set(["SUCCEEDED", "FAILED", "TIMED-OUT", "ABORTED", "ABORTING"]);
31
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
32
+ // Shared caller. actorPath is the actor's immutable Apify actor ID (a stable key
33
+ // that survives Store renames). The /v2/acts/{id} endpoint accepts it directly,
34
+ // so a Store rename never breaks these calls.
35
+ //
36
+ // START AND POLL, NOT RUN-SYNC. Apify's synchronous endpoints carry a platform
37
+ // ceiling of 300 seconds on the HTTP wait itself and answer 408 past it whatever
38
+ // the timeout parameter says, so a long run reads as a timeout even though the
39
+ // actor goes on to finish. Starting the run, polling it to a terminal status and
40
+ // then reading the dataset is the only way to wait as long as the actor needs.
41
+ //
42
+ // The token is read here rather than at module load, so the tool registers
43
+ // unconditionally and a server started without APIFY_TOKEN still advertises its
44
+ // capabilities instead of reporting none.
45
+ async function runActor(actorPath, actorLabel, input) {
46
+ const APIFY_TOKEN = process.env.APIFY_TOKEN;
47
+ if (!APIFY_TOKEN) {
48
+ return { isError: true, content: [{ type: "text", text: "APIFY_TOKEN is not set. Create a token at https://console.apify.com/account/integrations and set it as the APIFY_TOKEN environment variable." }] };
49
+ }
50
+ const headers = {
51
+ Authorization: `Bearer ${APIFY_TOKEN}`,
52
+ "Content-Type": "application/json",
53
+ "User-Agent": USER_AGENT,
54
+ };
55
+ const httpError = async (response) => {
56
+ let detail = "";
57
+ try {
58
+ const body = (await response.json());
59
+ if (body?.error?.message)
60
+ detail = ` ${body.error.message}`;
61
+ }
62
+ catch {
63
+ detail = "";
64
+ }
65
+ switch (response.status) {
66
+ case 400:
67
+ return `The ${actorLabel} run was rejected as invalid input.${detail}`;
68
+ case 401:
69
+ return "Invalid Apify token. Check your APIFY_TOKEN environment variable.";
70
+ case 402:
71
+ return "Insufficient Apify credits. Check your account balance at https://console.apify.com/billing";
72
+ default:
73
+ return `Apify request to ${actorLabel} failed with status ${response.status}.${detail}`;
74
+ }
75
+ };
76
+ // 1. Start the run.
77
+ let started;
78
+ try {
79
+ started = await fetch(`https://api.apify.com/v2/acts/${actorPath}/runs?timeout=${ACTOR_RUN_TIMEOUT_SECS}`, { method: "POST", headers, body: JSON.stringify(input) });
80
+ }
81
+ catch (err) {
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ return { isError: true, content: [{ type: "text", text: `Could not reach the Apify API: ${message}` }] };
84
+ }
85
+ if (!started.ok) {
86
+ return { isError: true, content: [{ type: "text", text: await httpError(started) }] };
87
+ }
88
+ let run;
89
+ try {
90
+ run = (await started.json()).data ?? {};
91
+ }
92
+ catch (err) {
93
+ const message = err instanceof Error ? err.message : String(err);
94
+ return { isError: true, content: [{ type: "text", text: `The ${actorLabel} run start returned a response that could not be parsed: ${message}` }] };
95
+ }
96
+ const runId = run.id;
97
+ if (!runId) {
98
+ return { isError: true, content: [{ type: "text", text: `The ${actorLabel} run start returned no run id, so there is nothing to wait for.` }] };
99
+ }
100
+ // 2. Poll to a terminal status.
101
+ const deadline = Date.now() + WRAPPER_WAIT_MS;
102
+ let status = run.status ?? "READY";
103
+ let datasetId = run.defaultDatasetId;
104
+ while (!TERMINAL.has(status)) {
105
+ if (Date.now() >= deadline) {
106
+ return {
107
+ isError: true,
108
+ content: [{ type: "text", text: `The ${actorLabel} run ${runId} was still ${status} after ${Math.round(WRAPPER_WAIT_MS / 1000)} seconds and this call stopped waiting. The run itself is still on Apify: read it at https://console.apify.com/actors/runs/${runId}` }],
109
+ };
110
+ }
111
+ await sleep(POLL_INTERVAL_MS);
112
+ let poll;
113
+ try {
114
+ poll = await fetch(`https://api.apify.com/v2/actor-runs/${runId}`, { headers });
115
+ }
116
+ catch (err) {
117
+ const message = err instanceof Error ? err.message : String(err);
118
+ return { isError: true, content: [{ type: "text", text: `Lost contact with the Apify API while waiting for ${actorLabel} run ${runId}: ${message}` }] };
119
+ }
120
+ if (!poll.ok) {
121
+ return { isError: true, content: [{ type: "text", text: await httpError(poll) }] };
122
+ }
123
+ const body = (await poll.json());
124
+ status = body.data?.status ?? status;
125
+ datasetId = body.data?.defaultDatasetId ?? datasetId;
126
+ }
127
+ // 3. A run that did not succeed is a failure the caller must see, never an
128
+ // empty success. Surfacing it here is what keeps a crashed run from reading
129
+ // as "no results found".
130
+ if (status !== "SUCCEEDED") {
131
+ return {
132
+ isError: true,
133
+ content: [{ type: "text", text: `The ${actorLabel} run did not succeed (run ID: ${runId}, status: ${status}).` }],
134
+ };
135
+ }
136
+ if (!datasetId) {
137
+ return { isError: true, content: [{ type: "text", text: `The ${actorLabel} run ${runId} succeeded but reported no dataset, so there is nothing to return.` }] };
138
+ }
139
+ // 4. Read the dataset.
140
+ let ds;
141
+ try {
142
+ ds = await fetch(`https://api.apify.com/v2/datasets/${datasetId}/items?format=json`, { headers });
143
+ }
144
+ catch (err) {
145
+ const message = err instanceof Error ? err.message : String(err);
146
+ return { isError: true, content: [{ type: "text", text: `Could not read the ${actorLabel} dataset: ${message}` }] };
147
+ }
148
+ if (!ds.ok) {
149
+ return { isError: true, content: [{ type: "text", text: await httpError(ds) }] };
150
+ }
151
+ let items;
152
+ try {
153
+ items = await ds.json();
154
+ }
155
+ catch (err) {
156
+ const message = err instanceof Error ? err.message : String(err);
157
+ return { isError: true, content: [{ type: "text", text: `The ${actorLabel} run returned a response that could not be parsed: ${message}` }] };
158
+ }
159
+ if (!Array.isArray(items)) {
160
+ const asObj = items;
161
+ const detail = asObj?.error?.message
162
+ ? `${asObj.error.message}`
163
+ : JSON.stringify(items);
164
+ return { isError: true, content: [{ type: "text", text: `The ${actorLabel} run did not return a dataset. ${detail}` }] };
165
+ }
166
+ return { content: [{ type: "text", text: JSON.stringify(items, null, 2) }] };
167
+ }
168
+ const server = new McpServer({
169
+ name: "mamba-sequencer-event-poller",
170
+ version: pkg.version,
171
+ });
172
+ // Provider keys come from this server's own environment, never from tool
173
+ // arguments, so an agent transcript never carries them. Each is the caller's
174
+ // own key; the actor stores none.
175
+ function keysFromEnv() {
176
+ const out = {};
177
+ const k0 = process.env.INSTANTLY_API_KEY?.trim();
178
+ if (k0)
179
+ out.instantly_api_key = k0;
180
+ const k1 = process.env.SMARTLEAD_API_KEY?.trim();
181
+ if (k1)
182
+ out.smartlead_api_key = k1;
183
+ const k2 = process.env.HEYREACH_API_KEY?.trim();
184
+ if (k2)
185
+ out.heyreach_api_key = k2;
186
+ const k3 = process.env.LEMLIST_API_KEY?.trim();
187
+ if (k3)
188
+ out.lemlist_api_key = k3;
189
+ return out;
190
+ }
191
+ // Sequencer Event Poller (immutable actor ID S6s8Rjd61tGdrMRk4). Every buyer facing input of the actor is exposed except the four vendor keys, which come from the environment (see keysFromEnv). The actor takes numbers and booleans as strings, so those inputs are strings here too.
192
+ const bool = () => z.enum(["true", "false"]).optional();
193
+ server.registerTool("poll_sequencer_events", {
194
+ title: "Poll sequencer events",
195
+ description: "Read replies, bounces, unsubscribes, meetings booked, interest changes, and LinkedIn replies from your own Instantly, Smartlead, HeyReach, and lemlist accounts for a time window. Returns one flat row per event (vendor, event type, time, lead email and name, company, campaign, reply text where the vendor returns it) plus one free run summary row with counts and the status of each vendor. Vendor keys are read from this server's environment (INSTANTLY_API_KEY, SMARTLEAD_API_KEY, HEYREACH_API_KEY, LEMLIST_API_KEY); vendors with no key are skipped. Read-only: it never creates, edits, pauses, or sends anything in a sequencer. A run that does not succeed is returned as an error with its run ID. Requires an APIFY_TOKEN and is billed per event row.",
196
+ annotations: {
197
+ title: "Poll sequencer events",
198
+ readOnlyHint: true,
199
+ destructiveHint: false,
200
+ idempotentHint: false,
201
+ openWorldHint: true,
202
+ },
203
+ inputSchema: {
204
+ since_hours: z.string().optional().describe("Read events from this many hours before the run, 1 to 2160 (90 days). Default 24. Ignored when since is set."),
205
+ since: z.string()
206
+ .optional()
207
+ .describe("Optional start of the window in UTC, for example 2026-10-20T00:00:00Z."),
208
+ until: z.string()
209
+ .optional()
210
+ .describe("Optional end of the window in UTC. Default now."),
211
+ event_types: z.array(z.enum(["reply", "linkedin_reply", "bounce", "unsubscribe", "meeting_booked", "interested", "not_interested", "out_of_office", "connection_accepted", "open", "click"]))
212
+ .optional()
213
+ .describe("Which events to return. Default: reply, linkedin_reply, bounce, unsubscribe, meeting_booked, interested, connection_accepted."),
214
+ only_new: bool().describe("Skip events an earlier run already returned (free). Default true."),
215
+ state_key: z.string()
216
+ .optional()
217
+ .describe("Optional name for the only new events memory, so two schedules keep separate memories."),
218
+ instantly_campaign_ids: z.array(z.string())
219
+ .optional()
220
+ .describe("Read only these Instantly campaigns (UUIDs). Empty: all campaigns."),
221
+ smartlead_campaign_ids: z.array(z.string())
222
+ .optional()
223
+ .describe("Read only these Smartlead campaigns. Empty: all non draft campaigns."),
224
+ heyreach_campaign_ids: z.array(z.string())
225
+ .optional()
226
+ .describe("Read only these HeyReach campaigns (numeric ids). Empty: all campaigns."),
227
+ lemlist_campaign_ids: z.array(z.string())
228
+ .optional()
229
+ .describe("Read only these lemlist campaigns (cam_ ids). Empty: all campaigns."),
230
+ max_pages_per_query: z.string().optional().describe("Pages of 100 records per vendor query, 1 to 100. Default 20."),
231
+ max_events: z.string().optional().describe("Event rows per run, oldest first, up to 50000. Each event row is billed. Default 5000."),
232
+ max_charge_usd: z.string()
233
+ .optional()
234
+ .describe("Optional. The run stops before a charge that would pass this amount."),
235
+ },
236
+ }, async (args) => runActor("S6s8Rjd61tGdrMRk4", "Sequencer Event Poller", { ...compact(args), ...keysFromEnv() }));
237
+ const transport = new StdioServerTransport();
238
+ await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "@mambalabsdev/mcp-sequencer-event-poller",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "MCP server for Sequencer Event Poller. Replies, bounces, unsubscribes, meetings, and LinkedIn replies from your own Instantly, Smartlead, HeyReach, and lemlist accounts, one row per event. Read only. Runs on Apify.",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-sequencer-event-poller": "./build/index.js"
8
+ },
9
+ "files": [
10
+ "build",
11
+ "README.md",
12
+ "LICENSE",
13
+ "SECURITY.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc && chmod +x build/index.js",
17
+ "test": "npm run build && node --test test/*.test.js",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "model-context-protocol",
23
+ "instantly",
24
+ "smartlead",
25
+ "heyreach",
26
+ "lemlist",
27
+ "cold-email",
28
+ "replies",
29
+ "apify",
30
+ "clay"
31
+ ],
32
+ "author": "Mamba Labs <labs@mambamindsetgrowth.com>",
33
+ "license": "MIT",
34
+ "homepage": "https://apify.com/mambalabs/sequencer-event-poller",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/mambalabsdev/mcp-sequencer-event-poller"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "dependencies": {
43
+ "@modelcontextprotocol/sdk": "^1.32.0",
44
+ "zod": "^4.4.3"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^26.2.0",
48
+ "typescript": "5.9.3"
49
+ },
50
+ "mcpName": "com.mambabuilt/mcp-sequencer-event-poller"
51
+ }