# Vercel AI SDK and MCPmailer

AI SDK agents load the MCPmailer tools through its MCP client and pass them to generateText.

The AI SDK ships an MCP client. Point it at MCPmailer, spread the tools into your generateText or streamText call, and the model can send mail and read replies like any other tool.

## Setup

1. **Install the MCP package** @ai-sdk/mcp carries the client; ai carries generateText.
1. **Create a mailbox** One per agent, so its address and its key are the same identity.
1. **Open the client once** Reuse it across requests. Every tools() call reaches the server.
1. **Close it when done** The transport holds a connection open until you do.

## Install

```bash
npm install ai @ai-sdk/mcp
```

## AI SDK (TypeScript)

```ts
import { createMCPClient } from '@ai-sdk/mcp';
import { generateText } from 'ai';

const mcp = await createMCPClient({
  transport: {
    type: 'http',
    url: 'https://connect.mcpmailer.com/mcp',
    headers: { Authorization: 'Bearer mmk_live_...' }
  }
});

const { text } = await generateText({
  model: 'openai/gpt-5.4',
  tools: await mcp.tools(),
  prompt: 'Email anna@customer.com her order status.'
});
```

## Answer unread mail

stopWhen lets the model take several turns: list, read, reply. Without it the SDK stops after the first tool call and nothing is sent.

```ts
import { createMCPClient } from '@ai-sdk/mcp';
import { generateText, isStepCount } from 'ai';

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

try {
  const { text } = await generateText({
    model: 'openai/gpt-5.4',
    tools: await mcp.tools(),
    stopWhen: isStepCount(8),
    system: 'You answer support email. Reply in thread, never start new ones.',
    prompt: 'Check for unread mail and answer anything you can.'
  });
  console.log(text);
} finally {
  await mcp.close();
}
```

## Worth knowing

### Give it room to finish

A reply is at least three tool calls: list_messages, read_message, reply_all. The default stops after one step, so set stopWhen or the run ends having read a message and sent nothing.

### One client, many requests

createMCPClient opens a connection. Creating one per request in a server route leaks them; open it at module scope, or close it in a finally block as above.

### Tool names come from us

The keys in tools() are our tool names, so a model prompted to "use send_email" matches what it is given. You can narrow the set by picking keys off the object before passing it.


Docs: https://mcpmailer.com/docs.md