dendraOne procedure.
Every surface.
dendra is a typed RPC/REST framework for Next.js and TypeScript where every procedure is also an LLM tool and an MCP server. Define it once — get a typed client, REST, OpenAPI, streaming, and tools an agent can call. No codegen, no decorators.
One definition, many surfaces
A typed client, REST + OpenAPI 3.1, streaming, an in-process caller, an LLM tool, and an MCP server — all projected from a single procedure. They can’t drift.
No codegen, no decorators
The client type comes from typeof appRouter — pure inference. Nothing to generate, nothing to run, nothing to keep in sync.
AI is a byproduct
Mark a procedure .ai() and it becomes a tool the model can call — with the same input validation and the same request context as your HTTP calls.
MCP, both directions
Expose your procedures as an MCP server, and consume external MCP servers — merged into one toolset your agent (or Claude) can use.
Zero-dependency core
The core ships with no runtime dependencies. runAgent, useAssistant, and persistent memory are opt-in subpaths you add only when you want them.
Context, managed
Persistent recall and lazy tool loading (search_tools) keep a model’s window lean even when you connect big MCP connectors.
one definition, many surfaces
Your router is one object of procedures. dendra projects it into every surface — they can’t drift, because they all derive from the same spec.

define → serve → call
// server/router.ts — define once
import { initDendra, s, type RouterRecord } from 'dendra'
const { route } = initDendra<Ctx>()
export const appRouter = {
notes: {
list: route.get('/notes')
.handler(({ ctx }) => ctx.db.notes.all()),
create: route.post('/notes')
.input(s.object({ title: s.string(), body: s.string() }))
.ai({ description: 'Create a note' }) // ← also an LLM / MCP tool
.handler(({ input, ctx }) => ctx.db.notes.insert(input)),
},
} satisfies RouterRecord
export type AppRouter = typeof appRouter
// lib/api.ts — typed client, inferred, no codegen
const api = createClient<AppRouter>('', { prefix: '/rpc/' })
await api.notes.create({ title, body }) // fully typedhow dendra compares
A typed-API framework and the AI/MCP world in one layer — instead of assembling the pieces yourself.
| tRPC | MCP SDK | dendra | |
|---|---|---|---|
| Typed client, no codegen | ✓ | — | ✓ |
| REST + OpenAPI 3.1 | — | — | ✓ |
| Your API is also LLM tools | — | by hand | ✓ |
| MCP server (expose procedures) | — | ✓ | ✓ |
| Consume external MCP | — | — | ✓ |
| Context budget (memory + lazy tools) | — | — | ✓ |