流式模型上下文协议服务器

一个轻量级、流式优先、无状态的模型上下文协议服务器,适用于Node.js,支持多种编码格式和无缓冲流式传输。

  • by ZJONSSON
  • JavaScript
  • 本地部署
  • 更新于
在 GitHub 查看 zjonsson/simple-mcp

使用说明

简单mcp

Node.js的小型、流媒体优先、无状态模型上下文协议服务器。没有打字稿,完全用JsDoc打字。

状态

早期预览(v0.0.1)。API可能会发生变化。

为什么不是主流的TypeScript SDK?

  • SSE耦合使多节点部署复杂化:标准SDK维护一个内存映射,将POST与SSE流相匹配,SSE流在没有粘性会话的情况下中断。
  • 以服务器为中心的客户端状态:工具列表和其他特定于客户端的设置在服务器实例上,除非每个连接运行一个服务器,否则每个客户端的变化会很尴尬。
  • Base64响应需要完全缓冲:返回base64强制在响应之前在内存中构建整个有效载荷。
  • 不必要的大表面积:当你只需要一个紧凑的流媒体管道时,代码太多,移动部件太多。

这个图书馆是什么

  • 先流媒体:单身 Transform 您可以将JSON-RPC请求写入并从中读取响应。适用于stdio和HTTP。
  • 设计无状态:没有交通地图。每个请求都是自包含的。推送通知在协商或交给SSE时通过SSE发送 notify 钩子你可以用pub/sub回来。
  • 可更换编解码器:NDJSON、JSON和SSE编码器/解码器,无需更改服务器逻辑。
  • 无大缓冲区:响应可以嵌入节点 Readable 溪流;文本流以JSON字符串的形式流动,二进制流实时进行base64编码。

安装

npm i @zjonsson/simple-mcp

快速品尝

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也可以工作。如果客户端请求SSE,则响应对服务器发起的通知保持开放;否则,你会得到一个 notify 挂钩发布乐队外。

快速示例

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流(客户端包括 mcp-session-id 绑定到会话)。默认值 notify 发射 HttpTransport.events 使用 sessionId 作为事件名称。此路由订阅该通道并将SSE帧写入客户端。对于分布式系统,覆盖 notify 发布到您的中央发布/订阅,并让订阅者重新发布到 HttpTransport.events 使用 sessionId 作为事件名称。(服务器还将设置 mcp-session-id 初始化时的响应标头。)

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

核心理念

  • 一个抽象: Transport 扩展节点 Transform 在对象模式下。通过背压输入请求,获取响应。
  • 通过HTTP协商: Content-Type/Accept 选择JSON、NDJSON或SSE。Stdio默认为NDJSON。
  • 通知:
    • 传入 notification/* 从客户那里不会产生尸体。
    • 发送的通知在可用时发送给SSE,或发送给您的 notify 酒吧/酒吧扇出的钩子。

何时使用此

  • 你想要一个小型的、可组合的MCP服务器,它可以水平扩展,没有粘性会话。
  • 您需要在不缓冲整个响应的情况下流式传输大输出。
  • 您更喜欢标准节点流和最小表面积。