Vercel AI SDK
Build a Vercel AI SDK agent that reads Gmail as the user with AgentKit: wrap Scalekit tools with tool() and jsonSchema(), or connect to a Virtual MCP server.
Build an agent using the Vercel AI SDK that reads a user’s Gmail inbox. Wrap each Scalekit tool with tool() from the ai package, and pass its JSON Schema to the model with jsonSchema().
Before you start
Section titled “Before you start”- Create a Gmail connection in AgentKit > Connections. The samples use the connection name
gmail, so change it if yours differs. See Set up a connection. - Have the
.envfile from the Quickstart, and add your OpenAI API key asOPENAI_API_KEYto it. - The samples load
.envwithimport 'dotenv/config'.
Install
Section titled “Install”npm install @scalekit-sdk/node ai@7 @ai-sdk/openai@4 dotenvFor Node.js, save the code in a .mts file, such as agent.mts, and run it with npx tsx agent.mts. The .mts extension makes the file an ES module, so it can use top-level await.
Initialize
Section titled “Initialize”import 'dotenv/config';import { ScalekitClient } from '@scalekit-sdk/node';
const scalekit = new ScalekitClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!,);Connect the user to Gmail
Section titled “Connect the user to Gmail”import { createInterface } from 'node:readline/promises';import { ConnectorStatus } from '@scalekit-sdk/node';
// Connect the user's Gmail account, and wait until it's ACTIVE before calling toolsconst connectionName = 'gmail';const identifier = 'user_123'; // your app's unique user ID
let { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ connectionName, identifier,});if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { const { link } = await scalekit.actions.getAuthorizationLink({ connectionName, identifier }); console.log('Authorize Gmail:', link); const rl = createInterface({ input: process.stdin, output: process.stdout }); await rl.question('Press Enter after authorizing...'); rl.close(); // Fetch the account again to pick up the new status ({ connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ connectionName, identifier, }));}
if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { throw new Error(`Gmail is not ACTIVE (status ${connectedAccount?.status}). Authorize it and run again.`);}See Authorize a user for production auth handling.
Run the agent
Section titled “Run the agent”Fetch the tools scoped to this user, wrap each one with the AI SDK’s tool() helper, then let generateText run the tool-calling loop. Use built-in tools explains the scoped tool list, paging past 100 tools, and how to read data when the app returns an error.
import { generateText, jsonSchema, stepCountIs, tool } from 'ai';import { openai } from '@ai-sdk/openai';
const { tools: scopedTools } = await scalekit.tools.listScopedTools('user_123', { filter: { connectionNames: ['gmail'] }, pageSize: 100, // up to 100 tools per page; page with nextPageToken for more});
// Tool definitions are typed as generic JSON, so read each field explicitlyconst definitions = scopedTools.flatMap((t) => (t.tool?.definition ? [t.tool.definition] : []));
const tools = Object.fromEntries( definitions.map((definition) => { const name = String(definition.name); const schema = definition.input_schema ?? { type: 'object', properties: {} }; return [ name, tool({ description: String(definition.description ?? ''), inputSchema: jsonSchema<Record<string, unknown>>(schema as Parameters<typeof jsonSchema>[0]), execute: async (args) => { const result = await scalekit.actions.executeTool({ toolName: name, identifier: 'user_123', connector: 'gmail', toolInput: args, }); return result.data; }, }), ]; }),);
const { text } = await generateText({ model: openai('gpt-4o'), tools, stopWhen: stepCountIs(5), prompt: 'Fetch my last 5 unread emails and summarize them',});console.log(text);Use MCP instead
Section titled “Use MCP instead”The Vercel AI SDK connects to MCP servers with createMCPClient from @ai-sdk/mcp. Pass the Virtual MCP server URL and a session token, and the client loads the server’s tools for you.
npm install @ai-sdk/mcp@2Mint the session token on your backend for each agent session with scalekit.actions.mcp.createSessionToken, as shown in Mint session tokens, and pass it to this code.
import { createMCPClient } from '@ai-sdk/mcp';import { generateText, stepCountIs } from 'ai';import { openai } from '@ai-sdk/openai';
const mcpUrl = process.env.SCALEKIT_MCP_SERVER_URL!; // mcp_server_url from your Virtual MCP serverconst mcpToken = process.env.SCALEKIT_MCP_SESSION_TOKEN!; // minted on your backend for this user
const mcpClient = await createMCPClient({ transport: { type: 'http', url: mcpUrl, headers: { Authorization: `Bearer ${mcpToken}` }, },});
const tools = await mcpClient.tools();
const { text } = await generateText({ model: openai('gpt-4o'), tools, stopWhen: stepCountIs(5), prompt: 'Fetch my last 5 unread emails and summarize them',});await mcpClient.close();console.log(text);See Create a Virtual MCP server to create the server, and Mint session tokens to check the user’s connections and mint a token.
API reference
The endpoints this page's code calls, with every field and the SDK method for each: