@codespar/mcp-twilio 0.1.0 → 0.2.1

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
@@ -4,22 +4,32 @@ MCP server for [Twilio](https://www.twilio.com) — the global standard for prog
4
4
 
5
5
  SMS, WhatsApp, and Voice across 180+ countries. Verify (2FA) and Lookup (phone validation) included. Fills the global messaging gap in a catalog otherwise tilted to Brazil-specific providers (Z-API, Take Blip, Zenvia, Evolution API).
6
6
 
7
- ## Tools
7
+ ## Tools (22)
8
8
 
9
9
  | Tool | Purpose |
10
- |------|---------|
11
- | `send_message` | Send an SMS or WhatsApp message (prefix `To` with `whatsapp:+E164` for WhatsApp) |
12
- | `get_message` | Retrieve a message by SID |
13
- | `list_messages` | List messages with optional filters (To, From, DateSent) |
14
- | `delete_message` | Delete a message from history |
15
- | `make_call` | Place an outbound voice call driven by a TwiML `Url` |
16
- | `get_call` | Retrieve a call by SID |
17
- | `update_call` | Hang up or redirect an in-progress call |
18
- | `start_verification` | Send a Verify (2FA) code via sms / whatsapp / call |
19
- | `check_verification` | Check a Verify (2FA) code |
20
- | `lookup_phone` | Validate + format + classify a phone number (Lookups v2) |
21
- | `list_incoming_numbers` | List your Twilio-provisioned phone numbers |
22
- | `buy_phone_number` | Provision a new phone number |
10
+ |---|---|
11
+ | `send_message` | Send an SMS or WhatsApp message. |
12
+ | `get_message` | Retrieve a message resource by SID (SM... |
13
+ | `list_messages` | List messages with optional filters. |
14
+ | `delete_message` | Delete a message from history. |
15
+ | `make_call` | Place an outbound voice call. |
16
+ | `get_call` | Retrieve a call resource by SID (CA...). |
17
+ | `update_call` | Modify an in-progress call. |
18
+ | `start_verification` | Start a Verify (2FA) challenge. |
19
+ | `check_verification` | Check a Verify (2FA) code against a Service SID. |
20
+ | `lookup_phone` | Validate and normalize a phone number via Lookups v2. |
21
+ | `list_incoming_numbers` | List Twilio-provisioned phone numbers on this account. |
22
+ | `buy_phone_number` | Provision a new phone number. |
23
+ | `list_recordings` | List call recordings on this account. |
24
+ | `create_verify_service` | Create a Verify Service (VA...). |
25
+ | `create_conversation` | Create a Twilio Conversation. |
26
+ | `list_conversations` | List Conversations. |
27
+ | `add_conversation_participant` | Add a participant to a Conversation. |
28
+ | `send_conversation_message` | Post a message into a Conversation. |
29
+ | `list_messaging_services` | List Messaging Services (MG...). |
30
+ | `execute_studio_flow` | Trigger a Studio Flow Execution for a contact. |
31
+ | `create_taskrouter_task` | Create a TaskRouter Task on a Workspace. |
32
+ | `list_taskrouter_workers` | List Workers on a TaskRouter Workspace. |
23
33
 
24
34
  ## Install
25
35
 
package/dist/index.js CHANGED
@@ -11,28 +11,42 @@
11
11
  * providers (Z-API, Take Blip, Zenvia, Evolution API). Twilio ships in 180+
12
12
  * countries on day one.
13
13
  *
14
- * Tools (12):
15
- * send_message — send SMS or WhatsApp (prefix `To` with `whatsapp:+E164`)
16
- * get_message — retrieve a message by SID
17
- * list_messages — list messages with optional To/From/DateSent filters
18
- * delete_message — delete a message from history
19
- * make_call — place an outbound voice call driven by a TwiML Url
20
- * get_call — retrieve a call by SID
21
- * update_call — hang up or redirect an in-progress call
22
- * start_verification send a Verify (2FA) code via sms / whatsapp / call
23
- * check_verification check a Verify (2FA) code
24
- * lookup_phonevalidate + format + classify a phone number
25
- * list_incoming_numbers list provisioned Twilio phone numbers
26
- * buy_phone_number provision a new phone number
14
+ * Tools (22):
15
+ * send_message — send SMS or WhatsApp (prefix `To` with `whatsapp:+E164`)
16
+ * get_message — retrieve a message by SID
17
+ * list_messages — list messages with optional To/From/DateSent filters
18
+ * delete_message — delete a message from history
19
+ * make_call — place an outbound voice call driven by a TwiML Url
20
+ * get_call — retrieve a call by SID
21
+ * update_call — hang up or redirect an in-progress call
22
+ * list_recordings list call recordings (optionally filtered by CallSid)
23
+ * start_verification send a Verify (2FA) code via sms / whatsapp / call
24
+ * check_verificationcheck a Verify (2FA) code
25
+ * create_verify_service provision a new Verify Service (VA...)
26
+ * lookup_phone validate + format + classify a phone number
27
+ * list_incoming_numbers — list provisioned Twilio phone numbers
28
+ * buy_phone_number — provision a new phone number
29
+ * create_conversation — create a Conversation (Conversations API)
30
+ * list_conversations — list Conversations
31
+ * add_conversation_participant — add an SMS / WhatsApp / chat participant to a Conversation
32
+ * send_conversation_message — post a message into a Conversation
33
+ * list_messaging_services — list Messaging Services (MG...)
34
+ * execute_studio_flow — trigger a Studio Flow execution for a contact
35
+ * create_taskrouter_task — create a TaskRouter task on a Workspace
36
+ * list_taskrouter_workers — list TaskRouter Workers on a Workspace
27
37
  *
28
38
  * Authentication
29
39
  * HTTP Basic with AccountSid:AuthToken.
30
40
  * Authorization: Basic <base64(AccountSid:AuthToken)>
31
41
  *
32
42
  * API surface
33
- * Accounts API : https://api.twilio.com/2010-04-01/Accounts/{AccountSid}
34
- * Verify API : https://verify.twilio.com/v2
35
- * Lookups API : https://lookups.twilio.com/v2
43
+ * Accounts API : https://api.twilio.com/2010-04-01/Accounts/{AccountSid}
44
+ * Verify API : https://verify.twilio.com/v2
45
+ * Lookups API : https://lookups.twilio.com/v2
46
+ * Conversations API : https://conversations.twilio.com/v1
47
+ * Messaging API : https://messaging.twilio.com/v1
48
+ * Studio API : https://studio.twilio.com/v2
49
+ * TaskRouter API : https://taskrouter.twilio.com/v1
36
50
  *
37
51
  * Request bodies are application/x-www-form-urlencoded. Responses are JSON
38
52
  * (Accounts endpoints use the `.json` suffix).
@@ -96,7 +110,7 @@ function buildQuery(params) {
96
110
  const s = q.toString();
97
111
  return s ? `?${s}` : "";
98
112
  }
99
- const server = new Server({ name: "mcp-twilio", version: "0.1.0" }, { capabilities: { tools: {} } });
113
+ const server = new Server({ name: "mcp-twilio", version: "0.2.1" }, { capabilities: { tools: {} } });
100
114
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
101
115
  tools: [
102
116
  {
@@ -260,6 +274,144 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
260
274
  },
261
275
  },
262
276
  },
277
+ {
278
+ name: "list_recordings",
279
+ description: "List call recordings on this account. Optionally filter by CallSid, or by DateCreated range. Returns Twilio's paginated list.",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ CallSid: { type: "string", description: "Restrict to recordings produced by this Call SID (CA...)" },
284
+ DateCreatedAfter: { type: "string", description: "Return recordings created on/after this date (YYYY-MM-DD)" },
285
+ DateCreatedBefore: { type: "string", description: "Return recordings created on/before this date (YYYY-MM-DD)" },
286
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
287
+ },
288
+ },
289
+ },
290
+ {
291
+ name: "create_verify_service",
292
+ description: "Create a Verify Service (VA...). A service groups verification attempts and holds per-service config (code length, friendly name).",
293
+ inputSchema: {
294
+ type: "object",
295
+ properties: {
296
+ FriendlyName: { type: "string", description: "Human-readable name for the service (e.g. your app name)" },
297
+ CodeLength: { type: "number", description: "OTP code length, 4-10 (default 6)" },
298
+ LookupEnabled: { type: "boolean", description: "Run Lookup on targets before sending (blocks invalid numbers)" },
299
+ DefaultTemplateSid: { type: "string", description: "Default message template SID" },
300
+ },
301
+ required: ["FriendlyName"],
302
+ },
303
+ },
304
+ {
305
+ name: "create_conversation",
306
+ description: "Create a Twilio Conversation. Conversations host multi-channel (SMS / WhatsApp / chat) threads with server-side history.",
307
+ inputSchema: {
308
+ type: "object",
309
+ properties: {
310
+ FriendlyName: { type: "string", description: "Human-readable label for the conversation" },
311
+ UniqueName: { type: "string", description: "Developer-defined unique identifier (alternative addressable key)" },
312
+ MessagingServiceSid: { type: "string", description: "Messaging Service SID (MG...) used for outbound SMS/WhatsApp in this conversation" },
313
+ Attributes: { type: "string", description: "JSON string of custom attributes stored on the conversation" },
314
+ },
315
+ },
316
+ },
317
+ {
318
+ name: "list_conversations",
319
+ description: "List Conversations. Returns a paginated list; pass PageSize to cap.",
320
+ inputSchema: {
321
+ type: "object",
322
+ properties: {
323
+ StartDate: { type: "string", description: "Only include conversations created on/after this ISO-8601 date" },
324
+ EndDate: { type: "string", description: "Only include conversations created on/before this ISO-8601 date" },
325
+ State: { type: "string", enum: ["active", "inactive", "closed"], description: "Filter by conversation state" },
326
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
327
+ },
328
+ },
329
+ },
330
+ {
331
+ name: "add_conversation_participant",
332
+ description: "Add a participant to a Conversation. For SMS / WhatsApp, pass MessagingBinding.Address (+E164 or whatsapp:+E164) + MessagingBinding.ProxyAddress (your Twilio number). For chat participants, pass Identity.",
333
+ inputSchema: {
334
+ type: "object",
335
+ properties: {
336
+ ConversationSid: { type: "string", description: "Conversation SID (CH...) or UniqueName" },
337
+ Identity: { type: "string", description: "Chat identity (use for in-app chat participants)" },
338
+ "MessagingBinding.Address": { type: "string", description: "Participant's address: +E164 for SMS, whatsapp:+E164 for WhatsApp" },
339
+ "MessagingBinding.ProxyAddress": { type: "string", description: "Your Twilio number the participant messages with (E.164 or whatsapp:+E164)" },
340
+ Attributes: { type: "string", description: "JSON string of custom participant attributes" },
341
+ },
342
+ required: ["ConversationSid"],
343
+ },
344
+ },
345
+ {
346
+ name: "send_conversation_message",
347
+ description: "Post a message into a Conversation. Fanned out to all participants via their channel (SMS / WhatsApp / chat).",
348
+ inputSchema: {
349
+ type: "object",
350
+ properties: {
351
+ ConversationSid: { type: "string", description: "Conversation SID (CH...) or UniqueName" },
352
+ Body: { type: "string", description: "Message text (UTF-8)" },
353
+ Author: { type: "string", description: "Identity of the author (defaults to `system` if omitted)" },
354
+ MediaSid: { type: "string", description: "Media SID (ME...) from a prior MCS upload" },
355
+ Attributes: { type: "string", description: "JSON string of custom message attributes" },
356
+ },
357
+ required: ["ConversationSid"],
358
+ },
359
+ },
360
+ {
361
+ name: "list_messaging_services",
362
+ description: "List Messaging Services (MG...). A Messaging Service bundles sender pools, templates, and routing rules.",
363
+ inputSchema: {
364
+ type: "object",
365
+ properties: {
366
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
367
+ },
368
+ },
369
+ },
370
+ {
371
+ name: "execute_studio_flow",
372
+ description: "Trigger a Studio Flow Execution for a contact. Studio flows are visual IVR / workflow builders — this kicks one off for a specific To/From pair.",
373
+ inputSchema: {
374
+ type: "object",
375
+ properties: {
376
+ FlowSid: { type: "string", description: "Studio Flow SID (FW...)" },
377
+ To: { type: "string", description: "Contact address (E.164 or whatsapp:+E164)" },
378
+ From: { type: "string", description: "Your Twilio number (E.164 or whatsapp:+E164)" },
379
+ Parameters: { type: "string", description: "JSON string of variables injected into the flow's execution context" },
380
+ },
381
+ required: ["FlowSid", "To", "From"],
382
+ },
383
+ },
384
+ {
385
+ name: "create_taskrouter_task",
386
+ description: "Create a TaskRouter Task on a Workspace. TaskRouter routes work (calls, chats, tickets) to eligible Workers based on attributes.",
387
+ inputSchema: {
388
+ type: "object",
389
+ properties: {
390
+ WorkspaceSid: { type: "string", description: "TaskRouter Workspace SID (WS...)" },
391
+ Attributes: { type: "string", description: "JSON string of task attributes used for routing (e.g. {\"selected_language\":\"pt-br\"})" },
392
+ WorkflowSid: { type: "string", description: "Workflow SID (WW...) that decides how this task is routed" },
393
+ TaskChannel: { type: "string", description: "Task channel unique_name or SID (e.g. voice, chat, sms, default)" },
394
+ Priority: { type: "number", description: "Priority (higher = more urgent)" },
395
+ Timeout: { type: "number", description: "Seconds before the task times out (default 86400)" },
396
+ },
397
+ required: ["WorkspaceSid"],
398
+ },
399
+ },
400
+ {
401
+ name: "list_taskrouter_workers",
402
+ description: "List Workers on a TaskRouter Workspace. Optionally filter by ActivityName, Available, or TargetWorkersExpression.",
403
+ inputSchema: {
404
+ type: "object",
405
+ properties: {
406
+ WorkspaceSid: { type: "string", description: "TaskRouter Workspace SID (WS...)" },
407
+ ActivityName: { type: "string", description: "Filter by activity name (e.g. Available, Idle, Offline)" },
408
+ Available: { type: "string", description: "Filter by availability: 'true' or 'false'" },
409
+ TargetWorkersExpression: { type: "string", description: "TaskRouter expression to filter workers (e.g. languages HAS \"pt-br\")" },
410
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
411
+ },
412
+ required: ["WorkspaceSid"],
413
+ },
414
+ },
263
415
  ],
264
416
  }));
265
417
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -370,6 +522,106 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
370
522
  body.StatusCallback = a.StatusCallback;
371
523
  return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "/IncomingPhoneNumbers.json", body), null, 2) }] };
372
524
  }
525
+ case "list_recordings": {
526
+ const q = buildQuery({
527
+ CallSid: a.CallSid,
528
+ "DateCreated>": a.DateCreatedAfter,
529
+ "DateCreated<": a.DateCreatedBefore,
530
+ PageSize: a.PageSize,
531
+ });
532
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `/Recordings.json${q}`), null, 2) }] };
533
+ }
534
+ case "create_verify_service": {
535
+ const body = { FriendlyName: a.FriendlyName };
536
+ if (a.CodeLength !== undefined)
537
+ body.CodeLength = a.CodeLength;
538
+ if (a.LookupEnabled !== undefined)
539
+ body.LookupEnabled = a.LookupEnabled;
540
+ if (a.DefaultTemplateSid)
541
+ body.DefaultTemplateSid = a.DefaultTemplateSid;
542
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "https://verify.twilio.com/v2/Services", body), null, 2) }] };
543
+ }
544
+ case "create_conversation": {
545
+ const body = {};
546
+ if (a.FriendlyName)
547
+ body.FriendlyName = a.FriendlyName;
548
+ if (a.UniqueName)
549
+ body.UniqueName = a.UniqueName;
550
+ if (a.MessagingServiceSid)
551
+ body.MessagingServiceSid = a.MessagingServiceSid;
552
+ if (a.Attributes)
553
+ body.Attributes = a.Attributes;
554
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "https://conversations.twilio.com/v1/Conversations", body), null, 2) }] };
555
+ }
556
+ case "list_conversations": {
557
+ const q = buildQuery({
558
+ StartDate: a.StartDate,
559
+ EndDate: a.EndDate,
560
+ State: a.State,
561
+ PageSize: a.PageSize,
562
+ });
563
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://conversations.twilio.com/v1/Conversations${q}`), null, 2) }] };
564
+ }
565
+ case "add_conversation_participant": {
566
+ const body = {};
567
+ if (a.Identity)
568
+ body.Identity = a.Identity;
569
+ if (a["MessagingBinding.Address"])
570
+ body["MessagingBinding.Address"] = a["MessagingBinding.Address"];
571
+ if (a["MessagingBinding.ProxyAddress"])
572
+ body["MessagingBinding.ProxyAddress"] = a["MessagingBinding.ProxyAddress"];
573
+ if (a.Attributes)
574
+ body.Attributes = a.Attributes;
575
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://conversations.twilio.com/v1/Conversations/${a.ConversationSid}/Participants`, body), null, 2) }] };
576
+ }
577
+ case "send_conversation_message": {
578
+ const body = {};
579
+ if (a.Body)
580
+ body.Body = a.Body;
581
+ if (a.Author)
582
+ body.Author = a.Author;
583
+ if (a.MediaSid)
584
+ body.MediaSid = a.MediaSid;
585
+ if (a.Attributes)
586
+ body.Attributes = a.Attributes;
587
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://conversations.twilio.com/v1/Conversations/${a.ConversationSid}/Messages`, body), null, 2) }] };
588
+ }
589
+ case "list_messaging_services": {
590
+ const q = buildQuery({ PageSize: a.PageSize });
591
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://messaging.twilio.com/v1/Services${q}`), null, 2) }] };
592
+ }
593
+ case "execute_studio_flow": {
594
+ const body = {
595
+ To: a.To,
596
+ From: a.From,
597
+ };
598
+ if (a.Parameters)
599
+ body.Parameters = a.Parameters;
600
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://studio.twilio.com/v2/Flows/${a.FlowSid}/Executions`, body), null, 2) }] };
601
+ }
602
+ case "create_taskrouter_task": {
603
+ const body = {};
604
+ if (a.Attributes)
605
+ body.Attributes = a.Attributes;
606
+ if (a.WorkflowSid)
607
+ body.WorkflowSid = a.WorkflowSid;
608
+ if (a.TaskChannel)
609
+ body.TaskChannel = a.TaskChannel;
610
+ if (a.Priority !== undefined)
611
+ body.Priority = a.Priority;
612
+ if (a.Timeout !== undefined)
613
+ body.Timeout = a.Timeout;
614
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://taskrouter.twilio.com/v1/Workspaces/${a.WorkspaceSid}/Tasks`, body), null, 2) }] };
615
+ }
616
+ case "list_taskrouter_workers": {
617
+ const q = buildQuery({
618
+ ActivityName: a.ActivityName,
619
+ Available: a.Available,
620
+ TargetWorkersExpression: a.TargetWorkersExpression,
621
+ PageSize: a.PageSize,
622
+ });
623
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://taskrouter.twilio.com/v1/Workspaces/${a.WorkspaceSid}/Workers${q}`), null, 2) }] };
624
+ }
373
625
  default:
374
626
  return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
375
627
  }
@@ -396,7 +648,7 @@ async function main() {
396
648
  const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
397
649
  t.onclose = () => { if (t.sessionId)
398
650
  transports.delete(t.sessionId); };
399
- const s = new Server({ name: "mcp-twilio", version: "0.1.0" }, { capabilities: { tools: {} } });
651
+ const s = new Server({ name: "mcp-twilio", version: "0.2.1" }, { capabilities: { tools: {} } });
400
652
  server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
401
653
  server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
402
654
  await s.connect(t);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codespar/mcp-twilio",
3
- "version": "0.1.0",
4
- "description": "MCP server for Twilio global SMS, WhatsApp, Voice, Verify, and Lookup across 180+ countries",
3
+ "version": "0.2.1",
4
+ "description": "MCP server for Twilio \u2014 global SMS, WhatsApp, Voice, Verify, and Lookup across 180+ countries",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "source": "github",
8
8
  "subfolder": "packages/communication/twilio"
9
9
  },
10
- "version": "0.1.0",
10
+ "version": "0.2.1",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "@codespar/mcp-twilio",
15
- "version": "0.1.0",
15
+ "version": "0.2.1",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
package/src/index.ts CHANGED
@@ -12,28 +12,42 @@
12
12
  * providers (Z-API, Take Blip, Zenvia, Evolution API). Twilio ships in 180+
13
13
  * countries on day one.
14
14
  *
15
- * Tools (12):
16
- * send_message — send SMS or WhatsApp (prefix `To` with `whatsapp:+E164`)
17
- * get_message — retrieve a message by SID
18
- * list_messages — list messages with optional To/From/DateSent filters
19
- * delete_message — delete a message from history
20
- * make_call — place an outbound voice call driven by a TwiML Url
21
- * get_call — retrieve a call by SID
22
- * update_call — hang up or redirect an in-progress call
23
- * start_verification send a Verify (2FA) code via sms / whatsapp / call
24
- * check_verification check a Verify (2FA) code
25
- * lookup_phonevalidate + format + classify a phone number
26
- * list_incoming_numbers list provisioned Twilio phone numbers
27
- * buy_phone_number provision a new phone number
15
+ * Tools (22):
16
+ * send_message — send SMS or WhatsApp (prefix `To` with `whatsapp:+E164`)
17
+ * get_message — retrieve a message by SID
18
+ * list_messages — list messages with optional To/From/DateSent filters
19
+ * delete_message — delete a message from history
20
+ * make_call — place an outbound voice call driven by a TwiML Url
21
+ * get_call — retrieve a call by SID
22
+ * update_call — hang up or redirect an in-progress call
23
+ * list_recordings list call recordings (optionally filtered by CallSid)
24
+ * start_verification send a Verify (2FA) code via sms / whatsapp / call
25
+ * check_verificationcheck a Verify (2FA) code
26
+ * create_verify_service provision a new Verify Service (VA...)
27
+ * lookup_phone validate + format + classify a phone number
28
+ * list_incoming_numbers — list provisioned Twilio phone numbers
29
+ * buy_phone_number — provision a new phone number
30
+ * create_conversation — create a Conversation (Conversations API)
31
+ * list_conversations — list Conversations
32
+ * add_conversation_participant — add an SMS / WhatsApp / chat participant to a Conversation
33
+ * send_conversation_message — post a message into a Conversation
34
+ * list_messaging_services — list Messaging Services (MG...)
35
+ * execute_studio_flow — trigger a Studio Flow execution for a contact
36
+ * create_taskrouter_task — create a TaskRouter task on a Workspace
37
+ * list_taskrouter_workers — list TaskRouter Workers on a Workspace
28
38
  *
29
39
  * Authentication
30
40
  * HTTP Basic with AccountSid:AuthToken.
31
41
  * Authorization: Basic <base64(AccountSid:AuthToken)>
32
42
  *
33
43
  * API surface
34
- * Accounts API : https://api.twilio.com/2010-04-01/Accounts/{AccountSid}
35
- * Verify API : https://verify.twilio.com/v2
36
- * Lookups API : https://lookups.twilio.com/v2
44
+ * Accounts API : https://api.twilio.com/2010-04-01/Accounts/{AccountSid}
45
+ * Verify API : https://verify.twilio.com/v2
46
+ * Lookups API : https://lookups.twilio.com/v2
47
+ * Conversations API : https://conversations.twilio.com/v1
48
+ * Messaging API : https://messaging.twilio.com/v1
49
+ * Studio API : https://studio.twilio.com/v2
50
+ * TaskRouter API : https://taskrouter.twilio.com/v1
37
51
  *
38
52
  * Request bodies are application/x-www-form-urlencoded. Responses are JSON
39
53
  * (Accounts endpoints use the `.json` suffix).
@@ -109,7 +123,7 @@ function buildQuery(params: Record<string, unknown>): string {
109
123
  }
110
124
 
111
125
  const server = new Server(
112
- { name: "mcp-twilio", version: "0.1.0" },
126
+ { name: "mcp-twilio", version: "0.2.1" },
113
127
  { capabilities: { tools: {} } }
114
128
  );
115
129
 
@@ -276,6 +290,144 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
276
290
  },
277
291
  },
278
292
  },
293
+ {
294
+ name: "list_recordings",
295
+ description: "List call recordings on this account. Optionally filter by CallSid, or by DateCreated range. Returns Twilio's paginated list.",
296
+ inputSchema: {
297
+ type: "object",
298
+ properties: {
299
+ CallSid: { type: "string", description: "Restrict to recordings produced by this Call SID (CA...)" },
300
+ DateCreatedAfter: { type: "string", description: "Return recordings created on/after this date (YYYY-MM-DD)" },
301
+ DateCreatedBefore: { type: "string", description: "Return recordings created on/before this date (YYYY-MM-DD)" },
302
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
303
+ },
304
+ },
305
+ },
306
+ {
307
+ name: "create_verify_service",
308
+ description: "Create a Verify Service (VA...). A service groups verification attempts and holds per-service config (code length, friendly name).",
309
+ inputSchema: {
310
+ type: "object",
311
+ properties: {
312
+ FriendlyName: { type: "string", description: "Human-readable name for the service (e.g. your app name)" },
313
+ CodeLength: { type: "number", description: "OTP code length, 4-10 (default 6)" },
314
+ LookupEnabled: { type: "boolean", description: "Run Lookup on targets before sending (blocks invalid numbers)" },
315
+ DefaultTemplateSid: { type: "string", description: "Default message template SID" },
316
+ },
317
+ required: ["FriendlyName"],
318
+ },
319
+ },
320
+ {
321
+ name: "create_conversation",
322
+ description: "Create a Twilio Conversation. Conversations host multi-channel (SMS / WhatsApp / chat) threads with server-side history.",
323
+ inputSchema: {
324
+ type: "object",
325
+ properties: {
326
+ FriendlyName: { type: "string", description: "Human-readable label for the conversation" },
327
+ UniqueName: { type: "string", description: "Developer-defined unique identifier (alternative addressable key)" },
328
+ MessagingServiceSid: { type: "string", description: "Messaging Service SID (MG...) used for outbound SMS/WhatsApp in this conversation" },
329
+ Attributes: { type: "string", description: "JSON string of custom attributes stored on the conversation" },
330
+ },
331
+ },
332
+ },
333
+ {
334
+ name: "list_conversations",
335
+ description: "List Conversations. Returns a paginated list; pass PageSize to cap.",
336
+ inputSchema: {
337
+ type: "object",
338
+ properties: {
339
+ StartDate: { type: "string", description: "Only include conversations created on/after this ISO-8601 date" },
340
+ EndDate: { type: "string", description: "Only include conversations created on/before this ISO-8601 date" },
341
+ State: { type: "string", enum: ["active", "inactive", "closed"], description: "Filter by conversation state" },
342
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
343
+ },
344
+ },
345
+ },
346
+ {
347
+ name: "add_conversation_participant",
348
+ description: "Add a participant to a Conversation. For SMS / WhatsApp, pass MessagingBinding.Address (+E164 or whatsapp:+E164) + MessagingBinding.ProxyAddress (your Twilio number). For chat participants, pass Identity.",
349
+ inputSchema: {
350
+ type: "object",
351
+ properties: {
352
+ ConversationSid: { type: "string", description: "Conversation SID (CH...) or UniqueName" },
353
+ Identity: { type: "string", description: "Chat identity (use for in-app chat participants)" },
354
+ "MessagingBinding.Address": { type: "string", description: "Participant's address: +E164 for SMS, whatsapp:+E164 for WhatsApp" },
355
+ "MessagingBinding.ProxyAddress": { type: "string", description: "Your Twilio number the participant messages with (E.164 or whatsapp:+E164)" },
356
+ Attributes: { type: "string", description: "JSON string of custom participant attributes" },
357
+ },
358
+ required: ["ConversationSid"],
359
+ },
360
+ },
361
+ {
362
+ name: "send_conversation_message",
363
+ description: "Post a message into a Conversation. Fanned out to all participants via their channel (SMS / WhatsApp / chat).",
364
+ inputSchema: {
365
+ type: "object",
366
+ properties: {
367
+ ConversationSid: { type: "string", description: "Conversation SID (CH...) or UniqueName" },
368
+ Body: { type: "string", description: "Message text (UTF-8)" },
369
+ Author: { type: "string", description: "Identity of the author (defaults to `system` if omitted)" },
370
+ MediaSid: { type: "string", description: "Media SID (ME...) from a prior MCS upload" },
371
+ Attributes: { type: "string", description: "JSON string of custom message attributes" },
372
+ },
373
+ required: ["ConversationSid"],
374
+ },
375
+ },
376
+ {
377
+ name: "list_messaging_services",
378
+ description: "List Messaging Services (MG...). A Messaging Service bundles sender pools, templates, and routing rules.",
379
+ inputSchema: {
380
+ type: "object",
381
+ properties: {
382
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
383
+ },
384
+ },
385
+ },
386
+ {
387
+ name: "execute_studio_flow",
388
+ description: "Trigger a Studio Flow Execution for a contact. Studio flows are visual IVR / workflow builders — this kicks one off for a specific To/From pair.",
389
+ inputSchema: {
390
+ type: "object",
391
+ properties: {
392
+ FlowSid: { type: "string", description: "Studio Flow SID (FW...)" },
393
+ To: { type: "string", description: "Contact address (E.164 or whatsapp:+E164)" },
394
+ From: { type: "string", description: "Your Twilio number (E.164 or whatsapp:+E164)" },
395
+ Parameters: { type: "string", description: "JSON string of variables injected into the flow's execution context" },
396
+ },
397
+ required: ["FlowSid", "To", "From"],
398
+ },
399
+ },
400
+ {
401
+ name: "create_taskrouter_task",
402
+ description: "Create a TaskRouter Task on a Workspace. TaskRouter routes work (calls, chats, tickets) to eligible Workers based on attributes.",
403
+ inputSchema: {
404
+ type: "object",
405
+ properties: {
406
+ WorkspaceSid: { type: "string", description: "TaskRouter Workspace SID (WS...)" },
407
+ Attributes: { type: "string", description: "JSON string of task attributes used for routing (e.g. {\"selected_language\":\"pt-br\"})" },
408
+ WorkflowSid: { type: "string", description: "Workflow SID (WW...) that decides how this task is routed" },
409
+ TaskChannel: { type: "string", description: "Task channel unique_name or SID (e.g. voice, chat, sms, default)" },
410
+ Priority: { type: "number", description: "Priority (higher = more urgent)" },
411
+ Timeout: { type: "number", description: "Seconds before the task times out (default 86400)" },
412
+ },
413
+ required: ["WorkspaceSid"],
414
+ },
415
+ },
416
+ {
417
+ name: "list_taskrouter_workers",
418
+ description: "List Workers on a TaskRouter Workspace. Optionally filter by ActivityName, Available, or TargetWorkersExpression.",
419
+ inputSchema: {
420
+ type: "object",
421
+ properties: {
422
+ WorkspaceSid: { type: "string", description: "TaskRouter Workspace SID (WS...)" },
423
+ ActivityName: { type: "string", description: "Filter by activity name (e.g. Available, Idle, Offline)" },
424
+ Available: { type: "string", description: "Filter by availability: 'true' or 'false'" },
425
+ TargetWorkersExpression: { type: "string", description: "TaskRouter expression to filter workers (e.g. languages HAS \"pt-br\")" },
426
+ PageSize: { type: "number", description: "Max rows per page (default 50, max 1000)" },
427
+ },
428
+ required: ["WorkspaceSid"],
429
+ },
430
+ },
279
431
  ],
280
432
  }));
281
433
 
@@ -370,6 +522,85 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
370
522
  if (a.StatusCallback) body.StatusCallback = a.StatusCallback;
371
523
  return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "/IncomingPhoneNumbers.json", body), null, 2) }] };
372
524
  }
525
+ case "list_recordings": {
526
+ const q = buildQuery({
527
+ CallSid: a.CallSid,
528
+ "DateCreated>": a.DateCreatedAfter,
529
+ "DateCreated<": a.DateCreatedBefore,
530
+ PageSize: a.PageSize,
531
+ });
532
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `/Recordings.json${q}`), null, 2) }] };
533
+ }
534
+ case "create_verify_service": {
535
+ const body: Record<string, unknown> = { FriendlyName: a.FriendlyName };
536
+ if (a.CodeLength !== undefined) body.CodeLength = a.CodeLength;
537
+ if (a.LookupEnabled !== undefined) body.LookupEnabled = a.LookupEnabled;
538
+ if (a.DefaultTemplateSid) body.DefaultTemplateSid = a.DefaultTemplateSid;
539
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "https://verify.twilio.com/v2/Services", body), null, 2) }] };
540
+ }
541
+ case "create_conversation": {
542
+ const body: Record<string, unknown> = {};
543
+ if (a.FriendlyName) body.FriendlyName = a.FriendlyName;
544
+ if (a.UniqueName) body.UniqueName = a.UniqueName;
545
+ if (a.MessagingServiceSid) body.MessagingServiceSid = a.MessagingServiceSid;
546
+ if (a.Attributes) body.Attributes = a.Attributes;
547
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", "https://conversations.twilio.com/v1/Conversations", body), null, 2) }] };
548
+ }
549
+ case "list_conversations": {
550
+ const q = buildQuery({
551
+ StartDate: a.StartDate,
552
+ EndDate: a.EndDate,
553
+ State: a.State,
554
+ PageSize: a.PageSize,
555
+ });
556
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://conversations.twilio.com/v1/Conversations${q}`), null, 2) }] };
557
+ }
558
+ case "add_conversation_participant": {
559
+ const body: Record<string, unknown> = {};
560
+ if (a.Identity) body.Identity = a.Identity;
561
+ if (a["MessagingBinding.Address"]) body["MessagingBinding.Address"] = a["MessagingBinding.Address"];
562
+ if (a["MessagingBinding.ProxyAddress"]) body["MessagingBinding.ProxyAddress"] = a["MessagingBinding.ProxyAddress"];
563
+ if (a.Attributes) body.Attributes = a.Attributes;
564
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://conversations.twilio.com/v1/Conversations/${a.ConversationSid}/Participants`, body), null, 2) }] };
565
+ }
566
+ case "send_conversation_message": {
567
+ const body: Record<string, unknown> = {};
568
+ if (a.Body) body.Body = a.Body;
569
+ if (a.Author) body.Author = a.Author;
570
+ if (a.MediaSid) body.MediaSid = a.MediaSid;
571
+ if (a.Attributes) body.Attributes = a.Attributes;
572
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://conversations.twilio.com/v1/Conversations/${a.ConversationSid}/Messages`, body), null, 2) }] };
573
+ }
574
+ case "list_messaging_services": {
575
+ const q = buildQuery({ PageSize: a.PageSize });
576
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://messaging.twilio.com/v1/Services${q}`), null, 2) }] };
577
+ }
578
+ case "execute_studio_flow": {
579
+ const body: Record<string, unknown> = {
580
+ To: a.To,
581
+ From: a.From,
582
+ };
583
+ if (a.Parameters) body.Parameters = a.Parameters;
584
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://studio.twilio.com/v2/Flows/${a.FlowSid}/Executions`, body), null, 2) }] };
585
+ }
586
+ case "create_taskrouter_task": {
587
+ const body: Record<string, unknown> = {};
588
+ if (a.Attributes) body.Attributes = a.Attributes;
589
+ if (a.WorkflowSid) body.WorkflowSid = a.WorkflowSid;
590
+ if (a.TaskChannel) body.TaskChannel = a.TaskChannel;
591
+ if (a.Priority !== undefined) body.Priority = a.Priority;
592
+ if (a.Timeout !== undefined) body.Timeout = a.Timeout;
593
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("POST", `https://taskrouter.twilio.com/v1/Workspaces/${a.WorkspaceSid}/Tasks`, body), null, 2) }] };
594
+ }
595
+ case "list_taskrouter_workers": {
596
+ const q = buildQuery({
597
+ ActivityName: a.ActivityName,
598
+ Available: a.Available,
599
+ TargetWorkersExpression: a.TargetWorkersExpression,
600
+ PageSize: a.PageSize,
601
+ });
602
+ return { content: [{ type: "text", text: JSON.stringify(await twilioRequest("GET", `https://taskrouter.twilio.com/v1/Workspaces/${a.WorkspaceSid}/Workers${q}`), null, 2) }] };
603
+ }
373
604
  default:
374
605
  return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
375
606
  }
@@ -392,7 +623,7 @@ async function main() {
392
623
  if (!sid && isInitializeRequest(req.body)) {
393
624
  const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
394
625
  t.onclose = () => { if (t.sessionId) transports.delete(t.sessionId); };
395
- const s = new Server({ name: "mcp-twilio", version: "0.1.0" }, { capabilities: { tools: {} } });
626
+ const s = new Server({ name: "mcp-twilio", version: "0.2.1" }, { capabilities: { tools: {} } });
396
627
  (server as unknown as { _requestHandlers: Map<unknown, unknown> })._requestHandlers.forEach((v, k) => (s as unknown as { _requestHandlers: Map<unknown, unknown> })._requestHandlers.set(k, v));
397
628
  (server as unknown as { _notificationHandlers?: Map<unknown, unknown> })._notificationHandlers?.forEach((v, k) => (s as unknown as { _notificationHandlers: Map<unknown, unknown> })._notificationHandlers.set(k, v));
398
629
  await s.connect(t);