@codespar/mcp-sendgrid 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -14,18 +14,27 @@
14
14
  * - Suppressions per unsubscribe group (list / add)
15
15
  * - Global stats (sent / delivered / opens / clicks)
16
16
  *
17
- * Tools (11):
18
- * send_mail — POST /mail/send (personalizations, content, attachments)
19
- * send_template — POST /mail/send using a dynamic template_id
20
- * add_contact — PUT /marketing/contacts (upsert, async job)
21
- * list_contacts — GET /marketing/contacts
22
- * delete_contact DELETE /marketing/contacts?ids=...
23
- * search_contacts POST /marketing/contacts/search (SGQL)
24
- * list_templates GET /templates?generations=dynamic
25
- * create_template POST /templates
26
- * list_suppressions GET /asm/groups/{group_id}/suppressions
27
- * add_suppression POST /asm/groups/{group_id}/suppressions
28
- * get_stats — GET /stats?start_date=X&end_date=Y
17
+ * Tools (20):
18
+ * send_mail — POST /mail/send (personalizations, content, attachments)
19
+ * send_template — POST /mail/send using a dynamic template_id
20
+ * add_contact — PUT /marketing/contacts (upsert, async job)
21
+ * list_contacts — GET /marketing/contacts
22
+ * get_contact GET /marketing/contacts/{id}
23
+ * delete_contact DELETE /marketing/contacts?ids=...
24
+ * search_contacts POST /marketing/contacts/search (SGQL)
25
+ * list_lists GET /marketing/lists
26
+ * create_list POST /marketing/lists
27
+ * delete_list DELETE /marketing/lists/{id}
28
+ * list_templates — GET /templates?generations=dynamic
29
+ * create_template — POST /templates
30
+ * list_unsubscribe_groups — GET /asm/groups
31
+ * list_suppressions — GET /asm/groups/{group_id}/suppressions
32
+ * add_suppression — POST /asm/groups/{group_id}/suppressions
33
+ * get_bounces — GET /suppression/bounces
34
+ * delete_bounce — DELETE /suppression/bounces/{email}
35
+ * cancel_scheduled_send — POST /user/scheduled_sends (cancel/pause by batch_id)
36
+ * get_event_webhook_settings — GET /user/webhooks/event/settings
37
+ * get_stats — GET /stats?start_date=X&end_date=Y
29
38
  *
30
39
  * Authentication
31
40
  * Authorization: Bearer <SENDGRID_API_KEY>
@@ -83,7 +92,7 @@ function buildQuery(params) {
83
92
  const s = q.toString();
84
93
  return s ? `?${s}` : "";
85
94
  }
86
- const server = new Server({ name: "mcp-sendgrid", version: "0.1.0" }, { capabilities: { tools: {} } });
95
+ const server = new Server({ name: "mcp-sendgrid", version: "0.2.0" }, { capabilities: { tools: {} } });
87
96
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
88
97
  tools: [
89
98
  {
@@ -185,6 +194,51 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
185
194
  required: ["query"],
186
195
  },
187
196
  },
197
+ {
198
+ name: "get_contact",
199
+ description: "Retrieve a single Marketing Campaigns contact by id via GET /marketing/contacts/{id}. Returns full contact record including custom fields and list_ids.",
200
+ inputSchema: {
201
+ type: "object",
202
+ properties: {
203
+ id: { type: "string", description: "Contact UUID" },
204
+ },
205
+ required: ["id"],
206
+ },
207
+ },
208
+ {
209
+ name: "list_lists",
210
+ description: "List all Marketing Campaigns contact lists via GET /marketing/lists. Returns list UUIDs, names, and contact_count. Supports pagination.",
211
+ inputSchema: {
212
+ type: "object",
213
+ properties: {
214
+ page_size: { type: "number", description: "Results per page (default 100, max 1000)" },
215
+ page_token: { type: "string", description: "Pagination token from previous response" },
216
+ },
217
+ },
218
+ },
219
+ {
220
+ name: "create_list",
221
+ description: "Create a Marketing Campaigns contact list via POST /marketing/lists. Returns the new list UUID. Use the id with add_contact's list_ids to populate it.",
222
+ inputSchema: {
223
+ type: "object",
224
+ properties: {
225
+ name: { type: "string", description: "List name (max 100 chars, must be unique)" },
226
+ },
227
+ required: ["name"],
228
+ },
229
+ },
230
+ {
231
+ name: "delete_list",
232
+ description: "Delete a Marketing Campaigns contact list via DELETE /marketing/lists/{id}. Contacts are NOT deleted by default — set delete_contacts=true to also remove contacts that belong ONLY to this list.",
233
+ inputSchema: {
234
+ type: "object",
235
+ properties: {
236
+ id: { type: "string", description: "List UUID" },
237
+ delete_contacts: { type: "boolean", description: "If true, also delete contacts that are exclusive to this list (async job)" },
238
+ },
239
+ required: ["id"],
240
+ },
241
+ },
188
242
  {
189
243
  name: "list_templates",
190
244
  description: "List transactional templates via GET /templates. By default returns dynamic templates (recommended); set generations='legacy' for legacy.",
@@ -232,6 +286,60 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
232
286
  required: ["group_id", "recipient_emails"],
233
287
  },
234
288
  },
289
+ {
290
+ name: "list_unsubscribe_groups",
291
+ description: "List all unsubscribe groups on the account via GET /asm/groups. Returns [{id, name, description, is_default, unsubscribes}]. Use the id with list_suppressions / add_suppression.",
292
+ inputSchema: {
293
+ type: "object",
294
+ properties: {
295
+ id: { type: "number", description: "Optional: filter by a single group id" },
296
+ },
297
+ },
298
+ },
299
+ {
300
+ name: "get_bounces",
301
+ description: "Retrieve bounced recipients via GET /suppression/bounces. Returns [{email, created, reason, status}]. Filter by time window with start_time/end_time (Unix seconds).",
302
+ inputSchema: {
303
+ type: "object",
304
+ properties: {
305
+ start_time: { type: "number", description: "Unix timestamp (seconds) lower bound" },
306
+ end_time: { type: "number", description: "Unix timestamp (seconds) upper bound" },
307
+ limit: { type: "number", description: "Max results to return" },
308
+ offset: { type: "number", description: "Offset for pagination" },
309
+ },
310
+ },
311
+ },
312
+ {
313
+ name: "delete_bounce",
314
+ description: "Remove a bounced address from the bounce suppression list via DELETE /suppression/bounces/{email}. Call this after the recipient confirms the underlying issue (e.g. mailbox full) is resolved.",
315
+ inputSchema: {
316
+ type: "object",
317
+ properties: {
318
+ email: { type: "string", description: "Bounced email address to clear" },
319
+ },
320
+ required: ["email"],
321
+ },
322
+ },
323
+ {
324
+ name: "cancel_scheduled_send",
325
+ description: "Cancel or pause a scheduled send by batch_id via POST /user/scheduled_sends. A send_mail call with `send_at` + `batch_id` can be aborted until the send runs. Set status to 'cancel' or 'pause'.",
326
+ inputSchema: {
327
+ type: "object",
328
+ properties: {
329
+ batch_id: { type: "string", description: "The batch_id that was attached to the scheduled /mail/send call" },
330
+ status: { type: "string", enum: ["cancel", "pause"], description: "`cancel` aborts; `pause` holds the batch (can be resumed by deleting the status)" },
331
+ },
332
+ required: ["batch_id", "status"],
333
+ },
334
+ },
335
+ {
336
+ name: "get_event_webhook_settings",
337
+ description: "Retrieve the Event Webhook configuration via GET /user/webhooks/event/settings. Returns {url, enabled, delivered, open, click, bounce, dropped, spam_report, unsubscribe, ...} — useful to verify which SendGrid events are being forwarded.",
338
+ inputSchema: {
339
+ type: "object",
340
+ properties: {},
341
+ },
342
+ },
235
343
  {
236
344
  name: "get_stats",
237
345
  description: "Global email stats via GET /stats. Returns sent/delivered/opens/clicks/bounces/spam_reports aggregated between start_date and end_date.",
@@ -319,6 +427,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
319
427
  }
320
428
  case "search_contacts":
321
429
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/marketing/contacts/search", { query: a.query }), null, 2) }] };
430
+ case "get_contact":
431
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/marketing/contacts/${a.id}`), null, 2) }] };
432
+ case "list_lists": {
433
+ const q = buildQuery({
434
+ page_size: a.page_size,
435
+ page_token: a.page_token,
436
+ });
437
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/marketing/lists${q}`), null, 2) }] };
438
+ }
439
+ case "create_list":
440
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/marketing/lists", { name: a.name }), null, 2) }] };
441
+ case "delete_list": {
442
+ const q = buildQuery({
443
+ delete_contacts: a.delete_contacts ? "true" : undefined,
444
+ });
445
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("DELETE", `/marketing/lists/${a.id}${q}`), null, 2) }] };
446
+ }
322
447
  case "list_templates": {
323
448
  const q = buildQuery({
324
449
  generations: a.generations ?? "dynamic",
@@ -339,6 +464,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
339
464
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/asm/groups/${a.group_id}/suppressions`), null, 2) }] };
340
465
  case "add_suppression":
341
466
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", `/asm/groups/${a.group_id}/suppressions`, { recipient_emails: a.recipient_emails }), null, 2) }] };
467
+ case "list_unsubscribe_groups": {
468
+ const q = buildQuery({ id: a.id });
469
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/asm/groups${q}`), null, 2) }] };
470
+ }
471
+ case "get_bounces": {
472
+ const q = buildQuery({
473
+ start_time: a.start_time,
474
+ end_time: a.end_time,
475
+ limit: a.limit,
476
+ offset: a.offset,
477
+ });
478
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/suppression/bounces${q}`), null, 2) }] };
479
+ }
480
+ case "delete_bounce":
481
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("DELETE", `/suppression/bounces/${encodeURIComponent(String(a.email))}`), null, 2) }] };
482
+ case "cancel_scheduled_send":
483
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/user/scheduled_sends", { batch_id: a.batch_id, status: a.status }), null, 2) }] };
484
+ case "get_event_webhook_settings":
485
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", "/user/webhooks/event/settings"), null, 2) }] };
342
486
  case "get_stats": {
343
487
  const q = buildQuery({
344
488
  start_date: a.start_date,
@@ -374,7 +518,7 @@ async function main() {
374
518
  const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
375
519
  t.onclose = () => { if (t.sessionId)
376
520
  transports.delete(t.sessionId); };
377
- const s = new Server({ name: "mcp-sendgrid", version: "0.1.0" }, { capabilities: { tools: {} } });
521
+ const s = new Server({ name: "mcp-sendgrid", version: "0.2.0" }, { capabilities: { tools: {} } });
378
522
  server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
379
523
  server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
380
524
  await s.connect(t);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codespar/mcp-sendgrid",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for SendGrid — global transactional + marketing email (Twilio-owned). Pairs with @codespar/mcp-twilio for full messaging coverage.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "source": "github",
8
8
  "subfolder": "packages/communication/sendgrid"
9
9
  },
10
- "version": "0.1.0",
10
+ "version": "0.2.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "@codespar/mcp-sendgrid",
15
- "version": "0.1.0",
15
+ "version": "0.2.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
package/src/index.ts CHANGED
@@ -15,18 +15,27 @@
15
15
  * - Suppressions per unsubscribe group (list / add)
16
16
  * - Global stats (sent / delivered / opens / clicks)
17
17
  *
18
- * Tools (11):
19
- * send_mail — POST /mail/send (personalizations, content, attachments)
20
- * send_template — POST /mail/send using a dynamic template_id
21
- * add_contact — PUT /marketing/contacts (upsert, async job)
22
- * list_contacts — GET /marketing/contacts
23
- * delete_contact DELETE /marketing/contacts?ids=...
24
- * search_contacts POST /marketing/contacts/search (SGQL)
25
- * list_templates GET /templates?generations=dynamic
26
- * create_template POST /templates
27
- * list_suppressions GET /asm/groups/{group_id}/suppressions
28
- * add_suppression POST /asm/groups/{group_id}/suppressions
29
- * get_stats — GET /stats?start_date=X&end_date=Y
18
+ * Tools (20):
19
+ * send_mail — POST /mail/send (personalizations, content, attachments)
20
+ * send_template — POST /mail/send using a dynamic template_id
21
+ * add_contact — PUT /marketing/contacts (upsert, async job)
22
+ * list_contacts — GET /marketing/contacts
23
+ * get_contact GET /marketing/contacts/{id}
24
+ * delete_contact DELETE /marketing/contacts?ids=...
25
+ * search_contacts POST /marketing/contacts/search (SGQL)
26
+ * list_lists GET /marketing/lists
27
+ * create_list POST /marketing/lists
28
+ * delete_list DELETE /marketing/lists/{id}
29
+ * list_templates — GET /templates?generations=dynamic
30
+ * create_template — POST /templates
31
+ * list_unsubscribe_groups — GET /asm/groups
32
+ * list_suppressions — GET /asm/groups/{group_id}/suppressions
33
+ * add_suppression — POST /asm/groups/{group_id}/suppressions
34
+ * get_bounces — GET /suppression/bounces
35
+ * delete_bounce — DELETE /suppression/bounces/{email}
36
+ * cancel_scheduled_send — POST /user/scheduled_sends (cancel/pause by batch_id)
37
+ * get_event_webhook_settings — GET /user/webhooks/event/settings
38
+ * get_stats — GET /stats?start_date=X&end_date=Y
30
39
  *
31
40
  * Authentication
32
41
  * Authorization: Bearer <SENDGRID_API_KEY>
@@ -96,7 +105,7 @@ function buildQuery(params: Record<string, unknown>): string {
96
105
  }
97
106
 
98
107
  const server = new Server(
99
- { name: "mcp-sendgrid", version: "0.1.0" },
108
+ { name: "mcp-sendgrid", version: "0.2.0" },
100
109
  { capabilities: { tools: {} } }
101
110
  );
102
111
 
@@ -201,6 +210,51 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
201
210
  required: ["query"],
202
211
  },
203
212
  },
213
+ {
214
+ name: "get_contact",
215
+ description: "Retrieve a single Marketing Campaigns contact by id via GET /marketing/contacts/{id}. Returns full contact record including custom fields and list_ids.",
216
+ inputSchema: {
217
+ type: "object",
218
+ properties: {
219
+ id: { type: "string", description: "Contact UUID" },
220
+ },
221
+ required: ["id"],
222
+ },
223
+ },
224
+ {
225
+ name: "list_lists",
226
+ description: "List all Marketing Campaigns contact lists via GET /marketing/lists. Returns list UUIDs, names, and contact_count. Supports pagination.",
227
+ inputSchema: {
228
+ type: "object",
229
+ properties: {
230
+ page_size: { type: "number", description: "Results per page (default 100, max 1000)" },
231
+ page_token: { type: "string", description: "Pagination token from previous response" },
232
+ },
233
+ },
234
+ },
235
+ {
236
+ name: "create_list",
237
+ description: "Create a Marketing Campaigns contact list via POST /marketing/lists. Returns the new list UUID. Use the id with add_contact's list_ids to populate it.",
238
+ inputSchema: {
239
+ type: "object",
240
+ properties: {
241
+ name: { type: "string", description: "List name (max 100 chars, must be unique)" },
242
+ },
243
+ required: ["name"],
244
+ },
245
+ },
246
+ {
247
+ name: "delete_list",
248
+ description: "Delete a Marketing Campaigns contact list via DELETE /marketing/lists/{id}. Contacts are NOT deleted by default — set delete_contacts=true to also remove contacts that belong ONLY to this list.",
249
+ inputSchema: {
250
+ type: "object",
251
+ properties: {
252
+ id: { type: "string", description: "List UUID" },
253
+ delete_contacts: { type: "boolean", description: "If true, also delete contacts that are exclusive to this list (async job)" },
254
+ },
255
+ required: ["id"],
256
+ },
257
+ },
204
258
  {
205
259
  name: "list_templates",
206
260
  description: "List transactional templates via GET /templates. By default returns dynamic templates (recommended); set generations='legacy' for legacy.",
@@ -248,6 +302,60 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
248
302
  required: ["group_id", "recipient_emails"],
249
303
  },
250
304
  },
305
+ {
306
+ name: "list_unsubscribe_groups",
307
+ description: "List all unsubscribe groups on the account via GET /asm/groups. Returns [{id, name, description, is_default, unsubscribes}]. Use the id with list_suppressions / add_suppression.",
308
+ inputSchema: {
309
+ type: "object",
310
+ properties: {
311
+ id: { type: "number", description: "Optional: filter by a single group id" },
312
+ },
313
+ },
314
+ },
315
+ {
316
+ name: "get_bounces",
317
+ description: "Retrieve bounced recipients via GET /suppression/bounces. Returns [{email, created, reason, status}]. Filter by time window with start_time/end_time (Unix seconds).",
318
+ inputSchema: {
319
+ type: "object",
320
+ properties: {
321
+ start_time: { type: "number", description: "Unix timestamp (seconds) lower bound" },
322
+ end_time: { type: "number", description: "Unix timestamp (seconds) upper bound" },
323
+ limit: { type: "number", description: "Max results to return" },
324
+ offset: { type: "number", description: "Offset for pagination" },
325
+ },
326
+ },
327
+ },
328
+ {
329
+ name: "delete_bounce",
330
+ description: "Remove a bounced address from the bounce suppression list via DELETE /suppression/bounces/{email}. Call this after the recipient confirms the underlying issue (e.g. mailbox full) is resolved.",
331
+ inputSchema: {
332
+ type: "object",
333
+ properties: {
334
+ email: { type: "string", description: "Bounced email address to clear" },
335
+ },
336
+ required: ["email"],
337
+ },
338
+ },
339
+ {
340
+ name: "cancel_scheduled_send",
341
+ description: "Cancel or pause a scheduled send by batch_id via POST /user/scheduled_sends. A send_mail call with `send_at` + `batch_id` can be aborted until the send runs. Set status to 'cancel' or 'pause'.",
342
+ inputSchema: {
343
+ type: "object",
344
+ properties: {
345
+ batch_id: { type: "string", description: "The batch_id that was attached to the scheduled /mail/send call" },
346
+ status: { type: "string", enum: ["cancel", "pause"], description: "`cancel` aborts; `pause` holds the batch (can be resumed by deleting the status)" },
347
+ },
348
+ required: ["batch_id", "status"],
349
+ },
350
+ },
351
+ {
352
+ name: "get_event_webhook_settings",
353
+ description: "Retrieve the Event Webhook configuration via GET /user/webhooks/event/settings. Returns {url, enabled, delivered, open, click, bounce, dropped, spam_report, unsubscribe, ...} — useful to verify which SendGrid events are being forwarded.",
354
+ inputSchema: {
355
+ type: "object",
356
+ properties: {},
357
+ },
358
+ },
251
359
  {
252
360
  name: "get_stats",
253
361
  description: "Global email stats via GET /stats. Returns sent/delivered/opens/clicks/bounces/spam_reports aggregated between start_date and end_date.",
@@ -319,6 +427,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
319
427
  }
320
428
  case "search_contacts":
321
429
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/marketing/contacts/search", { query: a.query }), null, 2) }] };
430
+ case "get_contact":
431
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/marketing/contacts/${a.id}`), null, 2) }] };
432
+ case "list_lists": {
433
+ const q = buildQuery({
434
+ page_size: a.page_size,
435
+ page_token: a.page_token,
436
+ });
437
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/marketing/lists${q}`), null, 2) }] };
438
+ }
439
+ case "create_list":
440
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/marketing/lists", { name: a.name }), null, 2) }] };
441
+ case "delete_list": {
442
+ const q = buildQuery({
443
+ delete_contacts: a.delete_contacts ? "true" : undefined,
444
+ });
445
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("DELETE", `/marketing/lists/${a.id}${q}`), null, 2) }] };
446
+ }
322
447
  case "list_templates": {
323
448
  const q = buildQuery({
324
449
  generations: a.generations ?? "dynamic",
@@ -337,6 +462,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
337
462
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/asm/groups/${a.group_id}/suppressions`), null, 2) }] };
338
463
  case "add_suppression":
339
464
  return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", `/asm/groups/${a.group_id}/suppressions`, { recipient_emails: a.recipient_emails }), null, 2) }] };
465
+ case "list_unsubscribe_groups": {
466
+ const q = buildQuery({ id: a.id });
467
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/asm/groups${q}`), null, 2) }] };
468
+ }
469
+ case "get_bounces": {
470
+ const q = buildQuery({
471
+ start_time: a.start_time,
472
+ end_time: a.end_time,
473
+ limit: a.limit,
474
+ offset: a.offset,
475
+ });
476
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", `/suppression/bounces${q}`), null, 2) }] };
477
+ }
478
+ case "delete_bounce":
479
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("DELETE", `/suppression/bounces/${encodeURIComponent(String(a.email))}`), null, 2) }] };
480
+ case "cancel_scheduled_send":
481
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("POST", "/user/scheduled_sends", { batch_id: a.batch_id, status: a.status }), null, 2) }] };
482
+ case "get_event_webhook_settings":
483
+ return { content: [{ type: "text", text: JSON.stringify(await sendgridRequest("GET", "/user/webhooks/event/settings"), null, 2) }] };
340
484
  case "get_stats": {
341
485
  const q = buildQuery({
342
486
  start_date: a.start_date,
@@ -368,7 +512,7 @@ async function main() {
368
512
  if (!sid && isInitializeRequest(req.body)) {
369
513
  const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
370
514
  t.onclose = () => { if (t.sessionId) transports.delete(t.sessionId); };
371
- const s = new Server({ name: "mcp-sendgrid", version: "0.1.0" }, { capabilities: { tools: {} } });
515
+ const s = new Server({ name: "mcp-sendgrid", version: "0.2.0" }, { capabilities: { tools: {} } });
372
516
  (server as unknown as { _requestHandlers: Map<unknown, unknown> })._requestHandlers.forEach((v, k) => (s as unknown as { _requestHandlers: Map<unknown, unknown> })._requestHandlers.set(k, v));
373
517
  (server as unknown as { _notificationHandlers?: Map<unknown, unknown> })._notificationHandlers?.forEach((v, k) => (s as unknown as { _notificationHandlers: Map<unknown, unknown> })._notificationHandlers.set(k, v));
374
518
  await s.connect(t);