On this page
You’re building a notification system. The code is in Windsurf. The API is Twilio. Testing means switching to a terminal, running curl, switching back. It doesn’t have to.
What you’ll build
A Twilio MCP server that lets Windsurf’s AI panel send test SMS messages, check message delivery status, and list recent messages. Four capabilities. Five minutes.
Prerequisites
- Windsurf (any recent version)
- Node.js 18+ or Python 3.10+
- A Twilio account with an Account SID, Auth Token, and a phone number
Install
npm install -g usepaso
Create a declaration
usepaso init --name "Twilio"
Edit usepaso.yaml:
version: "1.0"
service:
name: Twilio
description: SMS and messaging API for sending and tracking messages
base_url: https://api.twilio.com/2010-04-01
auth:
type: api_key
header: Authorization
prefix: Basic
capabilities:
- name: list_messages
description: List recent messages sent from your Twilio account
method: GET
path: /Accounts/{AccountSid}/Messages.json
permission: read
inputs:
AccountSid:
type: string
required: true
description: Your Twilio Account SID
in: path
To:
type: string
description: Filter by recipient phone number
in: query
PageSize:
type: integer
description: Number of records to return (max 100)
in: query
- name: get_message
description: Get the status and details of a specific message
method: GET
path: /Accounts/{AccountSid}/Messages/{MessageSid}.json
permission: read
inputs:
AccountSid:
type: string
required: true
in: path
MessageSid:
type: string
required: true
description: The message SID
in: path
- name: send_message
description: Send an SMS message
method: POST
path: /Accounts/{AccountSid}/Messages.json
permission: write
consent_required: true
inputs:
AccountSid:
type: string
required: true
in: path
To:
type: string
required: true
description: Recipient phone number (E.164 format, e.g. +15551234567)
in: body
From:
type: string
required: true
description: Your Twilio phone number
in: body
Body:
type: string
required: true
description: Message text
in: body
- name: delete_message
description: Delete a message record from your Twilio account
method: DELETE
path: /Accounts/{AccountSid}/Messages/{MessageSid}.json
permission: admin
consent_required: true
inputs:
AccountSid:
type: string
required: true
in: path
MessageSid:
type: string
required: true
in: path
permissions:
read:
- list_messages
- get_message
write:
- send_message
admin:
- delete_message
Note the auth setup. Twilio uses HTTP Basic auth with your Account SID as the username and Auth Token as the password, encoded in Base64. Pass the Base64-encoded AccountSid:AuthToken string as USEPASO_AUTH_TOKEN.
Set your token
Twilio Basic auth expects base64(AccountSid:AuthToken):
echo -n "ACxxxx:your_auth_token" | base64
Set the output as your token:
export USEPASO_AUTH_TOKEN=<base64_output>
Or in .env:
USEPASO_AUTH_TOKEN=<base64_output>
Validate
usepaso validate --strict
valid (Twilio, 4 capabilities, 0 regrets)
Test before connecting
usepaso test list_messages -p AccountSid=ACxxxx --dry-run
--- DRY RUN (no request will be made) ---
GET https://api.twilio.com/2010-04-01/Accounts/ACxxxx/Messages.json
Authorization: Basic ...
Run a live test to confirm auth works:
usepaso test list_messages -p AccountSid=ACxxxx
Serve
usepaso serve
usepaso serving "Twilio" (4 capabilities). Agents welcome.
Transport: stdio. Waiting for an MCP client...
Connect to Windsurf
usepaso connect windsurf
Added "Twilio" in Windsurf config.
Config: ~/.codeium/windsurf/mcp_config.json
Restart Windsurf to connect.
Restart Windsurf.
Try it
Open the Windsurf AI panel and ask:
- “Show me the last 5 messages sent to +15551234567.” Windsurf calls
list_messagesand returns the list with delivery status. - “What’s the status of message SM1234abcd?” Windsurf calls
get_messageand returns the delivery details. - “Send a test SMS to +15559876543: ‘Deploy finished.’” Windsurf shows a confirmation (because
consent_required: true), then callssend_message.
Your Twilio dashboard reflects every message. No extra tooling, no context switching.
Questions
Why is delete_message in the admin tier?
Deleting a message record is irreversible. The admin tier and consent_required: true together mean agents must get explicit confirmation before calling it. If you never want agents to delete messages, add it to permissions.forbidden instead.
Can I use this in CI to send deployment notifications?
Yes, but use usepaso serve --strict in headless environments. Strict mode enforces consent gates at the server level, so automated agents can’t skip them.
Does paso support Twilio’s Messaging Services?
The From field in send_message accepts a Messaging Service SID (MGxxxx) as well as a phone number. Twilio routes it the same way.
Related:
- Windsurf Setup. full setup guide
- Permissions and Safety. how permission tiers and consent gates work
- MCP Servers for Agents You Don’t Trust. when to use
--strict