npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zjonsson/simple-mcp

v0.0.1

Published

Simple MCP implementation

Readme

simple-mcp

Tiny, streaming-first, stateless Model Context Protocol server for Node.js. No typescript, fully typed with JsDoc.

Status

Early preview (v0.0.1). APIs may change.

Why not the mainstream TypeScript SDK?

  • SSE coupling complicates multi-node deployments: The standard SDK maintains an in-memory map to match POSTs to an SSE stream, which breaks without sticky sessions.
  • Server-centric client state: Tool lists and other client-specific settings live on the server instance, making per-client variation awkward unless you run one server per connection.
  • Base64 responses require full buffering: Returning base64 forces building the entire payload in memory before responding.
  • Unnecessarily large surface area: Too much code and too many moving parts when all you need is a tight streaming pipeline.

What this library is

  • Streaming-first: A single Transform you can write JSON-RPC requests into and read responses out of. Works with stdio and HTTP.
  • Stateless by design: No transport map. Each request is self-contained. Push notifications are delivered via SSE when negotiated or handed to a notify hook you can back with pub/sub.
  • Codec-swappable: NDJSON, JSON, and SSE encoders/decoders without changing server logic.
  • No large buffers: Responses can embed Node Readable streams; text streams flow as JSON strings, binary streams are base64-encoded on the fly.

Install

npm i @zjonsson/simple-mcp

Quick taste

import { SimpleMCP, StdioTransport } from '@zjonsson/simple-mcp'

const server = new SimpleMCP({
  tools: [{
    name: 'echo',
    description: 'Echo text',
    inputSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] },
    fn: async ({ text }) => ({ content: [{ type: 'text', text }] })
  }]
});

await new StdioTransport(server).connect();

HTTP works too. If the client requests SSE, the response stays open for server-initiated notifications; otherwise, you get a notify hook to publish out-of-band.

Express example

import express from 'express'
import { SimpleMCP, HttpTransport } from '@zjonsson/simple-mcp'

const app = express()

// Important: do not attach JSON body parsers to the MCP route.
// The transport reads the raw request stream.

const server = new SimpleMCP({
  tools: [{ name: 'ping', description: 'Ping', inputSchema: { type: 'object', properties: {} }, fn: async () => ({}) }]
})

// Regular MCP endpoint (request/response)
app.post('/mcp', (req, res) => {
  const transport = new HttpTransport(server)
  transport.connect(req, res)
})

app.listen(3000)

SSE stream (client includes mcp-session-id to bind to a session). The default notify emits on HttpTransport.events using the sessionId as the event name. This route subscribes to that channel and writes SSE frames to the client. For distributed systems, override notify to publish to your central pub/sub, and have subscribers re-emit to HttpTransport.events using the sessionId as the event name. (The server will also set an mcp-session-id response header upon initialize.)

app.get('/mcp/sse', (req, res) => {
  const sessionId = String(req.headers['mcp-session-id'] || '')
  if (!sessionId) return res.status(400).send('Missing mcp-session-id header')

  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache, no-transform',
    Connection: 'keep-alive'
  })

  let id = 0
  const listener = (message) => {
    res.write(`id: ${id++}\nevent: message\ndata: ${JSON.stringify(message)}\n\n`)
  }
  HttpTransport.events.on(sessionId, listener)
  req.once('close', () => HttpTransport.events.removeListener(sessionId, listener))
})

Core ideas

  • One abstraction: Transport extends Node Transform in object mode. Feed requests in, get responses out, with backpressure.
  • Negotiated over HTTP: Content-Type/Accept select JSON, NDJSON, or SSE. Stdio defaults to NDJSON.
  • Notifications:
    • Incoming notification/* from clients don’t produce a body.
    • Outgoing notifications go to SSE when available, or to your notify hook for pub/sub fanout.

When to use this

  • You want a small, composable MCP server that scales horizontally without sticky sessions.
  • You need to stream big outputs without buffering the whole response.
  • You prefer standard Node streams and minimal surface area.