Skip to content
Dashboard

Introducing MCP clients, reasoning, sources and more.

The AI SDK powers everything in Otto, from agents to structuring data to building workflows. With the AI SDK we can focus on building our product, letting us deliver updates much faster. Best of all, we don't have to worry about supporting new models when they change - the AI SDK does it for us, letting us ship updates faster.
Sully Omar

Link to headingReasoning

https://ai-sdk-reasoning.vercel.app
import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
const { text, reasoning } = await generateText({
model: anthropic('claude-3-7-sonnet-20250219'),
prompt: 'How many people will live in the world in 2040?',
});

import { generateText } from 'ai';
import { bedrock } from '@ai-sdk/amazon-bedrock';
const { text, reasoning } = await generateText({
model: bedrock('anthropic.claude-3-7-sonnet-20250219-v1:0'),
prompt: 'How many people will live in the world in 2040?',
});

Link to headingModel Context Protocol (MCP) Clients

import { experimental_createMCPClient as createMCPClient } from 'ai';
import { openai } from '@ai-sdk/openai';
const mcpClient = await createMCPClient({
transport: {
type: 'sse',
url: 'https://my-server.com/sse',
},
});
const response = await generateText({
model: openai('gpt-4o'),
tools: await mcpClient.tools(), // use MCP tools
prompt: 'Find products under $100',
});

Link to headinguseChat Message Parts

function Chat() {
const { messages } = useChat();
return (
<div>
{messages.map(message => (
message.parts.map((part, i) => {
switch (part.type) {
case "text": return <p key={i}>{part.text}</p>;
case "source": return <p key={i}>{part.source.url}</p>;
case "reasoning": return <div key={i}>{part.reasoning}</div>;
case "tool-invocation": return <div key={i}>{part.toolInvocation.toolName}</div>;
case "file": return <img key={i} src={`data:${part.mimeType};base64,${part.data}`} />;
}
})
))}
</div>
);
}

Link to headingImage Generation with Language Models

import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages } = useChat();
return (
<div>
{messages.map(message => (
<div key={message.id}>
{message.role === 'user' ? 'User: ' : 'AI: '}
{message.parts.map((part, i) => {
if (part.type === 'text') {
return <div key={i}>{part.text}</div>;
} else if (
part.type === 'file' &&
part.mimeType.startsWith('image/')
) {
return (
<img
key={i}
src={`data:${part.mimeType};base64,${part.data}`}
alt="Generated image"
/>
);
}
})}
</div>
))}
</div>
);
}

Link to headingURL sources

https://ai-sdk-sources.vercel.app
api/chat/route.ts
import { google } from "@ai-sdk/google";
import { streamText } from "ai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: google("gemini-1.5-flash", { useSearchGrounding: true }),
messages,
});
return result.toDataStreamResponse({
sendSources: true,
});
}

app/page.tsx
function Chat() {
const { messages } = useChat();
return (
<div>
{messages.map((message) => (
<div key={message.id}>
{message.role === "user" ? "User: " : "AI: "}
{message.parts
.filter((part) => part.type !== "source")
.map((part, index) => {
if (part.type === "text") {
return <div key={index}>{part.text}</div>;
}
})}
{message.parts
.filter((part) => part.type === "source")
.map((part) => (
<span key={`source-${part.source.id}`}>
[
<a href={part.source.url} target="_blank">
{part.source.title ?? new URL(part.source.url).hostname}
</a>
]
</span>
))}
</div>
))}
</div>
);
}

Link to headingOpenAI Responses API

import { openai } from '@ai-sdk/openai';
const completionsAPIModel = openai('gpt-4o-mini');
const responsesAPIModel = openai.responses('gpt-4o-mini');

import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const result = await generateText({
model: openai.responses('gpt-4o-mini'),
prompt: 'What happened in San Francisco last week?',
tools: {
web_search_preview: openai.tools.webSearchPreview(),
},
});
console.log(result.text);
console.log(result.sources);

Link to headingSvelte 5

<script>
import { Chat } from '@ai-sdk/svelte';
// Use the Chat class instead of useChat hook
const chat = new Chat();
</script>
<div>
{#each chat.messages as message}
<div class="message {message.role}">{message.content}</div>
{/each}
</div>

Link to headingMiddleware Updates

import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
import {
customProvider,
defaultSettingsMiddleware,
wrapLanguageModel,
} from "ai";
// custom provider with defaultSettingsMiddleware:
export const model = customProvider({
languageModels: {
fast: openai("gpt-4o-mini"),
writing: anthropic("claude-3-5-sonnet-latest"),
reasoning: wrapLanguageModel({
model: anthropic("claude-3-7-sonnet-20250219"),
middleware: defaultSettingsMiddleware({
settings: {
providerMetadata: {
anthropic: {
thinking: { type: "enabled", budgetTokens: 12000 },
},
},
},
}),
}),
},
});

Link to headingOther Features

Link to headingProvider Updates

Link to headingGetting started

Link to headingShowcase

Switching to the AI SDK allowed us to instantly remove a significant amount of custom code and effortlessly support all current and future AI providers. The API is super clean, thoughtfully designed, and offers first-class TypeScript support—we couldn’t be happier!
Alessio Gravili Payload

Link to headingContributors