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. Five transports.

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/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 }

Everything you need. Nothing you don't.

Zod-Powered Schemas

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

Built-in OAuth 2.1

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

Auto-Generated Swagger

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

Session & Context

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

Vercel Serverless

Deploy stateless MCP servers to Vercel edge functions. Zero infrastructure to manage.

CLI with Prompts

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

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()