AI SDK
Turn Katman procedures into AI tools — LLMs call your API through function calling.
The Vercel AI SDK lets you connect LLMs to tools — functions the model can call when it needs data or wants to take actions. Katman can automatically convert your procedures into AI tools, extracting JSON Schema from your Zod input schemas.
This means your existing API becomes callable by AI models with zero extra code.
Prerequisites
You need a Katman router and the AI SDK:
npm install ai @ai-sdk/openai(Or any other AI SDK provider — Anthropic, Google, etc.)
Quick start
Convert your router to tools
import { } from "katman/ai"
import { } from "./router"
const = ()This creates one AI tool per procedure. Nested routers are flattened with underscores: users.list becomes users_list, admin.stats becomes admin_stats.
Use with any model
import { } from "ai"
import { } from "@ai-sdk/openai"
const { } = await ({
: ("gpt-4o"),
,
: "List all users with limit 5, then create a user named Bob",
})The model sees your procedures as callable functions. It reads the descriptions and parameter schemas, decides which tools to call, and Katman executes them.
How it works
For each procedure, Katman:
- Extracts a description from
route.descriptionorroute.summaryin your procedure definition. Falls back to"Call {name}". - Converts the Zod input schema to JSON Schema, which is the format LLMs use for function calling.
- Creates an AI SDK
toolthat executes the procedure when the model calls it.
This means your existing route metadata doubles as AI tool documentation:
const = k.query({
: z.object({ : z.number().optional() }),
: {
: "List all registered users",
: "Returns a list of users, optionally limited by count.",
},
: ({ , }) => .db.users.findMany({ : .limit }),
})The AI model sees "List all registered users" as the tool description and knows it can pass { limit: number } as input.
Single procedure
For more control, convert individual procedures instead of the whole router:
import { } from "katman/ai"
const = ("search", appRouter.search, {
: "Search the database for items matching a query",
})
const { } = await generateText({
: openai("gpt-4o"),
: { : },
: "Find all items related to TypeScript",
})The description option overrides anything from the procedure's route metadata.
Filtering procedures
You probably don't want to expose every procedure to the AI. Use the filter option to control which ones become tools:
const = routerToTools(appRouter, {
// Only expose query procedures, not mutations
: (, ) => .type === "query",
})Or filter by path:
const = routerToTools(appRouter, {
: () => !.startsWith("admin_"),
})Custom descriptions
Override descriptions for specific tools:
const = routerToTools(appRouter, {
: {
: "Get a list of all registered users. Supports a limit parameter.",
: "Create a new user account with a name and email.",
},
})These take priority over route metadata.
Good descriptions matter. LLMs decide which tool to call based on the description. Be specific about what the tool does and what parameters it accepts.
Supported input types
The Zod-to-JSON-Schema converter handles common types:
| Zod type | JSON Schema |
|---|---|
z.string() | { "type": "string" } |
z.number() | { "type": "number" } |
z.boolean() | { "type": "boolean" } |
z.object({...}) | { "type": "object", "properties": {...} } |
z.array(z.string()) | { "type": "array", "items": { "type": "string" } } |
z.enum(["a", "b"]) | { "type": "string", "enum": ["a", "b"] } |
z.optional(...) | Marked as not required |
For procedures without an input schema, the tool accepts an empty object.
What's next?
- Getting Started — set up a Katman router to convert into tools
- Procedures — add route metadata that becomes tool descriptions
- Integrations — other available integrations