How It Works
One action. Every transport.
Silkweave has one core idea: write your business logic once as an Action, then let adapters project it onto whatever transport an agent or human needs. No transport code leaks into your logic, and adding a new door never means rewriting the room behind it.
The three pieces
Everything in Silkweave is a composition of three concepts. Learn these and the rest of the toolkit is just adapters that follow the same contract.
- 1 Action
What your code does. A Zod
inputschema, an optionaloutput, and an asyncrun()- and nothing about transports. - 2 Adapter
The door to one transport. It takes your actions and speaks the protocol - MCP tools, REST routes, CLI flags - so your logic never has to.
- 3 Silkweave
The fluent builder that wires actions to adapters and carries every action's types forward to type-aware adapters like tRPC.
1. Action - what your code does
An Action is a named operation with a Zod input schema, an optional
output schema, and an async run(input, context) function. Actions are
deliberately transport-agnostic: they never import an HTTP framework, never read a socket, never
format an MCP result. They receive a typed context (logger, auth, request metadata)
and return plain data.
export const GreetAction = createAction({
name: 'greet',
description: 'Greet a person by name',
input: z.object({ name: z.string() }),
output: z.object({ message: z.string() }),
run: async ({ name }, { logger }) => {
logger.info('greeting', { name })
return { message: `Hello, ${name}!` }
}
}) Because the schema is Zod, one declaration drives MCP tool definitions, OpenAPI specs, tRPC procedure types, and CLI option parsing - validation and types for free, no second source of truth.
2. Adapter - the door to a transport
An Adapter translates actions into one specific transport. It takes config,
receives your actions at start(), and owns all the protocol-specific work -
registering MCP tools in PascalCase, building Fastify routes, mapping Zod types to
CLI flags. Each adapter is a separate package, so you only install the transports you actually
ship. See all seven adapters →
3. Silkweave - the fluent builder
Silkweave is the builder that wires actions to adapters:
silkweave({ name: 'my-server', version: '1.0.0' })
.adapter(stdio())
.action(GreetAction)
.start()
The builder is generic over the actions you add, so typeof server carries every
action's name and type forward. That is what lets type-aware adapters like tRPC infer a fully
typed router with zero hand-written glue.
Why decouple logic from transport?
Agents need services, and services need many doors: an MCP tool for a coding agent, a REST endpoint for a dashboard, a tRPC procedure for your own frontend, a CLI for local scripting. Built the usual way, each door is a fresh re-implementation of the same logic, drifting out of sync over time.
Silkweave collapses that to one definition and N adapters. Validation, types, auth, logging, and context are shared; only the wire format differs. Add a transport later and your existing actions light up on it for free.
Streaming actions
An action can also stream. Declare a chunk schema and make run an
async function* that yields chunks. Adapters detect this automatically and switch to
per-chunk delivery: MCP progress notifications, SSE or NDJSON over REST, or a tRPC subscription -
same action, transport-appropriate streaming. See streaming in the docs.