前言
最近MCP的概念大火,趁着这段时间的学习,打算自己着手开发一个MCP Server。作为程序员的MCP服务器,当然首先考虑这个server如何服务咱程序员了。利用端午几天时间,开发了一个简单的助力程序员提高工作效率的MCP servermcp-for-programmer。本文主要介绍HTTP Stream的连接方式
什么是MCP
Model Context Protocol (MCP) 是一种用于与AI模型交互的协议,它允许开发者定义和使用工具(tools)来扩展模型的能力。MCP服务器作为模型与工具之间的桥梁,负责处理请求、调用相应的工具,并将结果返回给模型。
MCP服务器架构
MCP服务器的核心架构包括:
- 传输层 :处理与客户端的通信,支持多种传输方式(stdio、SSE、HTTP Stream等)
- 工具注册:注册和管理可供模型调用的工具
- 提示词处理:加载和处理YAML格式的提示词模板
- 请求处理:解析请求,调用相应的工具,并返回结果
HTTP Stream
根据官方文档介绍,如果实现一个Stream连接有两种方式,With Session Management和Without Session Management。顾名思义,就是状态保持和非状态保持两种状态,这里我采用的是第一种。
- 客户端必须使用HTTP POST向MCP端点发送JSON-RPC消息
- 请求必须包含Accept头,列出application/json和text/event-stream作为支持的内容类型
- 请求体可以是单个JSON-RPC请求、通知、响应,或者是这些消息的批处理数组
- 如果输入仅包含JSON-RPC响应或通知:
- 服务器接受输入时,必须返回HTTP状态码202 Accepted,无响应体
- 服务器不接受输入时,必须返回HTTP错误状态码(如400 Bad Request)
- 如果输入包含任何JSON-RPC请求,服务器必须返回Content-Type: text/event-stream(启动SSE流)或Content-Type: application/json(返回一个JSON对象)
可恢复性与重传机制
事件ID机制
为了支持断开连接后的恢复和可能丢失的消息重传,MCP协议定义了以下机制:
- 服务器可以为SSE事件附加id字段,如SSE标准所述
- 如果存在,ID必须在该会话的所有流中全局唯一,或者在没有会话管理的情况下,在与特定客户端的所有流中全局唯一
当MCP客户端连接时,会产生一个新的session id的连接

断线重连实现
当连接断开后,客户端可以通过以下方式恢复连接:
- 客户端应该向MCP端点发起HTTP GET请求
- 请求中应包含Last-Event-ID头,指示最后接收到的事件ID
- 服务器可以使用此头部重放在断开连接的流上本应发送的消息,并从该点恢复流
- 服务器不能重放本应在不同流上传递的消息
typescript
// 从请求头获取Last-Event-ID,用于断线重连
const lastEventId = req.headers["last-event-id"] as string | undefined;
if (lastEventId) {
console.log(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
} else {
console.log(`Establishing new SSE stream for session ${sessionId}`);
}
// 重连机制由SDK实现,将请求交给传输对象处理
await activeTransport.transport.handleRequest(req, res);
return;
Last-Event-ID头部使用
Last-Event-ID头部是实现可恢复性的关键:
typescript
if (req.method === "GET" && reqUrl.pathname === endpoint) {
const sessionId = req.headers["mcp-session-id"] as string | undefined;
const activeTransport:
| {
server: McpServer;
transport: StreamableHTTPServerTransport;
}
| undefined = sessionId ? activeTransports[sessionId] : undefined;
if (!sessionId) {
res.writeHead(400).end("No sessionId");
return;
}
if (!activeTransport) {
res.writeHead(400).end("No active transport");
return;
}
const lastEventId = req.headers["last-event-id"] as string | undefined;
if (lastEventId) {
console.log(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
} else {
console.log(`Establishing new SSE stream for session ${sessionId}`);
}
//* 重连机制由SDK实现
await activeTransport.transport.handleRequest(req, res);
return;
}
会话管理
会话ID分配
通过mcp-session-id头实现会话的创建、维护和终止
MCP会话由客户端和服务器之间的逻辑相关交互组成,从初始化阶段开始:
- 使用Streamable HTTP传输的服务器可以在初始化时分配会话ID
- 会话ID通过包含在包含InitializeResult的HTTP响应的Mcp-Session-Id头中分配
- 会话ID应该是全局唯一且加密安全的(例如,安全生成的UUID、JWT或加密哈希)
- 会话ID必须仅包含可见的ASCII字符(范围从0x21到0x7E)
会话维护
会话维护的关键点:
- 如果服务器在初始化期间返回Mcp-Session-Id,使用Streamable HTTP传输的客户端必须在所有后续HTTP请求中包含它
- 需要会话ID的服务器应该对没有Mcp-Session-Id头的请求(初始化除外)响应HTTP 400 Bad Request
- 服务器可以随时终止会话,之后必须对包含该会话ID的请求响应HTTP 404 Not Found
项目简介
MCP-Server for Programmers 是一个基于 Model Context Protocol (MCP) 的服务器实现,专为帮助程序员理解和学习代码而设计。它能够通过提示词模板解析代码,提供代码解释、技术栈分析和最佳实践建议,帮助新手程序员更快地理解复杂代码。
代码地址
特性
- 🚀 基于 MCP 协议,支持多种传输方式(stdio、SSE、streamable、HTTP Stream)
- 📝 支持通过 YAML 文件定义提示词模板
- 🔧 自动将提示词转换为工具,无需手动映射
- 🧩 模板变量替换功能,支持条件渲染
- 🌐 内置 Express 服务器,提供 REST API
- 🔍 支持与 MCP Inspector 集成,方便调试
- 📋 标准化的提示词规范,确保一致性和可维护性
已完成功能
- ✅ MCP 服务器基础架构搭建
- ✅ 多种传输方式支持(stdio、SSE、streamable)
- ✅ YAML 提示词模板加载和解析
- ✅ 提示词自动转换为工具功能
- ✅ 模板变量替换和条件渲染
- ✅ Express REST API 服务
- ✅ 代码解释器提示词实现
- ✅ Rollup构建系统用于库打包
- ✅ HTTP Stream方式调用MCP服务器
- ✅ 提示词规范文档与示例
待完成功能
- 📋 管理界面更新、新增提示词
- 📋 用户界面优化与交互改进
- 📋 更多专业领域提示词模板
- 📋 代码分析与建议功能增强
- 📋 多语言支持扩展
- 📋 性能优化与缓存机制
- 📋 用户配置文件和个性化设置
- 📋 插件系统
实现效果
以我最近正在刷type challenges的场景,我常常需要AI帮我分析下代码,但是每次都需要输入一些重复的提示词,Claude或者deepseek才能输出我想要的分析。我这里将提示词以yaml的形式注册为tool,让Cursor或者cherry studio这类mcp客户端自动调用。
yaml
name: typescript-challenge-analyzer
description: 我正在刷typescript-challenge,根据我提供的ts代码段,分析这段TypeScript代码中使用的高级类型技术,提供最佳实践和使用场景示例,适合正在学习TypeScript类型系统的开发者
arguments: []
messages:
- role: user
content:
type: text
text: |
你是一位专业的TypeScript类型系统专家,擅长分析复杂的TypeScript类型挑战并提供清晰的解释和最佳实践。你的目标是帮助正在学习TypeScript的开发者理解高级类型技术。
请对这段TypeScript代码进行详细分析,我正在学习TypeScript类型系统,希望你能:
1. 解释这段代码使用了哪些TypeScript类型技术
2. 分析每个类型技术的作用和工作原理
3. 提供这些技术的最佳实践(包含示例代码)
4. 给出这些类型技术的实际使用场景(包含示例代码)
5. 如果有更优雅的实现方式,请提供改进建议
6. 根据tool的提示词思考以上几点

总结
当然,还有更多的模板可以预设,比如为开发者产出一个需求文档,或者为准备面试的程序员去发散提问的知识点等等。 欢迎大家一起学习,共同进步。github - mcp-for-programmer