Originally published at claudeguide.io/mcp-server-typescript-bun
TypeScript MCP Server on Bun: 60ms Cold Start (2026)
A TypeScript MCP server on Bun boots in ~60ms vs ~140ms on Node.js — a 2.3x cold-start edge for hosted, on-demand servers. The official @modelcontextprotocol/sdk runs on Bun without patches: stdio for Claude Desktop, HTTP+SSE for hosted services, single-file deploys via bun build --compile. Three Bun caveats: (1) fetch keep-alive defaults differ, (2) AbortController on streams needs an explicit listener, (3) read process.stdin directly — Bun's readline shim drops the JSON-RPC framing MCP requires.
When to choose TypeScript over Python
The Python MCP guide covers FastAPI servers. Pick TypeScript on Bun when:
- Your team is full-stack TS. A Next.js shop already has Zod, tsconfig, and TS CI. Adding Python doubles the toolchain.
- You need Bun's speed. Startup beats Node by ~80 ms and Python by ~250 ms — user-visible for MCPs spawned per-conversation by Claude Desktop.
-
You want to reuse Next.js types. Share a
types/package between MCP tools and web client. No drift between OpenAPI specs and TS interfaces.
Python wins when tools wrap pandas, scikit-learn, or libraries where the Python ecosystem is materially better. Otherwise TS on Bun is the 2026 default.
Minimal stdio server
The simplest MCP server registers one tool and reads JSON-RPC over stdin/stdout. Claude Desktop spawns the process, pipes requests in, and reads responses out.
// server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new Server(
{ name: "claudeguide-demo", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
const EchoArgs = z.object({ message: z.string().min(1).max(1000) });
server.setRequestHandler("tools/list", async () =
## Streaming resources: SSE "tail logs" tool
MCP supports streaming responses via Server-Sent Events. Useful for long-running tools — log tails, build watchers, agent traces.
ts
// tail-logs-tool.ts
import { z } from "zod";
const TailArgs = z.object({
file: z.string(),
lines: z.number().int().min(1).max(10_000).default(100),
});
server.setRequestHandler("tools/call", async (req) =
Tested against @modelcontextprotocol/sdk@1.x and Bun 1.x as of May 2026. If the SDK ships a v2 with breaking changes, this article will be updated.
Top comments (0)