zapsmtp-mcp 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +311 -2
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +16 -0
- package/dist/bin.js.map +1 -0
- package/dist/catalog.d.ts +30 -0
- package/dist/catalog.js +80 -0
- package/dist/catalog.js.map +1 -0
- package/dist/docs.d.ts +13 -0
- package/dist/docs.js +22 -0
- package/dist/docs.js.map +1 -0
- package/dist/generated/api.d.ts +2 -0
- package/dist/generated/api.js +5721 -0
- package/dist/generated/api.js.map +1 -0
- package/dist/generated/model.d.ts +89 -0
- package/dist/generated/model.js +37 -0
- package/dist/generated/model.js.map +1 -0
- package/dist/http.d.ts +25 -0
- package/dist/http.js +122 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +28 -0
- package/dist/main.js +123 -0
- package/dist/main.js.map +1 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.js +56 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +82 -0
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +46 -0
- package/dist/tools.js +342 -0
- package/dist/tools.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/docs/actions.md +13 -0
- package/docs/ai-tools.md +136 -0
- package/docs/analytics.md +1881 -0
- package/docs/click-actions.md +320 -0
- package/docs/conventions.md +131 -0
- package/docs/dashboard.md +69 -0
- package/docs/deliverability.md +1483 -0
- package/docs/domain-setup.md +1494 -0
- package/docs/domains.md +19 -0
- package/docs/emails.md +20 -0
- package/docs/inbound-guide.md +2188 -0
- package/docs/inbound.md +24 -0
- package/docs/index.json +240 -0
- package/docs/index.md +224 -0
- package/docs/keys.md +15 -0
- package/docs/llms.txt +176 -0
- package/docs/logs.md +11 -0
- package/docs/migration.md +1779 -0
- package/docs/platform.md +10 -0
- package/docs/receiving.md +19 -0
- package/docs/recipes.md +3594 -0
- package/docs/sdks.md +311 -0
- package/docs/sending.md +972 -0
- package/docs/smtp.md +183 -0
- package/docs/stats.md +12 -0
- package/docs/suppressions.md +14 -0
- package/docs/teams.md +36 -0
- package/docs/template-editor.md +62 -0
- package/docs/template-library.md +17 -0
- package/docs/templates.md +20 -0
- package/docs/templating.md +1613 -0
- package/docs/testing.md +153 -0
- package/docs/variables.md +11 -0
- package/docs/webhook-events.md +246 -0
- package/docs/webhooks.md +19 -0
- package/package.json +59 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ZapSMTP
|
|
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,312 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ZapSMTP MCP server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The official [Model Context Protocol](https://modelcontextprotocol.io) server for
|
|
4
|
+
[ZapSMTP](https://zapsmtp.com): let Claude, Cursor, VS Code, Codex and any other MCP client send,
|
|
5
|
+
receive and track email, and manage templates, domains, webhooks and everything else the API does.
|
|
6
|
+
|
|
7
|
+
- **The whole API**: one tool per API operation (112), generated from the API reference, so a new
|
|
8
|
+
endpoint becomes a tool with the next release. Clear descriptions and JSON Schemas with every
|
|
9
|
+
parameter, required field and allowed value.
|
|
10
|
+
- **Safe to hand to an agent**: tool annotations (read-only, destructive, idempotent, open-world) for
|
|
11
|
+
clients that ask before acting, `--read-only`, toolsets, a recipient domain allowlist, and sends that
|
|
12
|
+
never repeat when retried. The API key never reaches the model.
|
|
13
|
+
- **Made for agents**: `send_test_email` tries any delivery outcome on simulator addresses that never
|
|
14
|
+
leave ZapSMTP; `verify_webhook_signature` checks webhook requests; lists come back one page at a time
|
|
15
|
+
with a cursor for the next; errors carry the API's code, message and request id.
|
|
16
|
+
- **stdio or Streamable HTTP**: run it next to your editor, or serve a team over HTTP where every client
|
|
17
|
+
brings its own API key.
|
|
18
|
+
- **The docs as resources**: `llms.txt` and every guide, bundled in the package (nothing is fetched at
|
|
19
|
+
runtime).
|
|
20
|
+
|
|
21
|
+
Node.js 18.3 or newer. Built on the official [Node.js SDK](https://www.npmjs.com/package/zapsmtp).
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
Create an API key in the [dashboard](https://zapsmtp.com) (a `zap_test_…` key runs everything without
|
|
26
|
+
delivering anything), then add the server to your client.
|
|
27
|
+
|
|
28
|
+
### Claude Code
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
claude mcp add zapsmtp -e ZAP_API_KEY=zap_... -- npx -y zapsmtp-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
With a default sender and only the tools you need:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
claude mcp add zapsmtp -e ZAP_API_KEY=zap_... -e ZAP_SENDER="Acme <hello@acme.com>" \
|
|
38
|
+
-- npx -y zapsmtp-mcp --toolsets emails,templates,simulator
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Claude Desktop
|
|
42
|
+
|
|
43
|
+
Settings → Developer → Edit Config (`claude_desktop_config.json`):
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"zapsmtp": {
|
|
49
|
+
"command": "npx",
|
|
50
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
51
|
+
"env": { "ZAP_API_KEY": "zap_..." }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Cursor
|
|
58
|
+
|
|
59
|
+
`~/.cursor/mcp.json` (every project) or `.cursor/mcp.json` (one project):
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"zapsmtp": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
67
|
+
"env": { "ZAP_API_KEY": "zap_..." }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### VS Code (GitHub Copilot agent mode)
|
|
74
|
+
|
|
75
|
+
`.vscode/mcp.json`; VS Code asks for the key once and stores it securely:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"inputs": [
|
|
80
|
+
{ "type": "promptString", "id": "zapsmtp-key", "description": "ZapSMTP API key", "password": true }
|
|
81
|
+
],
|
|
82
|
+
"servers": {
|
|
83
|
+
"zapsmtp": {
|
|
84
|
+
"type": "stdio",
|
|
85
|
+
"command": "npx",
|
|
86
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
87
|
+
"env": { "ZAP_API_KEY": "${input:zapsmtp-key}" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### OpenAI Codex
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
codex mcp add zapsmtp --env ZAP_API_KEY=zap_... -- npx -y zapsmtp-mcp
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
or in `~/.codex/config.toml`:
|
|
100
|
+
|
|
101
|
+
```toml
|
|
102
|
+
[mcp_servers.zapsmtp]
|
|
103
|
+
command = "npx"
|
|
104
|
+
args = ["-y", "zapsmtp-mcp"]
|
|
105
|
+
env = { ZAP_API_KEY = "zap_..." }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Windsurf
|
|
109
|
+
|
|
110
|
+
`~/.codeium/windsurf/mcp_config.json`:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mcpServers": {
|
|
115
|
+
"zapsmtp": {
|
|
116
|
+
"command": "npx",
|
|
117
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
118
|
+
"env": { "ZAP_API_KEY": "zap_..." }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Zed
|
|
125
|
+
|
|
126
|
+
`settings.json`:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"context_servers": {
|
|
131
|
+
"zapsmtp": {
|
|
132
|
+
"source": "custom",
|
|
133
|
+
"command": "npx",
|
|
134
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
135
|
+
"env": { "ZAP_API_KEY": "zap_..." }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Gemini CLI
|
|
142
|
+
|
|
143
|
+
`~/.gemini/settings.json` (Gemini CLI expands `$ZAP_API_KEY` from your environment):
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"mcpServers": {
|
|
148
|
+
"zapsmtp": {
|
|
149
|
+
"command": "npx",
|
|
150
|
+
"args": ["-y", "zapsmtp-mcp"],
|
|
151
|
+
"env": { "ZAP_API_KEY": "$ZAP_API_KEY" }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Any other client
|
|
158
|
+
|
|
159
|
+
Run `npx -y zapsmtp-mcp` over stdio with `ZAP_API_KEY` in its environment, or connect to the HTTP
|
|
160
|
+
server below.
|
|
161
|
+
|
|
162
|
+
## Streamable HTTP
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npx -y zapsmtp-mcp --http # http://127.0.0.1:3000/mcp
|
|
166
|
+
npx -y zapsmtp-mcp --http --port 8080 --host 0.0.0.0
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The HTTP server holds no API key. Every client sends its own as `Authorization: Bearer <key>`, and each
|
|
170
|
+
request gets its own SDK client and MCP server (the server is stateless), so one client's key is never
|
|
171
|
+
used for another's calls. A request without a key gets `401`.
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
claude mcp add --transport http zapsmtp http://127.0.0.1:3000/mcp --header "Authorization: Bearer zap_..."
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"mcpServers": {
|
|
180
|
+
"zapsmtp": { "url": "http://127.0.0.1:3000/mcp", "headers": { "Authorization": "Bearer zap_..." } }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- It listens on `127.0.0.1` unless `--host` says otherwise, and while on loopback it refuses requests
|
|
186
|
+
whose `Host` or `Origin` is not local (DNS rebinding).
|
|
187
|
+
- Beyond your machine, put it behind HTTPS (a reverse proxy): the key travels in a header.
|
|
188
|
+
- `GET /health` answers `{"status": "ok"}` for load balancers. Request bodies are limited to 64 MiB.
|
|
189
|
+
|
|
190
|
+
## Options
|
|
191
|
+
|
|
192
|
+
| Flag | Environment | Default | |
|
|
193
|
+
|---|---|---|---|
|
|
194
|
+
| `--key <key>` | `ZAP_API_KEY` | | API key (stdio). Not used with `--http`. |
|
|
195
|
+
| `--http` | | off | Serve Streamable HTTP at `/mcp` instead of stdio |
|
|
196
|
+
| `--port <port>` | `ZAP_MCP_PORT` | `3000` | HTTP port |
|
|
197
|
+
| `--host <host>` | `ZAP_MCP_HOST` | `127.0.0.1` | HTTP address |
|
|
198
|
+
| `--toolsets <a,b>` | `ZAP_TOOLSETS` | the defaults below | Toolsets to expose, or `all` |
|
|
199
|
+
| `--read-only` | `ZAP_READ_ONLY=1` | off | Only tools that change nothing |
|
|
200
|
+
| `--sender <address>` | `ZAP_SENDER` | | From for sends that omit it; without one, sends require `from` |
|
|
201
|
+
| `--reply-to <address>` | `ZAP_REPLY_TO` | | Reply-To for sends that omit it |
|
|
202
|
+
| `--allowed-recipient-domains <a,b>` | `ZAP_ALLOWED_RECIPIENT_DOMAINS` | | Refuse sends to any other domain |
|
|
203
|
+
| `--base-url <url>` | `ZAP_BASE_URL` | `https://api.zapsmtp.com/v1` | API base URL |
|
|
204
|
+
| `--list-tools` | | | Print the tools these options expose, and exit |
|
|
205
|
+
| `-h`, `--help` / `-v`, `--version` | | | |
|
|
206
|
+
|
|
207
|
+
Flags win over the environment.
|
|
208
|
+
|
|
209
|
+
## Toolsets
|
|
210
|
+
|
|
211
|
+
The default toolsets give 76 tools; `--read-only` leaves 41 of them. Clients that slow down with many
|
|
212
|
+
tools do best with just the toolsets they need: `--toolsets emails,simulator` is 14 tools.
|
|
213
|
+
|
|
214
|
+
| Toolset | Default | Tools | |
|
|
215
|
+
|---|---|---|---|
|
|
216
|
+
| `emails` | yes | 12 | `emails_send`, `emails_send_batch`, `emails_list`, `emails_get`, `emails_update`, `emails_cancel`, `emails_get_content`, `emails_spam_check`, `emails_spam_check_sent`, `emails_attachments_list`, `emails_attachments_get`, `emails_share` |
|
|
217
|
+
| `receiving` | yes | 8 | `emails_receiving_list`, `emails_receiving_get`, `emails_receiving_delete`, `emails_receiving_attachments_list`, `emails_receiving_attachments_get`, `emails_receiving_redeliver`, `emails_receiving_report_spam`, `emails_receiving_reply` |
|
|
218
|
+
| `threads` | yes | 3 | `threads_list`, `threads_get`, `threads_update` |
|
|
219
|
+
| `templates` | yes | 12 | `templates_list`, `templates_create`, `templates_get`, `templates_update`, `templates_delete`, `templates_render`, `templates_render_source`, `templates_publish`, `templates_duplicate`, `templates_versions_list`, `templates_versions_get`, `templates_versions_restore` |
|
|
220
|
+
| `variables` | yes | 3 | `variables_list`, `variables_set_global`, `variables_delete_global` |
|
|
221
|
+
| `domains` | yes | 11 | `domains_list`, `domains_create`, `domains_get`, `domains_update`, `domains_verify`, `domains_delete`, `domains_get_dmarc`, `domains_get_reputation`, `domains_check_reputation`, `domains_get_brand`, `domains_update_brand` |
|
|
222
|
+
| `webhooks` | yes | 12 | `webhooks_list`, `webhooks_create`, `webhooks_get`, `webhooks_update`, `webhooks_delete`, `webhooks_test`, `webhooks_list_deliveries`, `webhooks_rotate_secret`, `webhooks_events_replay`, `webhooks_events_list`, `webhooks_events_get`, `verify_webhook_signature` |
|
|
223
|
+
| `suppressions` | yes | 6 | `suppressions_list`, `suppressions_create`, `suppressions_delete`, `suppressions_get`, `suppressions_create_batch`, `suppressions_delete_batch` |
|
|
224
|
+
| `logs` | yes | 2 | `logs_list`, `logs_get` |
|
|
225
|
+
| `stats` | yes | 4 | `stats_get`, `stats_timeseries`, `stats_breakdown`, `stats_metrics` |
|
|
226
|
+
| `usage` | yes | 1 | `usage_get` |
|
|
227
|
+
| `simulator` | yes | 2 | `simulator_get`, `send_test_email` |
|
|
228
|
+
| `inbound` | | 16 | inbound domains, routes and forward destinations |
|
|
229
|
+
| `actions` | | 5 | click actions |
|
|
230
|
+
| `template_modules` | | 5 | reusable template modules |
|
|
231
|
+
| `template_assets` | | 3 | images hosted for templates |
|
|
232
|
+
| `template_timers` | | 1 | countdown timer images |
|
|
233
|
+
| `api_keys` | | 4 | create, update and revoke API keys |
|
|
234
|
+
| `smtp_credentials` | | 3 | SMTP relay credentials |
|
|
235
|
+
| `dedicated_ips` | | 1 | dedicated sending IPs |
|
|
236
|
+
|
|
237
|
+
`zapsmtp-mcp --list-tools --toolsets all` prints every tool. Tool names follow the
|
|
238
|
+
[Node.js SDK](https://www.npmjs.com/package/zapsmtp): `zap.templates.versions.get` is
|
|
239
|
+
`templates_versions_get`.
|
|
240
|
+
|
|
241
|
+
## What the tools do
|
|
242
|
+
|
|
243
|
+
- **Arguments** are the API's parameters by their API names (`reply_to`, `scheduled_at`), path
|
|
244
|
+
parameters included (`templates_versions_get` takes `id` and `vid`). Unknown or missing arguments are
|
|
245
|
+
refused before anything is sent.
|
|
246
|
+
- **Results** are the API's JSON. A list returns one page: `{data, has_more, next_cursor}`; pass
|
|
247
|
+
`next_cursor` back as `cursor` for the next page with the same filters. An operation without a body
|
|
248
|
+
returns `{"ok": true}`.
|
|
249
|
+
- **Errors** are tool errors (`isError`) with `{"error": {status, code, type, message, request_id}}`,
|
|
250
|
+
so the model can correct itself; quote the `request_id` to support.
|
|
251
|
+
- **Sends** (`emails_send`, `emails_send_batch`, `emails_receiving_reply`) take an `idempotency_key`; the
|
|
252
|
+
server makes one when it is omitted, so the SDK's automatic retries never send twice.
|
|
253
|
+
- **`send_test_email`** sends to the simulator address of a scenario (`delivered`, `bounced`, `full`,
|
|
254
|
+
`blocked`, `delayed`, `complained`, `suppressed`, or any SMTP reply as `bounce+<code>…`) and returns
|
|
255
|
+
the email id with the event to expect.
|
|
256
|
+
- **`verify_webhook_signature`** checks a webhook request's `Zap-Signature` against its raw body and
|
|
257
|
+
the endpoint's secret, locally, and returns its events (several for a batch webhook).
|
|
258
|
+
|
|
259
|
+
Annotations: tools for `GET` requests, renders and spam checks are `readOnlyHint`. Deletes, cancelling a
|
|
260
|
+
scheduled email, rotating a webhook secret, removing suppressions and restoring a template version are
|
|
261
|
+
`destructiveHint`. Sends, test webhooks and replays are `openWorldHint`. Updates, deletes and
|
|
262
|
+
verifications are `idempotentHint`.
|
|
263
|
+
|
|
264
|
+
## Resources
|
|
265
|
+
|
|
266
|
+
When the package was built with the docs site, `resources/list` offers
|
|
267
|
+
`https://zapsmtp.com/llms.txt` (an index of the docs) and every guide as Markdown, for example
|
|
268
|
+
`https://zapsmtp.com/docs/sending.md`. They are read from the package; nothing is fetched.
|
|
269
|
+
|
|
270
|
+
## Safety
|
|
271
|
+
|
|
272
|
+
- **The key stays out of the conversation.** It is read from the environment or a flag and sent only to
|
|
273
|
+
the API. Tool results and errors are scrubbed of it, and the server writes nothing about it to its
|
|
274
|
+
logs. Prefer the environment (or VS Code's `promptString` input) over `--key`, which shows in process
|
|
275
|
+
lists.
|
|
276
|
+
- **Scope the key.** Give the agent a `zap_test_…` key while you try things, and a key restricted to
|
|
277
|
+
sending, one domain or one stream (`api_keys_create`) for production use.
|
|
278
|
+
- **Limit what the agent can do**: `--read-only`, `--toolsets`, and
|
|
279
|
+
`--allowed-recipient-domains acme.com,example.org`, which refuses sends to any other domain (and its
|
|
280
|
+
subdomains) before any request is made. Under the allowlist, `emails_receiving_reply` must name its
|
|
281
|
+
recipients in `to` and cannot use `reply_all`, since the original sender's domain is unknown until
|
|
282
|
+
the API answers. `send_test_email` always sends to the simulator.
|
|
283
|
+
- **Review before approving**: destructive tools are annotated, so clients that ask before running a tool
|
|
284
|
+
(Claude Code, Claude Desktop, VS Code, Cursor) show which calls change or delete things.
|
|
285
|
+
- **HTTP**: loopback by default with `Host`/`Origin` checks; use HTTPS beyond your machine.
|
|
286
|
+
|
|
287
|
+
## Embedding
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
import { API, buildTools, createServer, makeClient } from 'zapsmtp-mcp';
|
|
291
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
292
|
+
|
|
293
|
+
const tools = buildTools(API, { toolsets: ['emails', 'simulator'], sender: 'hello@acme.com' });
|
|
294
|
+
const server = createServer({ client: makeClient({ apiKey: process.env.ZAP_API_KEY! }), tools });
|
|
295
|
+
await server.connect(new StdioServerTransport());
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Development
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
cd sdks/node && npm ci && npm run build # the SDK this package uses
|
|
302
|
+
cd ../mcp && npm ci
|
|
303
|
+
npm run generate # src/generated/ by sdks/codegen (emit/mcp.mjs); the build fails when it is stale
|
|
304
|
+
npm test # every tool against the conformance server, HTTP auth, safety options
|
|
305
|
+
npm run coverage # 100% of the hand-written code
|
|
306
|
+
npm run build # the codegen check, dist/, and docs/ from landing/zapsmtp-site/dist when it is built
|
|
307
|
+
../live/run.sh mcp # against the dev API
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`src/generated/` is generated by `sdks/codegen` (`emit/mcp.mjs`; the code calling the SDK comes from
|
|
311
|
+
`codegen/templates/tools-model.ts`, shared with the CLI); `src/catalog.ts` holds the hand-written choices (toolsets,
|
|
312
|
+
annotations, descriptions).
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Entry point of the zapsmtp-mcp command.
|
|
3
|
+
import { main } from './main.js';
|
|
4
|
+
main(process.argv.slice(2), process.env, process).then((r) => {
|
|
5
|
+
if (typeof r === 'number') {
|
|
6
|
+
process.exitCode = r;
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const stop = () => { void r.close().then(() => process.exit(0)); };
|
|
10
|
+
process.once('SIGINT', stop);
|
|
11
|
+
process.once('SIGTERM', stop);
|
|
12
|
+
}, (err) => {
|
|
13
|
+
process.stderr.write(`zapsmtp-mcp: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,0CAA0C;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;IAC3D,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,EAAE,CAAC,GAAY,EAAE,EAAE;IAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3F,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Operation } from './generated/model.js';
|
|
2
|
+
export interface Toolset {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
default: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Every toolset, in the order they are listed. A resource without one here gets its own (snake_case name). */
|
|
8
|
+
export declare const TOOLSETS: Toolset[];
|
|
9
|
+
export declare const DEFAULT_TOOLSETS: string[];
|
|
10
|
+
/** The SDK method path of an operation, e.g. "emails.receiving.list". */
|
|
11
|
+
export declare const sdkName: (op: Operation) => string;
|
|
12
|
+
/** emails.receiving.attachments.list -> emails_receiving_attachments_list */
|
|
13
|
+
export declare const toolName: (op: Operation) => string;
|
|
14
|
+
/** Received emails get a toolset of their own; every other operation belongs to its top-level resource. */
|
|
15
|
+
export declare const toolsetOf: (op: Operation) => string;
|
|
16
|
+
export interface Annotations {
|
|
17
|
+
title: string;
|
|
18
|
+
readOnlyHint: boolean;
|
|
19
|
+
destructiveHint?: boolean;
|
|
20
|
+
idempotentHint?: boolean;
|
|
21
|
+
openWorldHint: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function annotations(op: Operation): Annotations;
|
|
24
|
+
/** Operations whose recipients --allowed-recipient-domains checks, and the parameters that hold them. */
|
|
25
|
+
export declare const RECIPIENT_PARAMS: Record<string, string[]>;
|
|
26
|
+
/** Operations that take the default sender and Reply-To. */
|
|
27
|
+
export declare const SENDS: Set<string>;
|
|
28
|
+
/** The operation's documentation, cut at a sentence end when it is long. */
|
|
29
|
+
export declare function describe(op: Operation): string;
|
|
30
|
+
export declare function trim(s: string, max: number): string;
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// The hand-written layer over the generated operations: tool names, toolsets,
|
|
2
|
+
// annotations and descriptions. Everything here is a judgement call the API
|
|
3
|
+
// model cannot make; the parameters themselves always come from the model.
|
|
4
|
+
import { snake } from './generated/model.js';
|
|
5
|
+
/** Every toolset, in the order they are listed. A resource without one here gets its own (snake_case name). */
|
|
6
|
+
export const TOOLSETS = [
|
|
7
|
+
{ name: 'emails', description: 'Send (one or a batch), list, get, reschedule, cancel, spam-check and share sent emails; their attachments', default: true },
|
|
8
|
+
{ name: 'receiving', description: 'Received (inbound) emails: list, get, reply, report spam, redeliver, attachments, delete', default: true },
|
|
9
|
+
{ name: 'threads', description: 'Conversations of sent and received emails', default: true },
|
|
10
|
+
{ name: 'templates', description: 'Templates: create, update, render, publish, duplicate, versions', default: true },
|
|
11
|
+
{ name: 'variables', description: 'Template variables and global variables', default: true },
|
|
12
|
+
{ name: 'domains', description: 'Sending domains: DNS records, verification, tracking, DMARC reports, reputation, brand (BIMI)', default: true },
|
|
13
|
+
{ name: 'webhooks', description: 'Webhook endpoints, test deliveries, delivery history, event replay, secret rotation, signature verification', default: true },
|
|
14
|
+
{ name: 'suppressions', description: 'The suppression list: add, remove, look up', default: true },
|
|
15
|
+
{ name: 'logs', description: 'API request logs', default: true },
|
|
16
|
+
{ name: 'stats', description: 'Sending statistics, time series, breakdowns and metrics', default: true },
|
|
17
|
+
{ name: 'usage', description: 'This month\'s usage and plan', default: true },
|
|
18
|
+
{ name: 'simulator', description: 'Simulator addresses, and send_test_email to try any delivery outcome safely', default: true },
|
|
19
|
+
{ name: 'inbound', description: 'Inbound domains, routes and forward destinations', default: false },
|
|
20
|
+
{ name: 'actions', description: 'Click actions (named buttons and links)', default: false },
|
|
21
|
+
{ name: 'template_modules', description: 'Reusable template modules', default: false },
|
|
22
|
+
{ name: 'template_assets', description: 'Images hosted for templates', default: false },
|
|
23
|
+
{ name: 'template_timers', description: 'Countdown timer images', default: false },
|
|
24
|
+
{ name: 'api_keys', description: 'API keys: create, update, revoke', default: false },
|
|
25
|
+
{ name: 'smtp_credentials', description: 'SMTP relay credentials', default: false },
|
|
26
|
+
{ name: 'dedicated_ips', description: 'Dedicated sending IPs and their warm-up', default: false },
|
|
27
|
+
];
|
|
28
|
+
export const DEFAULT_TOOLSETS = TOOLSETS.filter((t) => t.default).map((t) => t.name);
|
|
29
|
+
/** The SDK method path of an operation, e.g. "emails.receiving.list". */
|
|
30
|
+
export const sdkName = (op) => [...op.resource, op.method].join('.');
|
|
31
|
+
/** emails.receiving.attachments.list -> emails_receiving_attachments_list */
|
|
32
|
+
export const toolName = (op) => [...op.resource, op.method].map(snake).join('_');
|
|
33
|
+
/** Received emails get a toolset of their own; every other operation belongs to its top-level resource. */
|
|
34
|
+
export const toolsetOf = (op) => op.resource[0] === 'emails' && op.resource[1] === 'receiving' ? 'receiving' : snake(op.resource[0]);
|
|
35
|
+
/** POST operations that change nothing: they compute an answer. */
|
|
36
|
+
const READ_ONLY_POSTS = new Set(['templates.render', 'templates.renderSource', 'emails.spamCheck', 'emails.spamCheckSent']);
|
|
37
|
+
/** Operations that destroy or revoke something besides DELETE requests. */
|
|
38
|
+
const DESTRUCTIVE = new Set(['emails.cancel', 'webhooks.rotateSecret', 'suppressions.deleteBatch', 'templates.versions.restore']);
|
|
39
|
+
/** POST operations that end in the same state when repeated. */
|
|
40
|
+
const IDEMPOTENT_POSTS = new Set([
|
|
41
|
+
'emails.cancel', 'domains.verify', 'inbound.domains.verify', 'domains.checkReputation', 'templates.publish',
|
|
42
|
+
'emails.receiving.reportSpam', 'suppressions.createBatch', 'suppressions.deleteBatch', 'templates.versions.restore',
|
|
43
|
+
]);
|
|
44
|
+
/** Operations that send email or call a URL outside ZapSMTP. */
|
|
45
|
+
const OPEN_WORLD = new Set([
|
|
46
|
+
'emails.send', 'emails.sendBatch', 'emails.receiving.reply', 'inbound.forwardDestinations.create',
|
|
47
|
+
'inbound.forwardDestinations.resendConfirmation', 'webhooks.test', 'webhooks.events.replay', 'emails.receiving.redeliver',
|
|
48
|
+
]);
|
|
49
|
+
export function annotations(op) {
|
|
50
|
+
const name = sdkName(op);
|
|
51
|
+
const readOnly = op.httpMethod === 'GET' || READ_ONLY_POSTS.has(name);
|
|
52
|
+
const a = { title: op.title, readOnlyHint: readOnly, openWorldHint: OPEN_WORLD.has(name) };
|
|
53
|
+
if (!readOnly) {
|
|
54
|
+
a.destructiveHint = op.httpMethod === 'DELETE' || DESTRUCTIVE.has(name);
|
|
55
|
+
a.idempotentHint = op.httpMethod === 'PUT' || op.httpMethod === 'DELETE' || op.httpMethod === 'PATCH' || IDEMPOTENT_POSTS.has(name);
|
|
56
|
+
}
|
|
57
|
+
return a;
|
|
58
|
+
}
|
|
59
|
+
/** Operations whose recipients --allowed-recipient-domains checks, and the parameters that hold them. */
|
|
60
|
+
export const RECIPIENT_PARAMS = {
|
|
61
|
+
'emails.send': ['to', 'cc', 'bcc'],
|
|
62
|
+
'emails.sendBatch': ['to', 'cc', 'bcc'],
|
|
63
|
+
'emails.receiving.reply': ['to', 'cc', 'bcc'],
|
|
64
|
+
'inbound.forwardDestinations.create': ['email'],
|
|
65
|
+
};
|
|
66
|
+
/** Operations that take the default sender and Reply-To. */
|
|
67
|
+
export const SENDS = new Set(['emails.send', 'emails.sendBatch']);
|
|
68
|
+
const MAX_DESCRIPTION = 900;
|
|
69
|
+
/** The operation's documentation, cut at a sentence end when it is long. */
|
|
70
|
+
export function describe(op) {
|
|
71
|
+
return trim(op.doc, MAX_DESCRIPTION);
|
|
72
|
+
}
|
|
73
|
+
export function trim(s, max) {
|
|
74
|
+
if (s.length <= max)
|
|
75
|
+
return s;
|
|
76
|
+
const cut = s.slice(0, max);
|
|
77
|
+
const end = Math.max(cut.lastIndexOf('. '), cut.lastIndexOf('.\n'));
|
|
78
|
+
return end > max / 2 ? cut.slice(0, end + 1) : cut.slice(0, cut.lastIndexOf(' ')) + ' …';
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
|
package/dist/docs.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface DocPage {
|
|
2
|
+
uri: string;
|
|
3
|
+
name: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
/** the file in the docs directory */
|
|
7
|
+
file: string;
|
|
8
|
+
}
|
|
9
|
+
/** Where the build puts the docs: <package>/docs. */
|
|
10
|
+
export declare const DOCS_DIR: string;
|
|
11
|
+
/** The bundled pages; none when the package was built without them. */
|
|
12
|
+
export declare function loadDocs(dir?: string): DocPage[];
|
|
13
|
+
export declare function readDoc(dir: string, page: DocPage): string;
|
package/dist/docs.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The ZapSMTP docs as MCP resources: llms.txt and the guides in Markdown,
|
|
2
|
+
// bundled into the package at build time (scripts/bundle-docs.mjs). Nothing
|
|
3
|
+
// is fetched at runtime.
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
/** Where the build puts the docs: <package>/docs. */
|
|
8
|
+
export const DOCS_DIR = fileURLToPath(new URL('../docs/', import.meta.url));
|
|
9
|
+
/** The bundled pages; none when the package was built without them. */
|
|
10
|
+
export function loadDocs(dir = DOCS_DIR) {
|
|
11
|
+
try {
|
|
12
|
+
const pages = JSON.parse(readFileSync(join(dir, 'index.json'), 'utf8'));
|
|
13
|
+
return Array.isArray(pages) ? pages : [];
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function readDoc(dir, page) {
|
|
20
|
+
return readFileSync(join(dir, page.file), 'utf8');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=docs.js.map
|
package/dist/docs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../src/docs.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,yBAAyB;AACzB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAWzC,qDAAqD;AACrD,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE5E,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,MAAc,QAAQ;IAC7C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAc,CAAC;QACrF,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,IAAa;IAChD,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
|