Open Source TypeScript Toolkit

Define once.
Deploy everywhere.

Build MCP servers, REST APIs, and CLI tools from a single set of actions. No framework lock-in. No boilerplate. Just composition.

pnpm add @silkweave/core

Agents need services. Services need many doors.

The agentic landscape demands that services be reachable via MCP, REST, CLI, and more. Building each transport from scratch is unsustainable.

🔀

Fragmented Transports

MCP stdio, HTTP, REST, CLI - each requires a different server setup, different libraries, different patterns.

📋

Boilerplate Overload

Every new endpoint means repeating validation, error handling, and serialization. Your business logic drowns in glue code.

🔒

Framework Lock-in

Pick Express? Now you're stuck. Pick Fastify? Same story. Your actions are trapped inside your transport choice.

One action. Every transport.

Define your business logic once as an Action. Pick an Adapter. Silkweave wires them together.

Action
Zod schema + async handler
Adapter
stdio, HTTP, REST, CLI, Vercel
Silkweave
Fluent builder wires it up
actions/greet.ts
import { createAction } from '@silkweave/core'
import z from 'zod'

export const GreetAction = createAction({
  name: 'greet',
  description: 'Greet a user by name',
  input: z.object({
    name: z.string().describe('Name of the person to greet')
  }),
  run: async ({ name }) => {
    return { message: `Hello, ${name}!` }
  }
})

Same action. Seven adapters.

Swap one line to change how your action is served. The business logic stays identical.

@silkweave/mcp
import { silkweave } from '@silkweave/core'
import { stdio } from '@silkweave/mcp'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(stdio())
  .action(GreetAction)
  .start()
@silkweave/mcp
import { silkweave } from '@silkweave/core'
import { http } from '@silkweave/mcp'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(http({ port: 8080 }))
  .action(GreetAction)
  .start()
@silkweave/fastify
import { silkweave } from '@silkweave/core'
import { fastify } from '@silkweave/fastify'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(fastify({ port: 8080 }))
  .action(GreetAction)
  .start()
@silkweave/trpc
import { silkweave } from '@silkweave/core'
import { trpc, type InferTrpcRouter } from '@silkweave/trpc'
import { GreetAction } from './actions/greet.js'

const server = silkweave({ name: 'my-api', version: '1.0.0' })
  .adapter(trpc({ port: 8080 }))
  .action(GreetAction)

export type AppRouter = InferTrpcRouter<typeof server>

await server.start()
@silkweave/cli
import { silkweave } from '@silkweave/core'
import { cli } from '@silkweave/cli'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-tool', version: '1.0.0' })
  .adapter(cli())
  .action(GreetAction)
  .start()
@silkweave/vercel
import { silkweave } from '@silkweave/core'
import { vercel } from '@silkweave/vercel'
import { GreetAction } from './actions/greet.js'

const { adapter, handler } = vercel()
await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(adapter)
  .action(GreetAction)
  .start()

export default { fetch: handler }
@silkweave/typegen
import { silkweave } from '@silkweave/core'
import { typegen } from '@silkweave/typegen'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(typegen({ path: 'types/actions.d.ts' }))
  .action(GreetAction)
  .start()
// Generates: export interface GreetInput { name: string }

Everything you need. Nothing you don't.

Zod-Powered Schemas

Define inputs with Zod. Get validation, type inference, and auto-generated docs for free.

Learn more →

Built-in OAuth 2.1

Full OAuth proxy with PKCE, refresh tokens, and dynamic client registration out of the box.

Learn more →

Auto-Generated Swagger

The Fastify adapter produces OpenAPI specs and interactive Swagger UI automatically.

Learn more →

Session & Context

Fluent .set() API for per-request context. Actions receive a typed context bag - no globals.

Learn more →

Vercel Serverless

Deploy stateless MCP servers to Vercel, Cloudflare Workers, or Bun. Web Standard APIs, zero lock-in.

Learn more →

CLI with Prompts

Expose the same actions as a CLI tool with interactive prompts, powered by Commander + Clack.

Learn more →

Type Generation

Auto-generate .d.ts interfaces from your Zod schemas at build time. Zero runtime cost, full type safety.

Learn more →

Up and running in 3 steps.

1

Install

terminal
pnpm add @silkweave/core @silkweave/mcp zod
2

Define an action

actions/greet.ts
import { createAction } from '@silkweave/core'
import z from 'zod'

export const GreetAction = createAction({
  name: 'greet',
  description: 'Greet a user by name',
  input: z.object({
    name: z.string().describe('Name to greet')
  }),
  run: async ({ name }) => {
    return { message: `Hello, ${name}!` }
  }
})
3

Pick an adapter and start

server.ts
import { silkweave } from '@silkweave/core'
import { stdio } from '@silkweave/mcp'
import { GreetAction } from './actions/greet.js'

await silkweave({ name: 'my-server', version: '1.0.0' })
  .adapter(stdio())
  .action(GreetAction)
  .start()