Skip to the documentation
MCP server

Vercel AI SDK

Load the Nextmail tools into an app built with the Vercel AI SDK, through its MCP client and one sign-in.

Install

npm install ai @ai-sdk/mcp

From AI SDK 7 the MCP client lives in @ai-sdk/mcp, and ai no longer exports one. Both packages need Node.js 22 or later.

Sign in once

Terminal
npx @nextmail/cli login

Choose the browser sign-in. On the approval page, pick the workspace, the access, the addresses the AI SDK may reach and how long the approval lasts. Read only is the default, and it leaves out tools such as sendEmail, replyToEmail and createDraft, so choose Read and send when the agent should draft or reply. The sign-in is saved on this machine and listed in Account → Command line, where you can narrow it or remove it. A sign-in the bridge has not used for 7 days, or one whose approval has ended, has to sign in again.

On a server or over SSH, add --no-browser: open the link on any device, approve, and paste the code it shows back into the terminal. A browser sign-in needs a person once, so a CI job cannot make one.

The MCP server takes an approved sign-in and never an API key. A key sent to it gets 401, with a WWW-Authenticate header that points at the OAuth metadata. Code that holds a key calls the REST API or an SDK instead.

Run an agent

TypeScript
import { createMCPClient } from '@ai-sdk/mcp'import { StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio'import { generateText, isStepCount } from 'ai' const client = await createMCPClient({  transport: new StdioMCPTransport({    command: 'npx',    args: ['-y', '@nextmail/cli', 'mcp', 'serve'],  }),}) try {  const { whoAmI, listThreads, getThread } = await client.tools()  const { text } = await generateText({    model: 'openai/gpt-6-astra',    tools: { whoAmI, listThreads, getThread },    stopWhen: isStepCount(10),    prompt: 'Summarise my unread mail.',  })  console.log(text)} finally {  await client.close()}

The framework starts the local bridge, npx -y @nextmail/cli mcp serve, as a stdio MCP server. The bridge sends each call to the MCP server with your saved sign-in and renews the access token when it runs out, so the agent never handles a token. To use another profile of the command line, add --profile <name> to the arguments. The bridge runs on Node.js 20.12 or later.

  • client.tools() returns the tools by name, so taking three out of it is the filter.
  • stopWhen: isStepCount(10) lets the model call tools and read their results for up to ten steps. Without it, generateText stops after one.
  • StdioMCPTransport passes the bridge only a few environment variables, HOME and PATH among them. Put anything else it needs in env, or name a profile with --profile in args.
  • Swap the model for any the AI SDK supports.

What the agent can do

The server registers up to 600 tools, and the AI SDK sees the ones both your role and the approval allow. A tool the approval leaves out is never listed, so the model never tries it. Every tool loaded is sent to the model on each turn, so give the agent the ones its job needs. The example starts from whoAmI, listThreads and getThread.

ToolWhat it doesAccess it needs
whoAmIThe role you hold in the active workspace, and every permission it grantsNone
listThreads, getThreadList conversations with filters, and read the latest message of oneRead only
waitForEmailWait up to 60 seconds for a message that matches, such as a sign-in codeRead only
createDraftSave a draft without sending it, as a reply when given a threadRead and send
replyToEmail, sendEmailReply inside a thread, or send a new emailRead and send
modifyLabelsAdd or remove labels on conversationsRead and send

The MCP server never asks before a tool acts, so a tool that sends or deletes does it at once. A few tools make a change the REST API guards with a verification code, such as creating a rule or removing a domain, and the bridge cannot ask for a code. Run npx @nextmail/cli verify in a terminal with the same profile, or choose Allow changes for 60 minutes on this sign-in in Account → Command line, and those tools run for the next 60 minutes.

In a deployed app

Stdio is for local servers, and an app on a serverless platform cannot start the bridge. It connects to the remote server, https://api.nextmail.sh/mcp, over HTTP instead, with an authProvider: an OAuthClientProvider from @ai-sdk/mcp. The AI SDK runs discovery, registration and the code exchange, and your app supplies storage for the client and its tokens, the redirect to the approval page and the callback that finishes it. The AI SDK repository has a full example under examples/mcp.

TypeScript
const client = await createMCPClient({  transport: {    type: 'http',    url: 'https://api.nextmail.sh/mcp',    authProvider,  },})