@mailkite/mcp 0.2.0 → 0.4.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 +15 -0
- package/package.json +3 -3
- package/spec/api.json +277 -33
- package/spec/cases.json +657 -74
- package/spec/check-docs.mjs +182 -0
- package/spec/schemas/agent-request.json +17 -0
- package/spec/schemas/agent-response.json +13 -0
- package/spec/schemas/create-route-request.json +9 -4
- package/spec/schemas/create-template-request.json +16 -0
- package/spec/schemas/decrypt-request.json +19 -0
- package/spec/schemas/encrypt-request.json +19 -0
- package/spec/schemas/route-message-request.json +17 -0
- package/spec/schemas/route-response.json +12 -0
- package/spec/schemas/send-request.json +11 -2
package/README.md
CHANGED
|
@@ -10,6 +10,19 @@ from the shared SDK contract in [`../spec`](../spec); transport, auth, and error
|
|
|
10
10
|
handling come from the [MailKite Node SDK](../node). Nothing about the API is
|
|
11
11
|
duplicated here — update the spec and the MCP follows.
|
|
12
12
|
|
|
13
|
+
> ### Hosted vs local — which should I use?
|
|
14
|
+
>
|
|
15
|
+
> Most users should connect to the **hosted remote MCP** instead of running this
|
|
16
|
+
> package: `https://mcp.mailkite.dev/mcp` (Streamable HTTP, one-click **OAuth** — no
|
|
17
|
+
> key to copy, no local process). In Claude Code that's the **plugin**
|
|
18
|
+
> (`/plugin marketplace add mailkite/claude-code` → `/plugin install mailkite@mailkite`)
|
|
19
|
+
> or `claude mcp add --transport http mailkite https://mcp.mailkite.dev/mcp`. See
|
|
20
|
+
> <https://mailkite.dev/docs/ai-agents>.
|
|
21
|
+
>
|
|
22
|
+
> Run **this local server** when you want a **static key** (no browser OAuth), **offline /
|
|
23
|
+
> CI** use, a stdio-only client, a custom `MAILKITE_BASE_URL`, or `verifyWebhook` to run
|
|
24
|
+
> fully locally. Both expose the exact same tools (same `../spec`).
|
|
25
|
+
|
|
13
26
|
## Install / configure
|
|
14
27
|
|
|
15
28
|
Point your MCP client at the server and give it your MailKite credential. The
|
|
@@ -40,6 +53,8 @@ One tool per MailKite API operation (generated from [`../spec/api.json`](../spec
|
|
|
40
53
|
| Tool | Operation |
|
|
41
54
|
| --- | --- |
|
|
42
55
|
| `mailkite_send` | Send a message over a verified domain |
|
|
56
|
+
| `mailkite_agent` | Send a message to an inbox agent and get its reply |
|
|
57
|
+
| `mailkite_route` | Route a message to a registered route and run its action |
|
|
43
58
|
| `mailkite_list_domains` | List your domains |
|
|
44
59
|
| `mailkite_create_domain` | Add a domain (returns DNS records) |
|
|
45
60
|
| `mailkite_get_domain` | Get one domain with DNS + webhook |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailkite/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Model Context Protocol server for MailKite — exposes the MailKite API to LLM agents as tools. A thin layer over the MailKite Node SDK and the shared sdks/spec contract.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"homepage": "https://mailkite.dev/docs/libraries",
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
37
|
-
"url": "git+https://github.com/
|
|
37
|
+
"url": "git+https://github.com/mailkite/mailkite.git",
|
|
38
38
|
"directory": "sdks/mcp"
|
|
39
39
|
},
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
43
43
|
"ajv": "^8.17.1",
|
|
44
|
-
"mailkite": "^0.
|
|
44
|
+
"mailkite": "^0.4.0"
|
|
45
45
|
}
|
|
46
46
|
}
|
package/spec/api.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailkite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Canonical interface contract for every MailKite SDK. One low-level request() plus one function per endpoint. All languages expose the same shape; only naming adapts to each language's convention (e.g. Go exports PascalCase).",
|
|
5
5
|
"baseUrl": "https://api.mailkite.dev",
|
|
6
6
|
"auth": {
|
|
@@ -11,126 +11,370 @@
|
|
|
11
11
|
"methods": [
|
|
12
12
|
{
|
|
13
13
|
"name": "send",
|
|
14
|
-
"summary": "Send a message over a verified domain.",
|
|
15
|
-
"http": {
|
|
16
|
-
|
|
14
|
+
"summary": "Send a message over a verified domain. Pass `templateId` (+ optional `templateData`) to send from a saved or base template.",
|
|
15
|
+
"http": {
|
|
16
|
+
"method": "POST",
|
|
17
|
+
"path": "/v1/send"
|
|
18
|
+
},
|
|
19
|
+
"args": [
|
|
20
|
+
{
|
|
21
|
+
"name": "message",
|
|
22
|
+
"in": "body",
|
|
23
|
+
"schema": "send-request"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
17
26
|
"returns": "send-response"
|
|
18
27
|
},
|
|
28
|
+
{
|
|
29
|
+
"name": "listTemplates",
|
|
30
|
+
"summary": "List your saved email templates (light metadata only — no body). Use getTemplate for the full template.",
|
|
31
|
+
"http": {
|
|
32
|
+
"method": "GET",
|
|
33
|
+
"path": "/api/templates"
|
|
34
|
+
},
|
|
35
|
+
"args": [],
|
|
36
|
+
"returns": "any"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "listBaseTemplates",
|
|
40
|
+
"summary": "List the premade base templates (light metadata). Clone one with createTemplate({ baseId }) or send from it directly via send({ templateId }).",
|
|
41
|
+
"http": {
|
|
42
|
+
"method": "GET",
|
|
43
|
+
"path": "/api/templates/base"
|
|
44
|
+
},
|
|
45
|
+
"args": [],
|
|
46
|
+
"returns": "any"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "getTemplate",
|
|
50
|
+
"summary": "Get one template (full: subject, html, text, theme). Works for your templates (tpl_…) and base templates (base_…).",
|
|
51
|
+
"http": {
|
|
52
|
+
"method": "GET",
|
|
53
|
+
"path": "/api/templates/{id}"
|
|
54
|
+
},
|
|
55
|
+
"args": [
|
|
56
|
+
{
|
|
57
|
+
"name": "id",
|
|
58
|
+
"in": "path"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"returns": "any"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "createTemplate",
|
|
65
|
+
"summary": "Create a template. Pass `baseId` to clone a base template into your own, or provide name/subject/html/text/theme directly.",
|
|
66
|
+
"http": {
|
|
67
|
+
"method": "POST",
|
|
68
|
+
"path": "/api/templates"
|
|
69
|
+
},
|
|
70
|
+
"args": [
|
|
71
|
+
{
|
|
72
|
+
"name": "body",
|
|
73
|
+
"in": "body",
|
|
74
|
+
"schema": "create-template-request"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"returns": "any"
|
|
78
|
+
},
|
|
19
79
|
{
|
|
20
80
|
"name": "listDomains",
|
|
21
81
|
"summary": "List your domains, each with its webhook URL.",
|
|
22
|
-
"http": {
|
|
82
|
+
"http": {
|
|
83
|
+
"method": "GET",
|
|
84
|
+
"path": "/api/domains"
|
|
85
|
+
},
|
|
23
86
|
"args": [],
|
|
24
87
|
"returns": "any"
|
|
25
88
|
},
|
|
26
89
|
{
|
|
27
90
|
"name": "createDomain",
|
|
28
91
|
"summary": "Add a domain. Returns the domain + DNS records.",
|
|
29
|
-
"http": {
|
|
30
|
-
|
|
92
|
+
"http": {
|
|
93
|
+
"method": "POST",
|
|
94
|
+
"path": "/api/domains"
|
|
95
|
+
},
|
|
96
|
+
"args": [
|
|
97
|
+
{
|
|
98
|
+
"name": "body",
|
|
99
|
+
"in": "body",
|
|
100
|
+
"schema": "create-domain-request"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
31
103
|
"returns": "any"
|
|
32
104
|
},
|
|
33
105
|
{
|
|
34
106
|
"name": "getDomain",
|
|
35
107
|
"summary": "Get one domain with DNS records + webhook.",
|
|
36
|
-
"http": {
|
|
37
|
-
|
|
108
|
+
"http": {
|
|
109
|
+
"method": "GET",
|
|
110
|
+
"path": "/api/domains/{id}"
|
|
111
|
+
},
|
|
112
|
+
"args": [
|
|
113
|
+
{
|
|
114
|
+
"name": "id",
|
|
115
|
+
"in": "path"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
38
118
|
"returns": "any"
|
|
39
119
|
},
|
|
40
120
|
{
|
|
41
121
|
"name": "deleteDomain",
|
|
42
122
|
"summary": "Remove a domain.",
|
|
43
|
-
"http": {
|
|
44
|
-
|
|
123
|
+
"http": {
|
|
124
|
+
"method": "DELETE",
|
|
125
|
+
"path": "/api/domains/{id}"
|
|
126
|
+
},
|
|
127
|
+
"args": [
|
|
128
|
+
{
|
|
129
|
+
"name": "id",
|
|
130
|
+
"in": "path"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
45
133
|
"returns": "any"
|
|
46
134
|
},
|
|
47
135
|
{
|
|
48
136
|
"name": "verifyDomain",
|
|
49
137
|
"summary": "Check DNS and update status.",
|
|
50
|
-
"http": {
|
|
51
|
-
|
|
138
|
+
"http": {
|
|
139
|
+
"method": "POST",
|
|
140
|
+
"path": "/api/domains/{id}/verify"
|
|
141
|
+
},
|
|
142
|
+
"args": [
|
|
143
|
+
{
|
|
144
|
+
"name": "id",
|
|
145
|
+
"in": "path"
|
|
146
|
+
}
|
|
147
|
+
],
|
|
52
148
|
"returns": "any"
|
|
53
149
|
},
|
|
54
150
|
{
|
|
55
151
|
"name": "setWebhook",
|
|
56
152
|
"summary": "Set or replace the domain's catch-all webhook.",
|
|
57
|
-
"http": {
|
|
153
|
+
"http": {
|
|
154
|
+
"method": "PUT",
|
|
155
|
+
"path": "/api/domains/{id}/webhook"
|
|
156
|
+
},
|
|
58
157
|
"args": [
|
|
59
|
-
{
|
|
60
|
-
|
|
158
|
+
{
|
|
159
|
+
"name": "id",
|
|
160
|
+
"in": "path"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"name": "body",
|
|
164
|
+
"in": "body",
|
|
165
|
+
"schema": "set-webhook-request"
|
|
166
|
+
}
|
|
61
167
|
],
|
|
62
168
|
"returns": "any"
|
|
63
169
|
},
|
|
64
170
|
{
|
|
65
171
|
"name": "deleteWebhook",
|
|
66
172
|
"summary": "Remove the domain's webhook.",
|
|
67
|
-
"http": {
|
|
68
|
-
|
|
173
|
+
"http": {
|
|
174
|
+
"method": "DELETE",
|
|
175
|
+
"path": "/api/domains/{id}/webhook"
|
|
176
|
+
},
|
|
177
|
+
"args": [
|
|
178
|
+
{
|
|
179
|
+
"name": "id",
|
|
180
|
+
"in": "path"
|
|
181
|
+
}
|
|
182
|
+
],
|
|
69
183
|
"returns": "any"
|
|
70
184
|
},
|
|
71
185
|
{
|
|
72
186
|
"name": "testWebhook",
|
|
73
187
|
"summary": "Send a signed test event to the domain's webhook.",
|
|
74
|
-
"http": {
|
|
75
|
-
|
|
188
|
+
"http": {
|
|
189
|
+
"method": "POST",
|
|
190
|
+
"path": "/api/domains/{id}/webhook/test"
|
|
191
|
+
},
|
|
192
|
+
"args": [
|
|
193
|
+
{
|
|
194
|
+
"name": "id",
|
|
195
|
+
"in": "path"
|
|
196
|
+
}
|
|
197
|
+
],
|
|
76
198
|
"returns": "any"
|
|
77
199
|
},
|
|
78
200
|
{
|
|
79
201
|
"name": "checkDomainAvailability",
|
|
80
202
|
"summary": "Check whether a domain is available to register, and at what price. Read-only — no charge.",
|
|
81
|
-
"http": {
|
|
82
|
-
|
|
203
|
+
"http": {
|
|
204
|
+
"method": "GET",
|
|
205
|
+
"path": "/api/domains/register/check"
|
|
206
|
+
},
|
|
207
|
+
"args": [
|
|
208
|
+
{
|
|
209
|
+
"name": "domain",
|
|
210
|
+
"in": "query"
|
|
211
|
+
}
|
|
212
|
+
],
|
|
83
213
|
"returns": "any"
|
|
84
214
|
},
|
|
85
215
|
{
|
|
86
216
|
"name": "registerDomain",
|
|
87
217
|
"summary": "Register (buy) a domain on the customer's behalf; provisions mail DNS and adds it to the account in one call. Charges the registrar.",
|
|
88
|
-
"http": {
|
|
89
|
-
|
|
218
|
+
"http": {
|
|
219
|
+
"method": "POST",
|
|
220
|
+
"path": "/api/domains/register"
|
|
221
|
+
},
|
|
222
|
+
"args": [
|
|
223
|
+
{
|
|
224
|
+
"name": "body",
|
|
225
|
+
"in": "body",
|
|
226
|
+
"schema": "register-domain-request"
|
|
227
|
+
}
|
|
228
|
+
],
|
|
90
229
|
"returns": "any",
|
|
91
230
|
"agentConfirm": true
|
|
92
231
|
},
|
|
93
232
|
{
|
|
94
233
|
"name": "listRoutes",
|
|
95
234
|
"summary": "List inbound routing rules.",
|
|
96
|
-
"http": {
|
|
235
|
+
"http": {
|
|
236
|
+
"method": "GET",
|
|
237
|
+
"path": "/api/routes"
|
|
238
|
+
},
|
|
97
239
|
"args": [],
|
|
98
240
|
"returns": "any"
|
|
99
241
|
},
|
|
100
242
|
{
|
|
101
243
|
"name": "createRoute",
|
|
102
244
|
"summary": "Create a route (match, action, destination).",
|
|
103
|
-
"http": {
|
|
104
|
-
|
|
245
|
+
"http": {
|
|
246
|
+
"method": "POST",
|
|
247
|
+
"path": "/api/routes"
|
|
248
|
+
},
|
|
249
|
+
"args": [
|
|
250
|
+
{
|
|
251
|
+
"name": "body",
|
|
252
|
+
"in": "body",
|
|
253
|
+
"schema": "create-route-request"
|
|
254
|
+
}
|
|
255
|
+
],
|
|
105
256
|
"returns": "any"
|
|
106
257
|
},
|
|
258
|
+
{
|
|
259
|
+
"name": "agent",
|
|
260
|
+
"summary": "Send a message to one of your inbox agents and get its reply. Defaults to the account's default agent; pass `routeId` or `address` to target a specific agent, or `model` to override the model. This is separate from inbound routing — it does not match or override routes.",
|
|
261
|
+
"http": {
|
|
262
|
+
"method": "POST",
|
|
263
|
+
"path": "/v1/agent"
|
|
264
|
+
},
|
|
265
|
+
"args": [
|
|
266
|
+
{
|
|
267
|
+
"name": "message",
|
|
268
|
+
"in": "body",
|
|
269
|
+
"schema": "agent-request"
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
"returns": "agent-response"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"name": "route",
|
|
276
|
+
"summary": "Route a message to one of your registered routes (by `routeId` or `address`), running that route's action — agent, webhook, or forward. The route must already exist on your account; arbitrary destinations are not allowed.",
|
|
277
|
+
"http": {
|
|
278
|
+
"method": "POST",
|
|
279
|
+
"path": "/v1/route"
|
|
280
|
+
},
|
|
281
|
+
"args": [
|
|
282
|
+
{
|
|
283
|
+
"name": "message",
|
|
284
|
+
"in": "body",
|
|
285
|
+
"schema": "route-message-request"
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
"returns": "route-response"
|
|
289
|
+
},
|
|
107
290
|
{
|
|
108
291
|
"name": "listMessages",
|
|
109
292
|
"summary": "List stored messages.",
|
|
110
|
-
"http": {
|
|
293
|
+
"http": {
|
|
294
|
+
"method": "GET",
|
|
295
|
+
"path": "/api/messages"
|
|
296
|
+
},
|
|
111
297
|
"args": [],
|
|
112
298
|
"returns": "any"
|
|
113
299
|
},
|
|
114
300
|
{
|
|
115
301
|
"name": "getMessage",
|
|
116
302
|
"summary": "Get a message with deliveries + attachments.",
|
|
117
|
-
"http": {
|
|
118
|
-
|
|
303
|
+
"http": {
|
|
304
|
+
"method": "GET",
|
|
305
|
+
"path": "/api/messages/{id}"
|
|
306
|
+
},
|
|
307
|
+
"args": [
|
|
308
|
+
{
|
|
309
|
+
"name": "id",
|
|
310
|
+
"in": "path"
|
|
311
|
+
}
|
|
312
|
+
],
|
|
119
313
|
"returns": "any"
|
|
120
314
|
},
|
|
121
315
|
{
|
|
122
316
|
"name": "retryDelivery",
|
|
123
317
|
"summary": "Re-deliver a stored message to its webhook.",
|
|
124
|
-
"http": {
|
|
125
|
-
|
|
318
|
+
"http": {
|
|
319
|
+
"method": "POST",
|
|
320
|
+
"path": "/api/deliveries/{id}/retry"
|
|
321
|
+
},
|
|
322
|
+
"args": [
|
|
323
|
+
{
|
|
324
|
+
"name": "id",
|
|
325
|
+
"in": "path"
|
|
326
|
+
}
|
|
327
|
+
],
|
|
126
328
|
"returns": "any"
|
|
127
329
|
},
|
|
128
330
|
{
|
|
129
331
|
"name": "verifyWebhook",
|
|
130
332
|
"summary": "Verify the `x-mailkite-signature` header on an inbound webhook delivery. Runs entirely locally (HMAC-SHA256 over `${t}.${payload}`) — no network call. Returns true only when the signature matches and the event is within the freshness window.",
|
|
131
333
|
"local": true,
|
|
132
|
-
"args": [
|
|
334
|
+
"args": [
|
|
335
|
+
{
|
|
336
|
+
"name": "body",
|
|
337
|
+
"in": "body",
|
|
338
|
+
"schema": "verify-webhook-request"
|
|
339
|
+
}
|
|
340
|
+
],
|
|
133
341
|
"returns": "boolean"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"name": "replyOk",
|
|
345
|
+
"summary": "The acknowledgement body a webhook consumer returns to confirm it processed the event — the string `{\"status\":\"ok\"}`. Send it with a 2xx when the route is in `ack` mode (or always — it's harmless in `lenient` mode). Local, no network call.",
|
|
346
|
+
"local": true,
|
|
347
|
+
"args": [],
|
|
348
|
+
"returns": "string",
|
|
349
|
+
"sdkOnly": true
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"name": "encrypt",
|
|
353
|
+
"summary": "Encrypt a UTF-8 string to a domain's RSA public key (SPKI/PEM), returning the at-rest envelope JSON (`{v,keyAlg,fp,enc,iv,wrappedKey,ciphertext}`). Hybrid scheme: a fresh AES-256-GCM content key wrapped with RSA-OAEP(SHA-256) — byte-compatible with MailKite's own at-rest encryption. Local, no network call.",
|
|
354
|
+
"local": true,
|
|
355
|
+
"args": [
|
|
356
|
+
{
|
|
357
|
+
"name": "body",
|
|
358
|
+
"in": "body",
|
|
359
|
+
"schema": "encrypt-request"
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"returns": "string",
|
|
363
|
+
"sdkOnly": true
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"name": "decrypt",
|
|
367
|
+
"summary": "Decrypt a MailKite at-rest envelope JSON with your RSA private key (PKCS8/PEM), returning the original UTF-8 string. Reverses `encrypt` / MailKite's at-rest encryption (RSA-OAEP(SHA-256) unwrap → AES-256-GCM open). Local, no network call.",
|
|
368
|
+
"local": true,
|
|
369
|
+
"args": [
|
|
370
|
+
{
|
|
371
|
+
"name": "body",
|
|
372
|
+
"in": "body",
|
|
373
|
+
"schema": "decrypt-request"
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
"returns": "string",
|
|
377
|
+
"sdkOnly": true
|
|
134
378
|
}
|
|
135
379
|
]
|
|
136
380
|
}
|