Yak Docs
Tool Adapters

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/trpc
pnpm add @yak-io/trpc
yarn add @yak-io/trpc
bun add @yak-io/trpc

Quick 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"],
});
OptionTypeDescription
routerAnyRouterYour tRPC app router
createContext(opts?) => Promise<Context>Context factory
allowedProceduresstring[]Optional whitelist of procedures. If omitted, all procedures are allowed.
disallowedProceduresstring[]Optional blocklist of procedures. Applied after allowedProcedures.
idstringOptional 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"],
});
OptionTypeDescription
routerAnyRouterYour tRPC app router
createContext(opts?) => Promise<Context>Context factory
allowedProceduresstring[]Optional whitelist of procedures
disallowedProceduresstring[]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 available
  • disallowedProcedures – 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 createContext returns 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

On this page