Connect: Vercel AI SDK¶
Recipe · through the TypeScript client or our MCP server · their docs checked 2026-10-30
AI SDK 7 (TypeScript). The TS client route keeps approval in Python and runs confirm tools end to end. The MCP route is one call, for tools that need no approval. There is no AI SDK for Python.
Our side¶
def public_app(tools: Registry, host: str, agent_token: str, reviewer_token: str) -> Any:
"""REST at /, MCP at /mcp, one bearer check for both: for a host on the internet."""
from mcp.server.transport_security import TransportSecuritySettings
from agent_adapter.server import create_app
tokens = {
agent_token: Principal("hosted-agent"), # the token the remote framework sends
reviewer_token: Principal("reviewer@example.com", scopes=frozenset({APPROVER_SCOPE})),
}
security = TransportSecuritySettings(allowed_hosts=[host], allowed_origins=[f"https://{host}"])
return create_app(
tools,
authenticate=bearer_auth(tokens),
host="0.0.0.0", # a public bind: the public-host checks apply
allowed_hosts=[host], # REST: any other Host header gets 421
mcp_options={"transport_security": security}, # MCP: the same rule
)
Their side: TS client (recommended)¶
import * as ai from "ai";
import { ToolClient } from "@agent-adapter/client";
const client = new ToolClient({ baseUrl: "https://tools.example.com", token: process.env.AA_AGENT_TOKEN });
const tools = await client.asVercelTools(ai.tool, ai.jsonSchema, { runId });
const result = await ai.generateText({ model, tools, prompt: "File my 2026 return." });
asVercelTools builds each tool with description, inputSchema: jsonSchema(...) and
execute. A confirm tool's execute returns { pending_approval: approval_id }. Your
reviewer screen then calls client.decide(approval_id, { approved }), which runs the call
and returns its result. Watch the run with client.events(runId).
Their side: MCP¶
import { createMCPClient } from "@ai-sdk/mcp";
const mcp = await createMCPClient({
transport: {
type: "http",
url: "https://tools.example.com/mcp",
headers: { Authorization: `Bearer ${process.env.AA_AGENT_TOKEN}` },
},
});
try {
const { send_invoice, ...tools } = await mcp.tools(); // confirm tools stay out
await ai.generateText({ model, tools, prompt: "Shipping rate to the US?" });
} finally {
await mcp.close();
}
| Key | Meaning |
|---|---|
transport.type: "http" |
Streamable HTTP |
transport.url, transport.headers |
our /mcp endpoint and the bearer token |
transport.authProvider |
OAuth; our bearer_auth takes static tokens, so use headers |
toolApproval on generateText / streamText |
AI SDK 7's approval policy (needsApproval is deprecated) |
Checklist¶
| Check | Why |
|---|---|
toolApproval is a UI gate |
it adds a step; our executor still decides confirm tools |
| confirm tools go through the TS client | over MCP the AI SDK does not send our resume keys back |
| the token stays on the server (route handler, server action) | the server sends no CORS headers, and a browser bundle leaks it |
| MCP tool annotations are hints | the AI SDK does not turn them into a policy; neither do we |
| everything on the public-host checklist |
Sources¶
- AI SDK MCP tools: https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools
- AI SDK tool approvals: https://ai-sdk.dev/docs/agents/tool-approvals
- AI SDK 7 release: https://vercel.com/changelog/ai-sdk-7
- Our TS client:
clients/typescript/README.md