Send SMS from the Vercel AI SDK

Give an AI SDK agent TextKit's tools so it can send texts, check delivery and manage contacts, with two packages and one transport block.

1. Get a test key

Create a test key on the API keys page of the console. It starts ssms_sk_test_, runs everything in the sandbox, and texts no real phone except your own verified one. Put it in your environment as TEXTKIT_API_KEY:

bash
export TEXTKIT_API_KEY=ssms_sk_test_...

2. Connect the MCP server

The AI SDK's MCP client lives in @ai-sdk/mcp. Point its HTTP transport at https://mcp.jointextkit.com and send your key as a header:

bash
npm install ai @ai-sdk/mcp
typescript
import { createMCPClient } from '@ai-sdk/mcp';
import { generateText, isStepCount } from 'ai';

const textkit = await createMCPClient({
  transport: {
    type: 'http',
    url: 'https://mcp.jointextkit.com',
    headers: { Authorization: `Bearer ${process.env.TEXTKIT_API_KEY}` },
  },
});

try {
  // tools() returns every TextKit tool, keyed by name. Keep the ones you need.
  const { send_message, get_message } = await textkit.tools();

  const { text } = await generateText({
    model: 'anthropic/claude-haiku-5.5',
    tools: { send_message, get_message },
    stopWhen: isStepCount(5),
    prompt: 'Text +15005550006 "Your order shipped."',
  });
  console.log(text);
} finally {
  await textkit.close();
}

Use any model the AI SDK supports. Passing all tools works too (tools: await textkit.tools()), but a short list keeps each request small and the agent focused. The server exposes 142 tools: messages, verification, numbers, contacts, segments, broadcasts, automations and account reads. Each one is a single API call with your key, so the key's scopes, rate limits and send checks apply unchanged. The full list is on the MCP server page.

3. Check the sandbox run

+15005550006 is a sandbox number that always ends delivered, so the agent's tool call returns a message with an id starting msg_ and nothing reaches a phone. The message also shows in the console's message log, tagged Test. Ask for a text to your own number instead and, once that number is verified under Settings, it really arrives (up to 10 a day, ending "- via TextKit sandbox").

Without MCP: one tool on the SDK

If your app should not depend on a second connection, wrap the TextKit SDK in an AI SDK tool. It does the same send, with the SDK's retries and idempotency keys:

bash
npm install ai zod jointextkit
typescript
import { tool } from 'ai';
import { z } from 'zod';
import { TextKit } from 'jointextkit';

const sms = new TextKit(); // reads TEXTKIT_API_KEY

export const sendText = tool({
  description: 'Send one SMS to a US or Canadian phone number.',
  inputSchema: z.object({
    to: z.string().describe('E.164, for example +14155550132'),
    body: z.string().describe('The text to send'),
  }),
  execute: async ({ to, body }) => {
    const message = await sms.messages.send({ to, body });
    return { id: message.id, status: message.status };
  },
});

Pass it as tools: { sendText }. In a route that end users reach, set to on the server from your own records (the signed-in user's verified phone) rather than letting the model choose it.

Go live

Swap the test key for a live one (ssms_sk_live_). A live text needs a number on your account: buy one and register your use case with the carriers. When the account has one number, from is optional and the text goes out from it. To limit what an agent can do with a live key, give it one with only the scopes it needs.

Sources

More in integrations