#
tokens: 3780/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── assets
│   └── demo.gif
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
  1 | # Logs
  2 | logs
  3 | *.log
  4 | npm-debug.log*
  5 | yarn-debug.log*
  6 | yarn-error.log*
  7 | lerna-debug.log*
  8 | .pnpm-debug.log*
  9 | 
 10 | # Diagnostic reports (https://nodejs.org/api/report.html)
 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
 12 | 
 13 | # Runtime data
 14 | pids
 15 | *.pid
 16 | *.seed
 17 | *.pid.lock
 18 | 
 19 | # Directory for instrumented libs generated by jscoverage/JSCover
 20 | lib-cov
 21 | 
 22 | # Coverage directory used by tools like istanbul
 23 | coverage
 24 | *.lcov
 25 | 
 26 | # nyc test coverage
 27 | .nyc_output
 28 | 
 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
 30 | .grunt
 31 | 
 32 | # Bower dependency directory (https://bower.io/)
 33 | bower_components
 34 | 
 35 | # node-waf configuration
 36 | .lock-wscript
 37 | 
 38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
 39 | build/Release
 40 | build/
 41 | 
 42 | # Dependency directories
 43 | node_modules/
 44 | jspm_packages/
 45 | 
 46 | # Snowpack dependency directory (https://snowpack.dev/)
 47 | web_modules/
 48 | 
 49 | # TypeScript cache
 50 | *.tsbuildinfo
 51 | 
 52 | # Optional npm cache directory
 53 | .npm
 54 | 
 55 | # Optional eslint cache
 56 | .eslintcache
 57 | 
 58 | # Optional stylelint cache
 59 | .stylelintcache
 60 | 
 61 | # Microbundle cache
 62 | .rpt2_cache/
 63 | .rts2_cache_cjs/
 64 | .rts2_cache_es/
 65 | .rts2_cache_umd/
 66 | 
 67 | # Optional REPL history
 68 | .node_repl_history
 69 | 
 70 | # Output of 'npm pack'
 71 | *.tgz
 72 | 
 73 | # Yarn Integrity file
 74 | .yarn-integrity
 75 | 
 76 | # dotenv environment variable files
 77 | .env
 78 | .env.development.local
 79 | .env.test.local
 80 | .env.production.local
 81 | .env.local
 82 | 
 83 | # parcel-bundler cache (https://parceljs.org/)
 84 | .cache
 85 | .parcel-cache
 86 | 
 87 | # Next.js build output
 88 | .next
 89 | out
 90 | 
 91 | # Nuxt.js build / generate output
 92 | .nuxt
 93 | dist
 94 | 
 95 | # Gatsby files
 96 | .cache/
 97 | # Comment in the public line in if your project uses Gatsby and not Next.js
 98 | # https://nextjs.org/blog/next-9-1#public-directory-support
 99 | # public
100 | 
101 | # vuepress build output
102 | .vuepress/dist
103 | 
104 | # vuepress v2.x temp and cache directory
105 | .temp
106 | .cache
107 | 
108 | # Docusaurus cache and generated files
109 | .docusaurus
110 | 
111 | # Serverless directories
112 | .serverless/
113 | 
114 | # FuseBox cache
115 | .fusebox/
116 | 
117 | # DynamoDB Local files
118 | .dynamodb/
119 | 
120 | # TernJS port file
121 | .tern-port
122 | 
123 | # Stores VSCode versions used for testing VSCode extensions
124 | .vscode-test
125 | 
126 | # yarn v2
127 | .yarn/cache
128 | .yarn/unplugged
129 | .yarn/build-state.yml
130 | .yarn/install-state.gz
131 | .pnp.*
132 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Twilio MCP Server
  2 | 
  3 | A Model Context Protocol (MCP) server that enables Claude and other AI assistants to send SMS and MMS messages using Twilio.
  4 | 
  5 | ## Demo
  6 | 
  7 | ![Demo](./assets/demo.gif)
  8 | 
  9 | ## Features
 10 | 
 11 | - Send SMS messages 📱
 12 | - Pre-built prompts for common messaging scenarios 📝
 13 | - Secure handling of Twilio credentials 🔒
 14 | 
 15 | ## Requirements
 16 | 
 17 | - Node.js >= 18
 18 |   - If you need to update Node.js, we recommend using `nvm` (Node Version Manager):
 19 |     ```bash
 20 |     nvm install 18.14.2
 21 |     nvm alias default 18.14.2
 22 |     ```
 23 |   - If you encounter any errors in Claude Desktop, try running the following command in your terminal to verify the installation:
 24 |     ```bash
 25 |     npx -y @yiyang.1i/sms-mcp-server
 26 |     ```
 27 | 
 28 | ## Configuration
 29 | 
 30 | The server requires three environment variables:
 31 | 
 32 | - `ACCOUNT_SID`: Your Twilio account SID
 33 | - `AUTH_TOKEN`: Your Twilio auth token
 34 | - `FROM_NUMBER`: Your Twilio phone number (in E.164 format, e.g., +11234567890)
 35 | 
 36 | ### Claude Desktop Configuration
 37 | 
 38 | To use this server with Claude Desktop, add the following to your configuration file:
 39 | 
 40 | **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
 41 | 
 42 | **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
 43 | 
 44 | ```json
 45 | {
 46 |   "mcpServers": {
 47 |     "twilio": {
 48 |       "command": "npx",
 49 |       "args": [
 50 |         "-y",
 51 |         "@yiyang.1i/sms-mcp-server"
 52 |       ],
 53 |       "env": {
 54 |         "ACCOUNT_SID": "your_account_sid",
 55 |         "AUTH_TOKEN": "your_auth_token",
 56 |         "FROM_NUMBER": "your_twilio_number"
 57 |       }
 58 |     }
 59 |   }
 60 | }
 61 | ```
 62 | After that, restart Claude Desktop to reload the configuration. 
 63 | If connected, you should see Twilio under the 🔨 menu.
 64 | 
 65 | ## Example Interactions with Claude
 66 | 
 67 | Here are some natural ways to interact with the server through Claude:
 68 | 
 69 | 1. Simple SMS:
 70 | ```
 71 | Send a text message to the number +11234567890 saying "Don't forget about dinner tonight!"
 72 | ```
 73 | 
 74 | 2. Creative SMS:
 75 | ```
 76 | Write a haiku about autumn and send it to my number +11234567890
 77 | ```
 78 | 
 79 | ## Important Notes
 80 | 
 81 | 1. **Phone Number Format**: All phone numbers must be in E.164 format (e.g., +11234567890)
 82 | 2. **Rate Limits**: Be aware of your Twilio account's rate limits and pricing
 83 | 3. **Security**: Keep your Twilio credentials secure and never commit them to version control
 84 | 
 85 | ## Troubleshooting
 86 | 
 87 | Common error messages and solutions:
 88 | 
 89 | 1. "Phone number must be in E.164 format"
 90 |    - Make sure the phone number starts with "+" and the country code
 91 | 
 92 | 2. "Invalid credentials"
 93 |    - Double-check your ACCOUNT_SID and AUTH_TOKEN. You can copy them from the [Twilio Console](https://console.twilio.com)
 94 | 
 95 | ## Contributing
 96 | 
 97 | Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
 98 | 
 99 | ## License
100 | 
101 | This project is licensed under the MIT License - see the LICENSE file for details.
102 | 
103 | ## Security
104 | 
105 | Please do not include any sensitive information (like phone numbers or Twilio credentials) in GitHub issues or pull requests.
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@yiyang.1i/sms-mcp-server",
 3 |   "version": "2025.2.24",
 4 |   "description": "A Model Context Protocol (MCP) server that enables Claude and other AI assistants to send SMS and MMS messages using Twilio.",
 5 |   "license": "MIT",
 6 |   "author": "Yiyang Li",
 7 |   "type": "module",
 8 |   "bin": {
 9 |     "sms-mcp-server": "build/index.js"
10 |   },
11 |   "files": [
12 |     "build"
13 |   ],
14 |   "scripts": {
15 |     "build": "tsc && shx chmod +x build/*.js",
16 |     "prepare": "npm run build",
17 |     "watch": "tsc --watch"
18 |   },
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "1.5.0",
21 |     "twilio": "^5.4.5",
22 |     "zod": "^3.24.2"
23 |   },
24 |   "devDependencies": {
25 |     "@types/node": "^22",
26 |     "shx": "^0.3.4",
27 |     "typescript": "^5.3.3"
28 |   }
29 | }
30 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
  3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  4 | import { z } from "zod";
  5 | import twilio from "twilio";
  6 | 
  7 | // Environment variables validation
  8 | const requiredEnvVars = ["ACCOUNT_SID", "AUTH_TOKEN", "FROM_NUMBER"];
  9 | for (const envVar of requiredEnvVars) {
 10 |   if (!process.env[envVar]) {
 11 |     console.error(`Error: ${envVar} environment variable is required`);
 12 |     process.exit(1);
 13 |   }
 14 | }
 15 | 
 16 | // Initialize Twilio client
 17 | const client = twilio(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);
 18 | 
 19 | // Create MCP server
 20 | const server = new McpServer({
 21 |     name: "twilio-sms",
 22 |     version: "1.0.0",
 23 | });
 24 | 
 25 | server.prompt(
 26 |   "send-greeting",
 27 |   {
 28 |     to: z.string().describe("Recipient's phone number in E.164 format (e.g., +11234567890)"),
 29 |     occasion: z.string().describe("The occasion for the greeting (e.g., birthday, holiday)")
 30 |   },
 31 |   ({ to, occasion }) => ({
 32 |     messages: [{
 33 |       role: "user",
 34 |       content: {
 35 |         type: "text",
 36 |         text: `Please write a warm, personalized greeting for ${occasion} and send it as a text message to ${to}. Make it engaging and friendly.`
 37 |       }
 38 |     }]
 39 |   })
 40 | );
 41 | 
 42 | server.prompt(
 43 |   "send-haiku",
 44 |   {
 45 |     theme: z.string().describe("The theme of the haiku"),
 46 |     to: z.string().describe("Recipient's phone number in E.164 format (e.g., +11234567890)")
 47 |   },
 48 |   ({ to, theme }) => ({
 49 |     messages: [{
 50 |       role: "user",
 51 |       content: {
 52 |         type: "text",
 53 |         text: `Please write a warm, personalized greeting for ${theme} and send it as a text message to ${to}. Make it engaging and friendly.`
 54 |       }
 55 |     }]
 56 |   })
 57 | );
 58 | 
 59 | 
 60 | // Add send message tool
 61 | server.tool(
 62 |   "send-message",
 63 |   "Send an SMS message via Twilio",
 64 |   {
 65 |     to: z.string().describe("Recipient phone number in E.164 format (e.g., +11234567890)"),
 66 |     message: z.string().describe("Message content to send")
 67 |   },
 68 |   async ({ to, message }) => {
 69 |     try {
 70 |       // Validate phone number format
 71 |       if (!to.startsWith("+")) {
 72 |         return {
 73 |           content: [{
 74 |             type: "text",
 75 |             text: "Error: Phone number must be in E.164 format (e.g., +11234567890)"
 76 |           }],
 77 |           isError: true
 78 |         };
 79 |       }
 80 | 
 81 |       // Send message via Twilio
 82 |       const response = await client.messages.create({
 83 |         body: message,
 84 |         from: process.env.FROM_NUMBER,
 85 |         to: to
 86 |       });
 87 | 
 88 |       return {
 89 |         content: [{
 90 |           type: "text",
 91 |           text: `Message sent successfully! Message SID: ${response.sid}`
 92 |         }]
 93 |       };
 94 |     } catch (error) {
 95 |       console.error("Error sending message:", error);
 96 |       return {
 97 |         content: [{
 98 |           type: "text",
 99 |           text: `Error sending message: ${error instanceof Error ? error.message : "Unknown error"}`
100 |         }],
101 |         isError: true
102 |       };
103 |     }
104 |   }
105 | );
106 | 
107 | // Start server
108 | async function main() {
109 |   const transport = new StdioServerTransport();
110 |   await server.connect(transport);
111 |   console.error("Twilio SMS MCP Server running on stdio");
112 | }
113 | 
114 | main().catch((error) => {
115 |   console.error("Fatal error in main():", error);
116 |   process.exit(1);
117 | });
```