@mailkite/mcp 0.5.0 → 0.8.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 CHANGED
@@ -5,9 +5,14 @@
5
5
  (Claude Desktop, Claude Code, Cursor, …) as tools — send mail, manage domains,
6
6
  webhooks, routes, and inbound messages, all from a chat.
7
7
 
8
+ > **Read-only mirror.** This repo is a generated, release-time mirror of the MailKite
9
+ > monorepo (the private source of truth); the source isn't developed here. Install
10
+ > `@mailkite/mcp` from npm rather than cloning, and see the docs at
11
+ > <https://mailkite.dev/docs/libraries#mcp>.
12
+
8
13
  It's a **thin layer**. The tools, their input schemas, and validation all come
9
14
  from the shared SDK contract in [`../spec`](../spec); transport, auth, and error
10
- handling come from the [MailKite Node SDK](../node). Nothing about the API is
15
+ handling come from the [MailKite Node SDK](https://github.com/mailkite/mailkite-node). Nothing about the API is
11
16
  duplicated here — update the spec and the MCP follows.
12
17
 
13
18
  > ### Hosted vs local — which should I use?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailkite/mcp",
3
- "version": "0.5.0",
3
+ "version": "0.8.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,12 @@
34
34
  "homepage": "https://mailkite.dev/docs/libraries",
35
35
  "repository": {
36
36
  "type": "git",
37
- "url": "git+https://github.com/mailkite/mailkite.git",
38
- "directory": "sdks/mcp"
37
+ "url": "git+https://github.com/mailkite/mailkite-mcp.git"
39
38
  },
40
39
  "license": "MIT",
41
40
  "dependencies": {
42
41
  "@modelcontextprotocol/sdk": "^1.0.0",
43
42
  "ajv": "^8.17.1",
44
- "mailkite": "^0.5.0"
43
+ "mailkite": "^0.8.0"
45
44
  }
46
45
  }
package/server.mjs CHANGED
@@ -202,6 +202,25 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
202
202
  };
203
203
  }
204
204
 
205
+ // uploadAttachment is the one method whose input isn't a plain JSON body: `path` is read
206
+ // off the local disk and streamed as a raw binary upload. The generic resolveCall →
207
+ // mk.request() path only does JSON, so delegate to the SDK method, which picks the
208
+ // transport (path/bytes → binary, url/content → JSON). Validate against the same schema.
209
+ if (tool._method.name === "uploadAttachment") {
210
+ try {
211
+ const input = req.params.arguments || {};
212
+ const validate = validators["upload-attachment-request"];
213
+ if (validate && !validate(input)) {
214
+ return { isError: true, content: [{ type: "text", text: `Invalid input for upload-attachment-request: ${ajv.errorsText(validate.errors)}` }] };
215
+ }
216
+ const result = await mk.uploadAttachment(input);
217
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
218
+ } catch (err) {
219
+ const text = err instanceof MailKiteError ? `MailKite API error ${err.status}: ${err.message}` : `Error: ${err.message}`;
220
+ return { isError: true, content: [{ type: "text", text }] };
221
+ }
222
+ }
223
+
205
224
  try {
206
225
  const { method, urlPath, body } = resolveCall(tool._method, req.params.arguments);
207
226
  const result = await mk.request(method, urlPath, body);
package/spec/api.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailkite",
3
- "version": "0.5.0",
3
+ "version": "0.8.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": {
@@ -27,7 +27,7 @@
27
27
  },
28
28
  {
29
29
  "name": "uploadAttachment",
30
- "summary": "Upload a file to MailKite storage and get back a secure, time-limited URL. Reference the returned `url` as an attachment in send() (`{ filename, url }`) or link it inline in your HTML — instead of base64-inlining large files on every send. `content` is the file bytes, base64-encoded; `retentionDays` (7/30/90/365, default 7) sets how long the file and URL live.",
30
+ "summary": "Upload a file to MailKite storage and get back a secure, time-limited URL. Reference the returned `url` as an attachment in send() (`{ filename, url }`) or link it inline in your HTML — instead of base64-inlining large files on every send. Give the file ONE of four ways: a local `path` (read and streamed as raw bytes by the CLI/SDK/local MCP), a remote `url` (MailKite fetches and re-hosts it), base64 `content`, or — over raw HTTP — the file bytes as the POST body with `?filename=`. `retentionDays` (7/30/90/365, default 7) sets how long the file and URL live.",
31
31
  "http": {
32
32
  "method": "POST",
33
33
  "path": "/v1/attachments"
@@ -343,6 +343,233 @@
343
343
  ],
344
344
  "returns": "any"
345
345
  },
346
+ {
347
+ "name": "listLists",
348
+ "summary": "List your contact lists (static, curated broadcast audiences), each with its member count.",
349
+ "http": {
350
+ "method": "GET",
351
+ "path": "/api/lists"
352
+ },
353
+ "args": [],
354
+ "returns": "any"
355
+ },
356
+ {
357
+ "name": "createList",
358
+ "summary": "Create a contact list. Returns the list with its id (lst_…); add contacts with addListContacts.",
359
+ "http": {
360
+ "method": "POST",
361
+ "path": "/api/lists"
362
+ },
363
+ "args": [
364
+ {
365
+ "name": "body",
366
+ "in": "body",
367
+ "schema": "create-list-request"
368
+ }
369
+ ],
370
+ "returns": "any"
371
+ },
372
+ {
373
+ "name": "getList",
374
+ "summary": "Get one contact list with its member count.",
375
+ "http": {
376
+ "method": "GET",
377
+ "path": "/api/lists/{id}"
378
+ },
379
+ "args": [
380
+ {
381
+ "name": "id",
382
+ "in": "path"
383
+ }
384
+ ],
385
+ "returns": "any"
386
+ },
387
+ {
388
+ "name": "updateList",
389
+ "summary": "Rename a contact list.",
390
+ "http": {
391
+ "method": "PATCH",
392
+ "path": "/api/lists/{id}"
393
+ },
394
+ "args": [
395
+ {
396
+ "name": "id",
397
+ "in": "path"
398
+ },
399
+ {
400
+ "name": "body",
401
+ "in": "body",
402
+ "schema": "update-list-request"
403
+ }
404
+ ],
405
+ "returns": "any"
406
+ },
407
+ {
408
+ "name": "deleteList",
409
+ "summary": "Delete a contact list. The list is removed; the contacts themselves are kept.",
410
+ "http": {
411
+ "method": "DELETE",
412
+ "path": "/api/lists/{id}"
413
+ },
414
+ "args": [
415
+ {
416
+ "name": "id",
417
+ "in": "path"
418
+ }
419
+ ],
420
+ "returns": "any"
421
+ },
422
+ {
423
+ "name": "listListContacts",
424
+ "summary": "List the contacts that are members of a list.",
425
+ "http": {
426
+ "method": "GET",
427
+ "path": "/api/lists/{id}/contacts"
428
+ },
429
+ "args": [
430
+ {
431
+ "name": "id",
432
+ "in": "path"
433
+ }
434
+ ],
435
+ "returns": "any"
436
+ },
437
+ {
438
+ "name": "addListContacts",
439
+ "summary": "Add contacts (by id, ctr_…) to a list. Returns how many were newly added; contacts already on the list are ignored.",
440
+ "http": {
441
+ "method": "POST",
442
+ "path": "/api/lists/{id}/contacts"
443
+ },
444
+ "args": [
445
+ {
446
+ "name": "id",
447
+ "in": "path"
448
+ },
449
+ {
450
+ "name": "body",
451
+ "in": "body",
452
+ "schema": "add-list-contacts-request"
453
+ }
454
+ ],
455
+ "returns": "any"
456
+ },
457
+ {
458
+ "name": "removeListContact",
459
+ "summary": "Remove one contact from a list (the contact itself is kept).",
460
+ "http": {
461
+ "method": "DELETE",
462
+ "path": "/api/lists/{id}/contacts/{contactId}"
463
+ },
464
+ "args": [
465
+ {
466
+ "name": "id",
467
+ "in": "path"
468
+ },
469
+ {
470
+ "name": "contactId",
471
+ "in": "path"
472
+ }
473
+ ],
474
+ "returns": "any"
475
+ },
476
+ {
477
+ "name": "listBroadcasts",
478
+ "summary": "List your broadcasts (one-to-many sends) with status and send stats.",
479
+ "http": {
480
+ "method": "GET",
481
+ "path": "/api/broadcasts"
482
+ },
483
+ "args": [],
484
+ "returns": "any"
485
+ },
486
+ {
487
+ "name": "createBroadcast",
488
+ "summary": "Create a broadcast draft. `from` is required; set `audience` to { type: \"all\" } or { type: \"list\", id: \"lst_…\" }. Returns the broadcast with its id (bct_…). Send it with sendBroadcast.",
489
+ "http": {
490
+ "method": "POST",
491
+ "path": "/api/broadcasts"
492
+ },
493
+ "args": [
494
+ {
495
+ "name": "body",
496
+ "in": "body",
497
+ "schema": "create-broadcast-request"
498
+ }
499
+ ],
500
+ "returns": "any"
501
+ },
502
+ {
503
+ "name": "getBroadcast",
504
+ "summary": "Get one broadcast with its status and recipient summary.",
505
+ "http": {
506
+ "method": "GET",
507
+ "path": "/api/broadcasts/{id}"
508
+ },
509
+ "args": [
510
+ {
511
+ "name": "id",
512
+ "in": "path"
513
+ }
514
+ ],
515
+ "returns": "any"
516
+ },
517
+ {
518
+ "name": "updateBroadcast",
519
+ "summary": "Edit a draft broadcast (any of from/subject/audience/html/… ). Drafts only.",
520
+ "http": {
521
+ "method": "PATCH",
522
+ "path": "/api/broadcasts/{id}"
523
+ },
524
+ "args": [
525
+ {
526
+ "name": "id",
527
+ "in": "path"
528
+ },
529
+ {
530
+ "name": "body",
531
+ "in": "body",
532
+ "schema": "update-broadcast-request"
533
+ }
534
+ ],
535
+ "returns": "any"
536
+ },
537
+ {
538
+ "name": "deleteBroadcast",
539
+ "summary": "Delete a broadcast draft.",
540
+ "http": {
541
+ "method": "DELETE",
542
+ "path": "/api/broadcasts/{id}"
543
+ },
544
+ "args": [
545
+ {
546
+ "name": "id",
547
+ "in": "path"
548
+ }
549
+ ],
550
+ "returns": "any"
551
+ },
552
+ {
553
+ "name": "sendBroadcast",
554
+ "summary": "Send a broadcast now, or pass an ISO 8601 `scheduledAt` to schedule it. A one-click unsubscribe is always added. Returns the status and resolved audience count.",
555
+ "http": {
556
+ "method": "POST",
557
+ "path": "/api/broadcasts/{id}/send"
558
+ },
559
+ "args": [
560
+ {
561
+ "name": "id",
562
+ "in": "path"
563
+ },
564
+ {
565
+ "name": "body",
566
+ "in": "body",
567
+ "schema": "send-broadcast-request"
568
+ }
569
+ ],
570
+ "returns": "any",
571
+ "agentConfirm": true
572
+ },
346
573
  {
347
574
  "name": "verifyWebhook",
348
575
  "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.",
@@ -415,6 +642,21 @@
415
642
  ],
416
643
  "returns": "string",
417
644
  "sdkOnly": true
645
+ },
646
+ {
647
+ "name": "semanticSearch",
648
+ "summary": "Semantic search over the MailKite documentation — returns the most relevant doc sections for a natural-language query (hybrid vector + keyword search over https://mailkite.dev/docs). Public; no authentication required.",
649
+ "http": {
650
+ "method": "GET",
651
+ "path": "/v1/docs/search"
652
+ },
653
+ "args": [
654
+ {
655
+ "name": "query",
656
+ "in": "query"
657
+ }
658
+ ],
659
+ "returns": "semantic-search-response"
418
660
  }
419
661
  ]
420
662
  }
package/spec/cases.json CHANGED
@@ -72,6 +72,44 @@
72
72
  "expiresAt": "2026-07-02T00:00:00.000Z"
73
73
  }
74
74
  },
75
+ {
76
+ "name": "upload_attachment_url",
77
+ "method": "uploadAttachment",
78
+ "args": {
79
+ "url": "https://files.example.com/po.pdf",
80
+ "filename": "po.pdf",
81
+ "contentType": "application/pdf"
82
+ },
83
+ "request": {
84
+ "method": "POST",
85
+ "path": "/v1/attachments",
86
+ "bodySchema": "upload-attachment-request",
87
+ "body": {
88
+ "url": "https://files.example.com/po.pdf",
89
+ "filename": "po.pdf",
90
+ "contentType": "application/pdf"
91
+ }
92
+ },
93
+ "response": {
94
+ "status": 201,
95
+ "body": {
96
+ "id": "7d/usr_demo/0a1b2c3d/po.pdf",
97
+ "url": "https://api.mailkite.dev/up/7d/usr_demo/0a1b2c3d/po.pdf?exp=1799999999&sig=deadbeef",
98
+ "filename": "po.pdf",
99
+ "contentType": "application/pdf",
100
+ "size": 9,
101
+ "expiresAt": "2026-07-02T00:00:00.000Z"
102
+ }
103
+ },
104
+ "result": {
105
+ "id": "7d/usr_demo/0a1b2c3d/po.pdf",
106
+ "url": "https://api.mailkite.dev/up/7d/usr_demo/0a1b2c3d/po.pdf?exp=1799999999&sig=deadbeef",
107
+ "filename": "po.pdf",
108
+ "contentType": "application/pdf",
109
+ "size": 9,
110
+ "expiresAt": "2026-07-02T00:00:00.000Z"
111
+ }
112
+ },
75
113
  {
76
114
  "name": "send_full",
77
115
  "method": "send",
@@ -655,13 +693,386 @@
655
693
  "ok": true
656
694
  }
657
695
  },
696
+ {
697
+ "name": "list_lists",
698
+ "method": "listLists",
699
+ "args": {},
700
+ "request": {
701
+ "method": "GET",
702
+ "path": "/api/lists"
703
+ },
704
+ "response": {
705
+ "status": 200,
706
+ "body": [
707
+ {
708
+ "id": "lst_1",
709
+ "name": "Beta testers",
710
+ "member_count": 2
711
+ }
712
+ ]
713
+ },
714
+ "result": [
715
+ {
716
+ "id": "lst_1",
717
+ "name": "Beta testers",
718
+ "member_count": 2
719
+ }
720
+ ]
721
+ },
722
+ {
723
+ "name": "create_list",
724
+ "method": "createList",
725
+ "args": {
726
+ "name": "Beta testers"
727
+ },
728
+ "request": {
729
+ "method": "POST",
730
+ "path": "/api/lists",
731
+ "bodySchema": "create-list-request",
732
+ "body": {
733
+ "name": "Beta testers"
734
+ }
735
+ },
736
+ "response": {
737
+ "status": 201,
738
+ "body": {
739
+ "id": "lst_1",
740
+ "name": "Beta testers",
741
+ "member_count": 0
742
+ }
743
+ },
744
+ "result": {
745
+ "id": "lst_1",
746
+ "name": "Beta testers",
747
+ "member_count": 0
748
+ }
749
+ },
750
+ {
751
+ "name": "get_list",
752
+ "method": "getList",
753
+ "args": {
754
+ "id": "lst_1"
755
+ },
756
+ "request": {
757
+ "method": "GET",
758
+ "path": "/api/lists/lst_1"
759
+ },
760
+ "response": {
761
+ "status": 200,
762
+ "body": {
763
+ "id": "lst_1",
764
+ "name": "Beta testers",
765
+ "member_count": 2
766
+ }
767
+ },
768
+ "result": {
769
+ "id": "lst_1",
770
+ "name": "Beta testers",
771
+ "member_count": 2
772
+ }
773
+ },
774
+ {
775
+ "name": "update_list",
776
+ "method": "updateList",
777
+ "args": {
778
+ "id": "lst_1",
779
+ "name": "VIPs"
780
+ },
781
+ "request": {
782
+ "method": "PATCH",
783
+ "path": "/api/lists/lst_1",
784
+ "bodySchema": "update-list-request",
785
+ "body": {
786
+ "name": "VIPs"
787
+ }
788
+ },
789
+ "response": {
790
+ "status": 200,
791
+ "body": {
792
+ "id": "lst_1",
793
+ "name": "VIPs",
794
+ "member_count": 2
795
+ }
796
+ },
797
+ "result": {
798
+ "id": "lst_1",
799
+ "name": "VIPs",
800
+ "member_count": 2
801
+ }
802
+ },
803
+ {
804
+ "name": "delete_list",
805
+ "method": "deleteList",
806
+ "args": {
807
+ "id": "lst_1"
808
+ },
809
+ "request": {
810
+ "method": "DELETE",
811
+ "path": "/api/lists/lst_1"
812
+ },
813
+ "response": {
814
+ "status": 200,
815
+ "body": {
816
+ "ok": true
817
+ }
818
+ },
819
+ "result": {
820
+ "ok": true
821
+ }
822
+ },
823
+ {
824
+ "name": "list_list_contacts",
825
+ "method": "listListContacts",
826
+ "args": {
827
+ "id": "lst_1"
828
+ },
829
+ "request": {
830
+ "method": "GET",
831
+ "path": "/api/lists/lst_1/contacts"
832
+ },
833
+ "response": {
834
+ "status": 200,
835
+ "body": [
836
+ {
837
+ "id": "ctr_1",
838
+ "email": "jane@acme.com",
839
+ "name": "Jane Doe"
840
+ }
841
+ ]
842
+ },
843
+ "result": [
844
+ {
845
+ "id": "ctr_1",
846
+ "email": "jane@acme.com",
847
+ "name": "Jane Doe"
848
+ }
849
+ ]
850
+ },
851
+ {
852
+ "name": "add_list_contacts",
853
+ "method": "addListContacts",
854
+ "args": {
855
+ "id": "lst_1",
856
+ "contactIds": [
857
+ "ctr_1",
858
+ "ctr_2"
859
+ ]
860
+ },
861
+ "request": {
862
+ "method": "POST",
863
+ "path": "/api/lists/lst_1/contacts",
864
+ "bodySchema": "add-list-contacts-request",
865
+ "body": {
866
+ "contactIds": [
867
+ "ctr_1",
868
+ "ctr_2"
869
+ ]
870
+ }
871
+ },
872
+ "response": {
873
+ "status": 200,
874
+ "body": {
875
+ "added": 2
876
+ }
877
+ },
878
+ "result": {
879
+ "added": 2
880
+ }
881
+ },
882
+ {
883
+ "name": "remove_list_contact",
884
+ "method": "removeListContact",
885
+ "args": {
886
+ "id": "lst_1",
887
+ "contactId": "ctr_1"
888
+ },
889
+ "request": {
890
+ "method": "DELETE",
891
+ "path": "/api/lists/lst_1/contacts/ctr_1"
892
+ },
893
+ "response": {
894
+ "status": 200,
895
+ "body": {
896
+ "ok": true
897
+ }
898
+ },
899
+ "result": {
900
+ "ok": true
901
+ }
902
+ },
903
+ {
904
+ "name": "list_broadcasts",
905
+ "method": "listBroadcasts",
906
+ "args": {},
907
+ "request": {
908
+ "method": "GET",
909
+ "path": "/api/broadcasts"
910
+ },
911
+ "response": {
912
+ "status": 200,
913
+ "body": [
914
+ {
915
+ "id": "bct_1",
916
+ "subject": "Launch week",
917
+ "status": "draft"
918
+ }
919
+ ]
920
+ },
921
+ "result": [
922
+ {
923
+ "id": "bct_1",
924
+ "subject": "Launch week",
925
+ "status": "draft"
926
+ }
927
+ ]
928
+ },
929
+ {
930
+ "name": "create_broadcast",
931
+ "method": "createBroadcast",
932
+ "args": {
933
+ "from": "news@app.mailkite.dev",
934
+ "subject": "Launch week",
935
+ "audience": {
936
+ "type": "all"
937
+ },
938
+ "html": "<h1>We shipped</h1>"
939
+ },
940
+ "request": {
941
+ "method": "POST",
942
+ "path": "/api/broadcasts",
943
+ "bodySchema": "create-broadcast-request",
944
+ "body": {
945
+ "from": "news@app.mailkite.dev",
946
+ "subject": "Launch week",
947
+ "audience": {
948
+ "type": "all"
949
+ },
950
+ "html": "<h1>We shipped</h1>"
951
+ }
952
+ },
953
+ "response": {
954
+ "status": 201,
955
+ "body": {
956
+ "id": "bct_1",
957
+ "subject": "Launch week",
958
+ "status": "draft"
959
+ }
960
+ },
961
+ "result": {
962
+ "id": "bct_1",
963
+ "subject": "Launch week",
964
+ "status": "draft"
965
+ }
966
+ },
967
+ {
968
+ "name": "get_broadcast",
969
+ "method": "getBroadcast",
970
+ "args": {
971
+ "id": "bct_1"
972
+ },
973
+ "request": {
974
+ "method": "GET",
975
+ "path": "/api/broadcasts/bct_1"
976
+ },
977
+ "response": {
978
+ "status": 200,
979
+ "body": {
980
+ "id": "bct_1",
981
+ "subject": "Launch week",
982
+ "status": "draft"
983
+ }
984
+ },
985
+ "result": {
986
+ "id": "bct_1",
987
+ "subject": "Launch week",
988
+ "status": "draft"
989
+ }
990
+ },
991
+ {
992
+ "name": "update_broadcast",
993
+ "method": "updateBroadcast",
994
+ "args": {
995
+ "id": "bct_1",
996
+ "subject": "Launch week (final)"
997
+ },
998
+ "request": {
999
+ "method": "PATCH",
1000
+ "path": "/api/broadcasts/bct_1",
1001
+ "bodySchema": "update-broadcast-request",
1002
+ "body": {
1003
+ "subject": "Launch week (final)"
1004
+ }
1005
+ },
1006
+ "response": {
1007
+ "status": 200,
1008
+ "body": {
1009
+ "id": "bct_1",
1010
+ "subject": "Launch week (final)",
1011
+ "status": "draft"
1012
+ }
1013
+ },
1014
+ "result": {
1015
+ "id": "bct_1",
1016
+ "subject": "Launch week (final)",
1017
+ "status": "draft"
1018
+ }
1019
+ },
1020
+ {
1021
+ "name": "delete_broadcast",
1022
+ "method": "deleteBroadcast",
1023
+ "args": {
1024
+ "id": "bct_1"
1025
+ },
1026
+ "request": {
1027
+ "method": "DELETE",
1028
+ "path": "/api/broadcasts/bct_1"
1029
+ },
1030
+ "response": {
1031
+ "status": 200,
1032
+ "body": {
1033
+ "ok": true
1034
+ }
1035
+ },
1036
+ "result": {
1037
+ "ok": true
1038
+ }
1039
+ },
1040
+ {
1041
+ "name": "send_broadcast",
1042
+ "method": "sendBroadcast",
1043
+ "args": {
1044
+ "id": "bct_1",
1045
+ "scheduledAt": "2026-07-01T15:00:00Z"
1046
+ },
1047
+ "request": {
1048
+ "method": "POST",
1049
+ "path": "/api/broadcasts/bct_1/send",
1050
+ "bodySchema": "send-broadcast-request",
1051
+ "body": {
1052
+ "scheduledAt": "2026-07-01T15:00:00Z"
1053
+ }
1054
+ },
1055
+ "response": {
1056
+ "status": 200,
1057
+ "body": {
1058
+ "id": "bct_1",
1059
+ "status": "scheduled",
1060
+ "audienceCount": 2
1061
+ }
1062
+ },
1063
+ "result": {
1064
+ "id": "bct_1",
1065
+ "status": "scheduled",
1066
+ "audienceCount": 2
1067
+ }
1068
+ },
658
1069
  {
659
1070
  "name": "send_with_template",
660
1071
  "method": "send",
661
1072
  "args": {
662
1073
  "from": "hello@app.mailkite.dev",
663
1074
  "to": "ada@example.com",
664
- "templateId": "base_welcome-dark",
1075
+ "templateId": "base_welcome",
665
1076
  "templateData": {
666
1077
  "name": "Ada"
667
1078
  }
@@ -673,7 +1084,7 @@
673
1084
  "body": {
674
1085
  "from": "hello@app.mailkite.dev",
675
1086
  "to": "ada@example.com",
676
- "templateId": "base_welcome-dark",
1087
+ "templateId": "base_welcome",
677
1088
  "templateData": {
678
1089
  "name": "Ada"
679
1090
  }
@@ -733,8 +1144,8 @@
733
1144
  "status": 200,
734
1145
  "body": [
735
1146
  {
736
- "id": "base_welcome-dark",
737
- "name": "Welcome — Dark",
1147
+ "id": "base_welcome",
1148
+ "name": "Welcome",
738
1149
  "category": "Welcome",
739
1150
  "subject": "Welcome to MailKite",
740
1151
  "is_base": 1
@@ -743,8 +1154,8 @@
743
1154
  },
744
1155
  "result": [
745
1156
  {
746
- "id": "base_welcome-dark",
747
- "name": "Welcome — Dark",
1157
+ "id": "base_welcome",
1158
+ "name": "Welcome",
748
1159
  "category": "Welcome",
749
1160
  "subject": "Welcome to MailKite",
750
1161
  "is_base": 1
@@ -779,7 +1190,7 @@
779
1190
  "name": "create_template",
780
1191
  "method": "createTemplate",
781
1192
  "args": {
782
- "baseId": "base_welcome-dark",
1193
+ "baseId": "base_welcome",
783
1194
  "name": "My Welcome"
784
1195
  },
785
1196
  "request": {
@@ -787,7 +1198,7 @@
787
1198
  "path": "/api/templates",
788
1199
  "bodySchema": "create-template-request",
789
1200
  "body": {
790
- "baseId": "base_welcome-dark",
1201
+ "baseId": "base_welcome",
791
1202
  "name": "My Welcome"
792
1203
  }
793
1204
  },
@@ -956,6 +1367,42 @@
956
1367
  "privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9E2ll8K9E314m\njPfFkDBmImKFyvnqBJnqHukcAteqs99kK5QSx5wmg7PUw/9Ti/HTOr2V6lgXy6d+\nXbZl3XjCaFkmgTgKF9Zz8TtIQVUJNlmw1ztKEFr+yILoFovNxnND5WR+Nd5BUC6W\nW8sOAjswB21WthjDyVfEVSOHHRdYHcKAiF6e7yISDL5p9rcLFGjV37dvmH0DcskJ\nuYNwuAXlsEi4NIC3u4hK23pP9BEkDEmf0rmbSHugTl/VyzAlUiN/wUEcGu9Rl5iD\npIar+Vnbyr8ze6RNChWKcNjCZdGgI1mLDItbPEtW1IPvtyP6ymGuUqwl+C553q2t\nhuCURvlrAgMBAAECggEAWua+QXhZi28oQLh9VspfunrFizVuuYfEx75crE7hiPw5\nZltdMTouZIXlK2Gfm3coqDkRdMXZ3HbY6/P6ATddG3o3gj+VxaR4Qf20VqSyUV+D\n93VC1/TNCrkz1okgZaoHOJlMmzEizZvTCg7PrMh91DV957ZcaaSfQZD9J7RgyMeS\nC393/TI2IBR3nFQQMuNt0Rx0uXy2/T18hNQl2eSL+L2V+oCMERRetWzn9rQMDXI7\niLmh/dxE4gcTdSIflAUonWSFH6e9o8p+yJja4J966wP+B7j2dqmFr/09gBa3djHv\nEy+nhTYpfTrfYKnnE2pcXpFHWhd1iyRls93+Mb/RwQKBgQDqCyTLa8hjeeAun7fq\n2piRrFVr8NRVrFQwLmA8/3lcjXhCC80FG+SdSaZBJPD7EFDT3xePl/OnQmSHSnpR\nD+vklHVPAO4n3aMa/HKFgpxasxpUqRddzL6bBFNHpBgQR9Wv6hPiDP42SS7//uQF\nkrduS20kKsnrpGogy48zJQLfYwKBgQDO0E+PMmshHWbWDEE7Fjoe0dZtPx7CSG0B\nKXj5G+njHltUxPxodAYb95dUHQl/sFy3JpNcyBk8P+qlc/fhqojR/fE3+qK+EHjw\nKW/Ka4vEegtwdTXIeG4WgpTtFOjY7qsGHSFk2rFFjDrYtCMq6IBIClqk+dueCg52\nQsEHXQRwWQKBgQDBDNQa3xr5wswCaUhhdlImxsnnMU1UJcODwp0rc2d9ykuJ3wYL\n0sguXVO/pGMKFJk3Smu6zBH0wzT8y5g9SS7A6xwgQJoxVAZ3+gfUzLl/rwBnGNrn\nSj1mzJiNHXOj6jz+z8v6x9DgolkcW/lmB3E6jwjFrm3D62iHCKFkBIFsFQKBgAGq\ni/mLXnGV2w4+awge1bkJ18BpkcXe74Hi46aeIvRBelrke2QcCzCOfhmfYkQ1F4oi\nNW257vodSbariIO47AFFGnxo+Iave0n0C4KF+0pJ8W2mhBhpX/muc6S1VmrpAVe7\nRFmbqXH1/0NfsCjYVrA95R0PJkXPru4k+4kjprWBAoGAHtU/VXiOqSagIo3J/Bm5\nyUcJdbbguV/T9PPVu/Lq8SypCd5vqmwgYRmG+mIJEd/VYRkCZn3gbqNCn5OfbJh5\nG4Xatr7aofxyz2Qon/nix8Ut1+s1Npg1ugkz/atr4CZ4QArk8JmwsCReWJXCjKLX\n2WObKEWjGhgwths3MrC/CDw=\n-----END PRIVATE KEY-----"
957
1368
  },
958
1369
  "result": "Hello from MailKite — encrypted at rest. 🔒"
1370
+ },
1371
+ {
1372
+ "name": "semantic_search",
1373
+ "method": "semanticSearch",
1374
+ "args": {
1375
+ "query": "domains"
1376
+ },
1377
+ "request": {
1378
+ "method": "GET",
1379
+ "path": "/v1/docs/search"
1380
+ },
1381
+ "response": {
1382
+ "status": 200,
1383
+ "body": {
1384
+ "query": "domains",
1385
+ "matches": [
1386
+ {
1387
+ "slug": "domains",
1388
+ "title": "Domains & DNS",
1389
+ "section": "website",
1390
+ "snippet": "Add a domain, set DNS, and verify."
1391
+ }
1392
+ ]
1393
+ }
1394
+ },
1395
+ "result": {
1396
+ "query": "domains",
1397
+ "matches": [
1398
+ {
1399
+ "slug": "domains",
1400
+ "title": "Domains & DNS",
1401
+ "section": "website",
1402
+ "snippet": "Add a domain, set DNS, and verify."
1403
+ }
1404
+ ]
1405
+ }
959
1406
  }
960
1407
  ]
961
1408
  }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "add-list-contacts-request",
4
+ "title": "Add contacts to list request body",
5
+ "type": "object",
6
+ "required": ["contactIds"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "contactIds": {
10
+ "type": "array",
11
+ "items": { "type": "string" }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "create-broadcast-request",
4
+ "title": "Create broadcast request body",
5
+ "type": "object",
6
+ "required": ["from"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": { "type": "string" },
10
+ "from": { "type": "string" },
11
+ "replyTo": { "type": "string" },
12
+ "subject": { "type": "string" },
13
+ "preview": { "type": "string" },
14
+ "audience": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "properties": {
18
+ "type": { "type": "string", "enum": ["all", "list", "filter"] },
19
+ "id": { "type": "string" },
20
+ "query": { "type": "string" }
21
+ }
22
+ },
23
+ "templateId": { "type": "string" },
24
+ "html": { "type": "string" },
25
+ "text": { "type": "string" },
26
+ "footerAddress": { "type": "string" }
27
+ }
28
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "create-list-request",
4
+ "title": "Create list request body",
5
+ "type": "object",
6
+ "required": ["name"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": { "type": "string" }
10
+ }
11
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "semantic-search-response",
4
+ "title": "Semantic docs search response",
5
+ "type": "object",
6
+ "required": ["query", "matches"],
7
+ "properties": {
8
+ "query": { "type": "string", "description": "The query that was searched." },
9
+ "matches": {
10
+ "type": "array",
11
+ "description": "Most-relevant documentation sections, best first.",
12
+ "items": {
13
+ "type": "object",
14
+ "required": ["slug", "title", "snippet"],
15
+ "properties": {
16
+ "slug": { "type": "string", "description": "Doc slug — the page lives at https://mailkite.dev/docs/<slug> (e.g. \"quickstart\", \"domains\")." },
17
+ "title": { "type": "string", "description": "Human page title." },
18
+ "section": { "type": "string", "description": "Doc section/category." },
19
+ "snippet": { "type": "string", "description": "A relevant excerpt from the matched section." },
20
+ "score": { "type": "number", "description": "Relevance score (higher is closer); absent for lexical-only matches." }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "send-broadcast-request",
4
+ "title": "Send broadcast request body",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "scheduledAt": { "type": "string" }
9
+ }
10
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "update-broadcast-request",
4
+ "title": "Update broadcast request body (draft edits; all fields optional)",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "name": { "type": "string" },
9
+ "from": { "type": "string" },
10
+ "replyTo": { "type": "string" },
11
+ "subject": { "type": "string" },
12
+ "preview": { "type": "string" },
13
+ "audience": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "type": { "type": "string", "enum": ["all", "list", "filter"] },
18
+ "id": { "type": "string" },
19
+ "query": { "type": "string" }
20
+ }
21
+ },
22
+ "templateId": { "type": "string" },
23
+ "html": { "type": "string" },
24
+ "text": { "type": "string" },
25
+ "footerAddress": { "type": "string" }
26
+ }
27
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "update-list-request",
4
+ "title": "Update list request body",
5
+ "type": "object",
6
+ "required": ["name"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": { "type": "string" }
10
+ }
11
+ }
@@ -2,13 +2,15 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "upload-attachment-request",
4
4
  "title": "Upload attachment request body",
5
+ "description": "Provide the file ONE of four ways: `path` (a local file the SDK/CLI/MCP reads and streams as raw bytes), `url` (a remote file MailKite fetches and re-hosts), `content` (base64-encoded bytes), or — at the HTTP layer — the raw file bytes as the POST body with `?filename=`. `path`/raw-bytes go up as a real binary upload (like an S3/R2 PUT); `url`/`content` go up as JSON.",
5
6
  "type": "object",
6
- "required": ["filename", "content"],
7
7
  "additionalProperties": false,
8
8
  "properties": {
9
- "filename": { "type": "string", "description": "The file's name, e.g. \"invoice.pdf\". Shown to recipients on download." },
10
- "content": { "type": "string", "description": "The file bytes, base64-encoded." },
11
- "contentType": { "type": "string", "description": "MIME type, e.g. \"application/pdf\". Defaults to application/octet-stream." },
9
+ "filename": { "type": "string", "description": "The file's name, e.g. \"invoice.pdf\". Shown to recipients on download. Optional when it can be derived from `path` or `url`." },
10
+ "path": { "type": "string", "description": "Local filesystem path to the file. Read client-side by the CLI, SDKs, and the local MCP server, then uploaded as raw bytes. Not available on the hosted MCP (no filesystem)." },
11
+ "url": { "type": "string", "description": "A remote http(s) URL. MailKite fetches it and re-hosts the bytes under your account. Max 25 MB." },
12
+ "content": { "type": "string", "description": "The file bytes, base64-encoded. The lowest-common-denominator fallback when you can't send a path, URL, or raw bytes." },
13
+ "contentType": { "type": "string", "description": "MIME type, e.g. \"application/pdf\". Defaults to application/octet-stream (or is inferred from the file extension / fetched response)." },
12
14
  "retentionDays": {
13
15
  "type": "integer",
14
16
  "enum": [7, 30, 90, 365],