tRPC Adapter
The @yak-io/trpc package adapts your tRPC procedures into tools. It introspects your router to generate tool definitions and handles execution with proper context.
Installation
npm install @yak-io/trpcpnpm add @yak-io/trpcyarn add @yak-io/trpcbun add @yak-io/trpcQuick Start
The simplest way to integrate tRPC is with createTRPCToolAdapter. By default, all procedures from your router are exposed as tools:
// app/api/yak/[[...yak]]/route.ts
import { createNextYakHandler } from "@yak-io/nextjs/server";
import { createTRPCToolAdapter } from "@yak-io/trpc";
import { appRouter, createContext } from "@/server/trpc";
// All procedures are available by default
const trpcTools = createTRPCToolAdapter({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
});
export const { GET, POST } = createNextYakHandler({
tools: [trpcTools],
});Restricting procedures
Use allowedProcedures to whitelist specific procedures:
const trpcTools = createTRPCToolAdapter({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
allowedProcedures: ["orders.list", "orders.getById", "products.search"],
});Use disallowedProcedures to block specific procedures while allowing the rest:
const trpcTools = createTRPCToolAdapter({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
disallowedProcedures: ["admin.deleteUser", "billing.refund"],
});Using separate manifest and executor
For more control, you can use buildToolManifest and createTRPCToolExecutor separately:
import { createNextYakHandler } from "@yak-io/nextjs/server";
import { buildToolManifest, createTRPCToolExecutor } from "@yak-io/trpc";
import { appRouter, createContext } from "@/server/trpc";
const disallowedProcedures = [
"admin.deleteUser",
"billing.refund",
];
export const { GET, POST } = createNextYakHandler({
getTools: async () => buildToolManifest(appRouter, { disallowedProcedures }),
executeTool: createTRPCToolExecutor({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
disallowedProcedures,
}),
});API Reference
createTRPCToolAdapter
Creates a complete tool source with manifest and executor bundled:
import { createTRPCToolAdapter } from "@yak-io/trpc";
const trpcTools = createTRPCToolAdapter({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
// Optional: restrict to specific procedures
disallowedProcedures: ["admin.deleteUser"],
});| Option | Type | Description |
|---|---|---|
router | AnyRouter | Your tRPC app router |
createContext | (opts?) => Promise<Context> | Context factory |
allowedProcedures | string[] | Optional whitelist of procedures. If omitted, all procedures are allowed. |
disallowedProcedures | string[] | Optional blocklist of procedures. Applied after allowedProcedures. |
id | string | Optional source identifier (default: "trpc") |
buildToolManifest
Introspects a router and generates tool definitions:
import { buildToolManifest } from "@yak-io/trpc";
// All procedures
const tools = buildToolManifest(appRouter);
// Only specific procedures
const tools = buildToolManifest(appRouter, {
allowedProcedures: ["orders.list", "orders.getById"],
});
// All except specific procedures
const tools = buildToolManifest(appRouter, {
disallowedProcedures: ["admin.deleteUser"],
});Returns tool definitions with:
- Names from procedure paths (e.g.,
orders.list) - Descriptions from procedure metadata
- JSON schemas from Zod input validators
createTRPCToolExecutor
Creates an executor function:
import { createTRPCToolExecutor } from "@yak-io/trpc";
const executeTool = createTRPCToolExecutor({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
disallowedProcedures: ["admin.deleteUser"],
});| Option | Type | Description |
|---|---|---|
router | AnyRouter | Your tRPC app router |
createContext | (opts?) => Promise<Context> | Context factory |
allowedProcedures | string[] | Optional whitelist of procedures |
disallowedProcedures | string[] | Optional blocklist of procedures |
Procedure Filtering
By default, all procedures from your router are exposed as tools. You can restrict access using:
allowedProcedures– Whitelist approach: only specified procedures are availabledisallowedProcedures– Blocklist approach: all procedures except specified ones are available
When both options are provided, allowedProcedures is applied first, then disallowedProcedures filters the result.
// Blocklist approach (recommended for most cases)
const disallowedProcedures = [
// Block sensitive operations
"admin.deleteUser",
"billing.refund",
"system.reset",
];
// Whitelist approach (for maximum control)
const allowedProcedures = [
// Safe read operations
"orders.list",
"orders.getById",
"products.search",
// Controlled mutations
"cart.addItem",
"user.updatePreferences",
];Adding Descriptions
Help the AI understand when to use each procedure:
// server/trpc/router.ts
export const ordersRouter = router({
list: publicProcedure
.meta({ description: "List all orders for the current user" })
.query(async ({ ctx }) => {
return ctx.db.orders.findMany({ where: { userId: ctx.userId } });
}),
getById: publicProcedure
.meta({ description: "Get detailed information about a specific order" })
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {
return ctx.db.orders.findUnique({ where: { id: input.id } });
}),
});Context Handling
Use your existing createContext function:
import { createContext } from "@/server/trpc/context";
export const { GET, POST } = createNextYakHandler({
executeTool: createTRPCToolExecutor({
router: appRouter,
createContext, // Pass directly
}),
});The executor passes the incoming request to your context factory, so authentication works automatically.
Troubleshooting
Tool not appearing in manifest
- If using
allowedProcedures, verify the procedure path is in the list - If using
disallowedProcedures, ensure the procedure is not in the blocklist - Check the procedure is exported from your router
- Ensure the procedure has a Zod input schema
Context errors
- Verify
createContextreturns the expected shape - Check authentication is passed correctly
Procedure not executing
- Check server logs for validation errors
- Verify the procedure path matches exactly (case-sensitive)
- Ensure input matches the Zod schema