Skip to main content
Glama

Why mcp-lite?

The official @modelcontextprotocol/sdk pulls in Express 5, ajv, jose, cors and 27+ transitive dependencies — adding ~150-200MB to your heap. If you're building on Bun + Hono, you don't need any of that.

mcp-lite extracts the exact same MCP protocol implementation from the official SDK, strips the bloat, and gives you:

  • 50% faster module load — Zod schemas lazy-loaded on first message, not at import

  • 78% less heap — 5MB vs 150-200MB

  • Zero Express — uses Hono (which you already have)

  • Zero ajv — passthrough JSON Schema validator

  • Full TypeScript types — complete .d.ts declarations for any consumer

  • 100% protocol compliant — MCP spec 2025-11-25

Comparison

@modelcontextprotocol/sdk

mcp-lite

Dependencies

Express 5, ajv, jose, cors, eventsource...

zod + hono (peer)

Heap footprint

~150-200MB

~5MB

Module load

~190ms

~93ms

Transports

stdio, SSE, Streamable HTTP

stdio, Streamable HTTP

Protocol version

2025-11-25

2025-11-25

TypeScript

Full

Full

Runtime

Node.js, Bun, Deno

Bun (optimized)

OAuth

Built-in

Not included (use Hono middleware)

Package size

~2.5MB unpacked

~50KB unpacked

Related MCP server: MCP Template

Quick Start

1. Install

bun add mcp-lite zod

2. Create a server

import { McpServer, StdioServerTransport } from "mcp-lite";
import { z } from "zod";

const server = new McpServer({
  name: "my-server",
  version: "1.0.0",
});

server.tool(
  "get_weather",
  "Get current weather for a city",
  { city: z.string().describe("City name") },
  async ({ city }) => ({
    content: [{ type: "text", text: `Weather in ${city}: Sunny, 72°F` }],
  })
);

const transport = new StdioServerTransport();
await server.connect(transport);

3. Run it

bun run my-server.ts

That's it. Your MCP server is running over stdio.

HTTP Transport (Hono)

import { McpServer, WebStandardStreamableHTTPServerTransport } from "mcp-lite";
import { Hono } from "hono";
import { z } from "zod";

const server = new McpServer({
  name: "my-server",
  version: "1.0.0",
});

server.tool(
  "search",
  "Search for items",
  { query: z.string() },
  async ({ query }) => ({
    content: [{ type: "text", text: `Results for: ${query}` }],
  })
);

const transport = new WebStandardStreamableHTTPServerTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
});

await server.connect(transport);

const app = new Hono();
app.all("/mcp", (c) => transport.handleRequest(c.req.raw));

export default app;

Performance

mcp-lite is designed for cold-start performance. Here's what happens when your server starts:

Module load:    93ms   (vs 190ms official SDK)
  types-base:    0.1ms (ErrorCode, McpError, type guards)
  protocol:     12ms   (lazy Maps, inlined isTerminal)
  server:        8ms   (lazy task helpers)
  zod:          90ms   (DEFERRED — only loads on first message)

Key optimizations:

  • Zod schemas compile on first tools/call, not at import time

  • Protocol Maps use lazy getters (7 Maps created on-demand)

  • isTerminal() inlined to eliminate experimental/tasks/interfaces.js chain

  • Type guards use duck-typing, not Zod.safeParse()

API Reference

McpServer

High-level server with declarative registration.

const server = new McpServer({
  name: "my-server",      // Required
  version: "1.0.0",       // Required
  title: "My Server",     // Optional
  description: "...",     // Optional
  instructions: "...",    // Optional
});

server.tool(name, description?, schema?, annotations?, handler)

Register a tool.

// Full signature
server.tool(
  "get_weather",
  "Get weather for a city",
  { city: z.string() },
  { readOnlyHint: true },
  async ({ city }, extra) => ({
    content: [{ type: "text", text: `Sunny in ${city}` }],
  })
);

// Shorthand (no description)
server.tool("ping", {}, async () => ({
  content: [{ type: "text", text: "pong" }],
}));

// Shorthand (no parameters)
server.tool("version", "Get version", async () => ({
  content: [{ type: "text", text: "1.0.0" }],
}));

server.resource(uri, nameOrHandler?, handler?)

Register a static resource.

server.resource("config://app", "App Config", async (uri) => ({
  contents: [{ uri, mimeType: "application/json", text: '{"key":"value"}' }],
}));

server.resourceTemplate(uriTemplate, handler)

Register a dynamic resource template.

server.resourceTemplate("users://{userId}/profile", async (uri, params) => ({
  contents: [{ uri, text: `Profile for ${params.userId}` }],
}));

server.prompt(name, description?, handler)

Register a prompt.

server.prompt("greeting", "Generate a greeting", async (args) => ({
  messages: [{
    role: "user",
    content: { type: "text", text: `Hello ${args.name}!` },
  }],
}));

Notifications

server.sendToolListChanged();
server.sendResourceListChanged();
server.sendResourceUpdated("resource://my-resource");
server.sendPromptListChanged();
server.sendLogMessage("info", "Something happened");

Server

Low-level server with direct protocol handling.

import { Server } from "mcp-lite";

const server = new Server(
  { name: "my-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler("tools/list", async () => ({
  tools: [{ name: "ping", description: "Ping pong" }],
}));

server.setRequestHandler("tools/call", async (request) => ({
  content: [{ type: "text", text: "pong" }],
}));

Transports

StdioServerTransport

import { StdioServerTransport } from "mcp-lite";

const transport = new StdioServerTransport();
await server.connect(transport);

WebStandardStreamableHTTPServerTransport

import { WebStandardStreamableHTTPServerTransport } from "mcp-lite";

const transport = new WebStandardStreamableHTTPServerTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
  enableJsonResponse: true,       // Return JSON instead of SSE
  onsessioninitialized: (id) => console.log(`Session ${id}`),
  onsessionclosed: (id) => console.log(`Closed ${id}`),
});

await server.connect(transport);

// In your Hono app
app.all("/mcp", (c) => transport.handleRequest(c.req.raw));

InMemoryTransport

For testing.

import { InMemoryTransport } from "mcp-lite";

const transport = new InMemoryTransport();
await server.connect(transport);

Error Handling

import { McpError, ErrorCode } from "mcp-lite";

throw new McpError(ErrorCode.ToolNotFound, "Tool not found: my-tool");

Type Guards

import {
  isJSONRPCRequest,
  isJSONRPCNotification,
  isJSONRPCResponse,
  isJSONRPCError,
  isInitializeRequest,
  isInitializedNotification,
  isCompletable,
} from "mcp-lite";

if (isJSONRPCRequest(message)) {
  // handle request
}

Migration from Official SDK

1. Change the import

- import { McpServer, StdioServerTransport } from "@modelcontextprotocol/sdk";
+ import { McpServer, StdioServerTransport } from "mcp-lite";

2. Remove Express dependencies

- import express from "express";
- import cors from "cors";
+ import { Hono } from "hono";

3. Update transport instantiation

- const transport = new StreamableHTTPServerTransport({
-   sessionIdGenerator: () => crypto.randomUUID(),
- });
+ const transport = new WebStandardStreamableHTTPServerTransport({
+   sessionIdGenerator: () => crypto.randomUUID(),
+ });

4. Update route handler

- app.use("/mcp", cors());
- app.all("/mcp", express.json(), (req, res) => transport.handleRequest(req, res));
+ app.all("/mcp", (c) => transport.handleRequest(c.req.raw));

5. That's it

Everything else (tool registration, resource handling, prompts) works exactly the same.

Protocol Compliance

Implements MCP spec 2025-11-25:

Feature

Status

Lifecycle (initialize, initialized, ping)

✅

Tools (tools/list, tools/call)

✅

Resources (resources/list, resources/read)

✅

Resource Templates

✅

Prompts (prompts/list, prompts/get)

✅

Completions (completion/complete)

✅

Logging (logging/setLevel)

✅

Progress notifications

✅

Cancellation

✅

Subscriptions

✅

Pagination (cursor-based)

✅

Streamable HTTP (POST/GET/DELETE)

✅

SSE streaming

✅

Session management

✅

Tool annotations

✅

Project Structure

mcp-lite/
├── src/
│   ├── index.js              # Barrel exports (from types-base.js)
│   ├── index.d.ts            # Barrel type declarations
│   ├── types-base.js         # Non-Zod exports (0ms load)
│   ├── types-base.d.ts       # Non-Zod type declarations
│   ├── types.js              # Zod schemas (lazy-loaded)
│   ├── inMemory.js           # InMemoryTransport
│   ├── server/
│   │   ├── mcp.js            # McpServer (high-level)
│   │   ├── index.js          # Server (low-level)
│   │   ├── stdio.js          # StdioServerTransport
│   │   ├── webStandardStreamableHttp.js  # HTTP transport
│   │   ├── completable.js    # Completable helper
│   │   ├── zod-compat.js     # Zod v3/v4 compatibility
│   │   └── zod-json-schema-compat.js  # Zod → JSON Schema
│   ├── shared/
│   │   ├── protocol.js       # Protocol base class
│   │   ├── transport.js      # Transport interface
│   │   └── stdio.js          # Shared stdio helpers
│   ├── validation/
│   │   ├── ajv-provider.js   # PassthroughJsonSchemaValidator
│   │   └── index.js          # Validation barrel
│   └── experimental/
│       └── tasks/            # Task-augmented execution
├── FEATURES.md               # Full feature list & limitations
├── package.json
└── tsconfig.json

Known Limitations

  • No OAuth — Use Hono middleware for auth

  • No Express transport — Use Hono (which you should be using anyway)

  • Bun optimized — Node.js may work but is not tested

  • Lazy Zod — First tools/call has ~90ms overhead while Zod loads

Contributing

Contributions are welcome! Please read our Contributing Guidelines before submitting a PR.

# Clone the repo
git clone https://github.com/srsergi0/mcp-lite.git

# Install dependencies
bun install

# Run typecheck
bun tsc --noEmit

# Run tests
bun test

Security

If you discover a security vulnerability, please report it responsibly. See SECURITY.md for details.

License

MIT © srsergi0


Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A modern, lightning-fast starter template for building Model Context Protocol applications with Bun, enabling developers to create MCP servers with TypeScript support, validation, and environment configuration.
    4 npm
    2
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    A generic template for developing MCP servers with basic examples including echo tool, server info resource, and greeting prompt. Provides a starting point for building custom MCP servers with Bun.
    6 npm
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A lightweight HTTP-based MCP server built with Bun, enabling tool discovery and execution via JSON-RPC 2.0 over HTTP.
    6 npm
    MIT