Connect Twilio to Windsurf

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_messages and returns the list with delivery status.
  • “What’s the status of message SM1234abcd?” Windsurf calls get_message and returns the delivery details.
  • “Send a test SMS to +15559876543: ‘Deploy finished.’” Windsurf shows a confirmation (because consent_required: true), then calls send_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: