@nwire/handler — alone
The operation primitive. One typed function declaration that can run on HTTP, on a queue worker, or as an MCP tool — the transport adapter decides where.
What it does
defineHandler({ name, input, handler })produces a typed operation.- The same definition can be wired through
httpInterface().wire(binding, handler)(HTTP),queueInterface().from(topic).wire(handler)(BullMQ / NATS), ormcpInterface().wire(handler)(Model Context Protocol). - No transport coupling in your handler body —
ctxis the same shape across all of them.
Install
bash
pnpm add @nwire/handler zodDeclare once
ts
import { defineHandler } from "@nwire/handler"
import { z } from "zod"
export const summarizeText = defineHandler({
name: "ai.summarize-text",
input: z.object({ text: z.string().max(50_000) }),
handler: async ({ input }) => ({
summary: await callLLM(input.text),
}),
})Mount it on HTTP
ts
import { httpInterface } from "@nwire/http"
import { mountHandler } from "@nwire/handler/http"
const api = httpInterface()
mountHandler(api, "POST /summarize", summarizeText)Mount it on a queue
ts
import { Worker } from "bullmq"
import { runHandler } from "@nwire/handler"
new Worker("summaries", async (job) => {
return runHandler(summarizeText, { input: job.data })
})Mount it as an MCP tool
ts
import { mcpServer } from "@nwire/mcp"
import { handlerAsMcpTool } from "@nwire/handler/mcp"
const server = mcpServer({ name: "ai-tools" })
server.addTool(handlerAsMcpTool(summarizeText))When to use this and not defineAction
defineAction is the L4 form — it carries persona / journeyStep / emits + binds to actors and projections. defineHandler is the L1-style operation primitive without the domain machinery. Use it when:
- You want one operation surface across HTTP + queue + MCP and your code is procedural (no actor, no event emission).
- You're building an LLM tool, an internal admin endpoint, or a wrapper around a third-party API.
If you find yourself wanting events, actors, or projections, climb to defineAction in @nwire/forge.