nitrosend-mcp 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 +42 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +24 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# nitrosend-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [Nitrosend](https://nitrosend.com) — connect Claude to your email marketing platform.
|
|
4
|
+
|
|
5
|
+
Manage contacts, compose emails, build automated flows, and launch campaigns through natural language.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
claude mcp add nitro -e NITROSEND_API_KEY=nskey_live_... -- npx -y nitrosend-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Get your API key
|
|
14
|
+
|
|
15
|
+
1. Log in at [nitrosend.com](https://nitrosend.com)
|
|
16
|
+
2. Go to **Settings > API Keys**
|
|
17
|
+
3. Copy your live key (starts with `nskey_live_`)
|
|
18
|
+
|
|
19
|
+
## What you can do
|
|
20
|
+
|
|
21
|
+
Once connected, Claude can:
|
|
22
|
+
|
|
23
|
+
- **Read** — query contacts, segments, flows, campaigns, and account status
|
|
24
|
+
- **Compose** — create emails with sections, build multi-step flows, set up campaigns
|
|
25
|
+
- **Manage** — import contacts, create segments, manage lists and tags
|
|
26
|
+
- **Deliver** — preview emails, run spam checks, send tests, approve and schedule campaigns
|
|
27
|
+
- **Insights** — view open/click/unsubscribe metrics and trends
|
|
28
|
+
|
|
29
|
+
## Environment variables
|
|
30
|
+
|
|
31
|
+
| Variable | Required | Description |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `NITROSEND_API_KEY` | Yes | Your API key (`nskey_live_...`) |
|
|
34
|
+
| `NITROSEND_API_URL` | No | Override API endpoint (defaults to `https://api.nitrosend.com/mcp`) |
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
- Node.js 18+
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
package/dist/auth.d.ts
ADDED
package/dist/auth.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const DEFAULT_API_URL = "https://api.nitrosend.com/mcp";
|
|
2
|
+
export function getApiKey() {
|
|
3
|
+
const key = process.env.NITROSEND_API_KEY;
|
|
4
|
+
if (!key) {
|
|
5
|
+
console.error("Error: NITROSEND_API_KEY is not set.\n\n" +
|
|
6
|
+
"Set your API key:\n" +
|
|
7
|
+
" export NITROSEND_API_KEY=nskey_live_...\n\n" +
|
|
8
|
+
"Get your key at: https://nitrosend.com/settings/api-keys\n\n" +
|
|
9
|
+
"Or pass it when adding the server:\n" +
|
|
10
|
+
" claude mcp add nitro -e NITROSEND_API_KEY=nskey_live_... -- npx -y nitrosend-mcp");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
if (!key.startsWith("nskey_live_")) {
|
|
14
|
+
console.error("Error: Invalid API key format.\n\n" +
|
|
15
|
+
"API keys must start with nskey_live_.\n" +
|
|
16
|
+
"Get your key at: https://nitrosend.com/settings/api-keys");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
return key;
|
|
20
|
+
}
|
|
21
|
+
export function getApiUrl() {
|
|
22
|
+
return process.env.NITROSEND_API_URL || DEFAULT_API_URL;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,+BAA+B,CAAC;AAExD,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAE1C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CACX,0CAA0C;YACxC,qBAAqB;YACrB,+CAA+C;YAC/C,8DAA8D;YAC9D,sCAAsC;YACtC,oFAAoF,CACvF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CACX,oCAAoC;YAClC,yCAAyC;YACzC,0DAA0D,CAC7D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,eAAe,CAAC;AAC1D,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { getApiKey, getApiUrl } from "./auth.js";
|
|
4
|
+
const apiKey = getApiKey();
|
|
5
|
+
const apiUrl = getApiUrl();
|
|
6
|
+
const RETRY_DELAYS = [100, 300];
|
|
7
|
+
async function forward(line) {
|
|
8
|
+
let lastError = null;
|
|
9
|
+
for (let attempt = 0; attempt <= RETRY_DELAYS.length; attempt++) {
|
|
10
|
+
try {
|
|
11
|
+
const res = await fetch(apiUrl, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
Authorization: `Bearer ${apiKey}`,
|
|
16
|
+
},
|
|
17
|
+
body: line,
|
|
18
|
+
});
|
|
19
|
+
if (res.status === 202) {
|
|
20
|
+
// JSON-RPC notification — no response body
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
if (res.ok) {
|
|
24
|
+
return await res.text();
|
|
25
|
+
}
|
|
26
|
+
// 401/403 — don't retry auth errors
|
|
27
|
+
if (res.status === 401 || res.status === 403) {
|
|
28
|
+
console.error(`Auth error (${res.status}): Check your NITROSEND_API_KEY`);
|
|
29
|
+
return jsonRpcError(-32000, `Authentication failed (${res.status})`);
|
|
30
|
+
}
|
|
31
|
+
// 5xx — retry
|
|
32
|
+
if (res.status >= 500 && attempt < RETRY_DELAYS.length) {
|
|
33
|
+
await sleep(RETRY_DELAYS[attempt]);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
return jsonRpcError(-32000, `API returned ${res.status}`);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
lastError = err;
|
|
40
|
+
// Network error — retry
|
|
41
|
+
if (attempt < RETRY_DELAYS.length) {
|
|
42
|
+
await sleep(RETRY_DELAYS[attempt]);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const msg = lastError?.message || "Unknown network error";
|
|
48
|
+
console.error(`Network error: ${msg}`);
|
|
49
|
+
return jsonRpcError(-32000, `Network error: ${msg}`);
|
|
50
|
+
}
|
|
51
|
+
function jsonRpcError(code, message) {
|
|
52
|
+
return JSON.stringify({
|
|
53
|
+
jsonrpc: "2.0",
|
|
54
|
+
error: { code, message },
|
|
55
|
+
id: null,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function sleep(ms) {
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
61
|
+
const rl = createInterface({ input: process.stdin });
|
|
62
|
+
rl.on("line", async (line) => {
|
|
63
|
+
const trimmed = line.trim();
|
|
64
|
+
if (!trimmed)
|
|
65
|
+
return;
|
|
66
|
+
const response = await forward(trimmed);
|
|
67
|
+
if (response) {
|
|
68
|
+
process.stdout.write(response + "\n");
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
rl.on("close", () => {
|
|
72
|
+
process.exit(0);
|
|
73
|
+
});
|
|
74
|
+
console.error(`Nitrosend MCP bridge started (${apiUrl})`);
|
|
75
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nitrosend-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Nitrosend — connect Claude to your email marketing platform",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nitrosend-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc && shx chmod +x dist/*.js",
|
|
15
|
+
"prepare": "npm run build",
|
|
16
|
+
"dev": "tsc --watch"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22",
|
|
23
|
+
"shx": "^0.3.4",
|
|
24
|
+
"typescript": "^5.6.0"
|
|
25
|
+
}
|
|
26
|
+
}
|