MCP Server StreamableHTTP 开发学习文档

MCP Server StreamableHTTP 开发学习文档

目录

  1. StreamableHTTP 简介
  2. 核心功能与架构
  3. 源码结构与关键实现详解
  4. SSE(Server-Sent Events)机制与实现
  5. 本地部署与运行方法
  6. 客户端访问与设置
  7. 总结与扩展建议

1. StreamableHTTP 简介

StreamableHTTP 是 MCP(Model Context Protocol)的一种基于 HTTP 的流式通信传输方式。它支持服务端向客户端持续推送事件(如通知、资源变更等),并支持客户端断线重连后事件流的恢复(Resumability)。

典型应用场景:

  • 实时通知推送
  • 长连接事件流
  • 需要断线重连恢复的流式服务

2. 核心功能与架构

本示例服务端具备以下核心能力:

  • 基于 StreamableHTTP 的流式通信:支持 HTTP POST/GET/DELETE 等操作,事件以流式方式推送给客户端。
  • 工具(Tool)注册与调用:通过 @app.call_tool()@app.list_tools() 装饰器注册和暴露工具。
  • 事件推送与可恢复性:通过 InMemoryEventStore 实现事件的唯一 ID 存储与回放,支持客户端断线重连。
  • 灵活的日志与响应格式:支持日志级别配置、JSON 或 SSE 响应格式切换。
  • ASGI 应用集成:基于 Starlette 框架,兼容 Uvicorn 等 ASGI 服务器。

3. 源码结构与关键实现详解

3.1 入口与参数配置

入口函数为 main,通过 click 命令行参数配置端口、日志级别、响应格式:

@click.command()
@click.option("--port", default=3000, help="Port to listen on for HTTP")
@click.option("--log-level", default="INFO", help="Logging level")
@click.option("--json-response", is_flag=True, default=False, help="Enable JSON responses instead of SSE streams")
def main(port: int, log_level: str, json_response: bool) -> int:
    # 日志配置
    logging.basicConfig(
        level=getattr(logging, log_level.upper()),
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    )
    ...

说明:

  • 通过命令行可灵活指定服务端口、日志级别、响应格式(SSE/JSON)。
  • 便于开发、调试和生产环境切换。

3.2 工具注册与调用

工具注册

通过 @app.list_tools() 注册工具元信息,定义工具名称、描述、输入参数 schema:

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="start-notification-stream",
            description="Sends a stream of notifications with configurable count and interval",
            inputSchema={
                "type": "object",
                "required": ["interval", "count", "caller"],
                "properties": {
                    "interval": {"type": "number", "description": "Interval between notifications in seconds"},
                    "count": {"type": "number", "description": "Number of notifications to send"},
                    "caller": {"type": "string", "description": "Identifier of the caller"},
                },
            },
        )
    ]
工具调用

通过 @app.call_tool() 注册工具调用逻辑,实现通知流推送:

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    ctx = app.request_context
    interval = arguments.get("interval", 1.0)
    count = arguments.get("count", 5)
    caller = arguments.get("caller", "unknown")

    for i in range(count):
        notification_msg = f"[{i+1}/{count}] Event from '{caller}' - Use Last-Event-ID to resume if disconnected"
        await ctx.session.send_log_message(
            level="info",
            data=notification_msg,
            logger="notification_stream",
            related_request_id=ctx.request_id,
        )
        if i < count - 1:
            await anyio.sleep(interval)

    await ctx.session.send_resource_updated(uri=AnyUrl("http:///test_resource"))
    return [
        types.TextContent(
            type="text",
            text=f"Sent {count} notifications with {interval}s interval for caller: {caller}",
        )
    ]

说明:

  • 工具调用时会循环推送多条通知,演示流式推送能力。
  • 每条通知都带有序号和 caller 标识,便于客户端追踪。
  • 支持通过 Last-Event-ID 机制恢复事件流。

3.3 事件存储与可恢复性

InMemoryEventStore
from .event_store import InMemoryEventStore
event_store = InMemoryEventStore()
  • 作用:为每个 SSE 事件分配唯一 ID,并存储事件内容,支持客户端断线后通过 Last-Event-ID 头部恢复未接收的事件。
  • 注意:本实现为内存存储,仅适合演示。生产环境需替换为持久化存储(如 Redis、数据库等)。

3.4 Session 管理与 ASGI 集成

Session 管理
session_manager = StreamableHTTPSessionManager(
    app=app,
    event_store=event_store,
    json_response=json_response,
)
  • StreamableHTTPSessionManager 负责管理 HTTP 流会话、事件推送、事件恢复等。
ASGI 集成
async def handle_streamable_http(scope: Scope, receive: Receive, send: Send) -> None:
    await session_manager.handle_request(scope, receive, send)

starlette_app = Starlette(
    debug=True,
    routes=[Mount("/mcp", app=handle_streamable_http)],
    lifespan=lifespan,
)
  • 通过 Starlette 框架将 /mcp 路由挂载到自定义的流式 HTTP 处理器,实现与 ASGI 服务器(如 Uvicorn)的无缝集成。

4. SSE机制与实现

SSE(Server-Sent Events)简介

  • SSE 是一种基于 HTTP 的单向服务器推送技术,客户端通过持久连接接收服务端实时推送的事件。
  • 典型应用:实时通知、进度推送、消息流等。

本示例 SSE 实现要点

  • 事件通过 send_log_messagesend_resource_updated 等方法推送。
  • 每个事件分配唯一 ID,便于客户端断线重连后通过 Last-Event-ID 头部恢复。
  • 事件存储于 InMemoryEventStore,支持事件回放。

5. 本地部署与运行方法

环境准备

  1. 安装依赖
    确保已安装 Python 3.8+,并安装相关依赖(如未提供 requirements.txt,可根据源码推断):

    pip install anyio click mcp starlette pydantic uvicorn
    
  2. 运行服务

    # 进入示例目录
    cd python-sdk/examples/servers/simple-streamablehttp
    
    # 启动服务(默认端口3000,SSE模式)
    uv run mcp-simple-streamablehttp --port 3000
    
    # 或直接用 Python 启动
    python -m mcp_simple_streamablehttp.server --port 3000
    
    • --log-level DEBUG 可开启详细日志
    • --json-response 可切换为 JSON 响应(默认 SSE)

6. 客户端访问与设置

SSE 客户端访问

  • 客户端可通过 HTTP POST/GET 方式访问 /mcp 路由,接收流式事件。
  • 推荐使用支持 SSE 的 HTTP 客户端或浏览器插件进行测试。
示例:使用 curl 订阅 SSE
curl -N -H "Accept: text/event-stream" -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"tool":"start-notification-stream","arguments":{"interval":1,"count":5,"caller":"test-client"}}'
  • -N 保持连接不断开
  • 通过 Last-Event-ID 头部可实现断线重连恢复
断线重连示例
curl -N -H "Accept: text/event-stream" -H "Last-Event-ID: <上次收到的事件ID>" \
  -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"tool":"start-notification-stream","arguments":{"interval":1,"count":5,"caller":"test-client"}}'

其他客户端

  • 推荐使用 Inspector 或自定义 Typescript/Python 客户端。
  • Typescript SDK 已内置 StreamableHTTP 客户端示例。

7. 总结与扩展建议

  • 本示例演示了 MCP StreamableHTTP 的服务端实现、工具注册、事件推送与恢复机制。
  • 适合用于需要实时推送与断线恢复的场景。
  • 扩展建议
    • 将事件存储替换为持久化方案(如 Redis、数据库等)
    • 增加多工具、多事件类型支持
    • 加强安全认证与权限控制
    • 丰富客户端示例

如需进一步深入学习 MCP 协议、StreamableHTTP 机制或客户端开发,可参考官方文档或相关开源项目。

<think>好的,用户想了解如何开发MCP服务器,特别是教程或架构设计方面的内容。首先,我需要确认用户提到的MCP服务器具体指的是什么,因为不同的领域可能有不同的缩写。不过根据提供的引用内容,这里应该是指Local MCP Server和Remote MCP Server的架构设计,可能涉及微服务、云计算或分布式系统。 接下来,我需要整理已有的信息。引用中提到MCP架构设计分为本地和远程两种,并且生态发展推动了从本地向远程架构的演进。用户需要开发教程或架构设计指导,所以应该先解释这两种架构的区别和各自的优缺点,然后分步骤说明开发过程。 用户可能是一个开发者或架构师,希望构建或迁移到MCP Server架构,因此需要明确的步骤、技术选型建议以及注意事项。考虑到系统级指令,回答需要结构清晰,分步骤说明,同时引用提供的资料,并在末尾生成相关问题。 需要确保回答符合中文要求,使用正确的LaTeX格式,比如数学表达式用$...$,独立公式用$$...$$,但根据用户的问题,可能数学公式不多,但如果有技术参数或公式的话要注意格式。同时,生成的相关问题要围绕MCP服务器开发的可能疑问,比如选型、性能优化、迁移挑战等。 现在,组织回答的结构:首先介绍两种架构,然后分步骤讲解开发过程,包括环境搭建、模块设计、通信机制等,接着提供架构设计要点,最后给出相关问题。需要引用提到的Local和Remote MCP Server的内容,并在适当的位置添加引用标识。 需要确保回答真实可靠,可能结合常见的架构设计原则,如微服务、负载均衡、容错机制等。技术栈可能涉及容器化(如Docker、Kubernetes)、API网关(如Spring Cloud Gateway)、服务发现(Consul等)。同时,注意区分本地和远程架构的不同设计考虑,比如本地可能更注重低延迟和资源优化,远程则强调扩展性和多租户支持。 最后,检查是否符合所有系统级指令:正确使用LaTeX,中文回答,生成相关问题,引用标记。确保没有使用Markdown格式,代码块用三个反引号包裹,语言标识正确。</think>MCP服务器开发可分为本地(Local)和远程(Remote)两种架构模式,以下是开发要点和架构设计指南: ### 一、MCP服务器开发基础步骤 1. **环境搭建** - 安装容器化工具:$docker$ 和 $kubernetes$ 是构建MCP服务的核心基础设施 - 配置服务发现组件:如$Consul$或$Etcd$,用于实现节点注册与发现 - 示例部署命令: ```bash kubectl create deployment mcp-server --image=your-registry/mcp-core:1.0 ``` 2. **核心模块开发** - 任务调度引擎:实现基于$DAG$(有向无环图)的任务编排 - 资源管理器:内存分配算法需满足$O(1)$时间复杂度要求 - 通信接口:遵循$gRPC$协议规范,定义proto文件: ```proto service MCPService { rpc SubmitTask(TaskRequest) returns (TaskResponse); } ``` ### 二、架构设计要点对比 | 特性 | Local MCP Server | Remote MCP Server | |--------------------|-------------------------------|-----------------------------| | 部署位置 | 与应用同主机[^1] | 独立集群部署 | | 延迟 | $\mu < 10ms$ | $\mu < 100ms$ | | 资源隔离 | 进程级隔离 | 容器/虚拟机隔离 | | 扩展性 | 垂直扩展 | 水平自动扩展 | ### 三、关键设计模式 1. **Local MCP Server架构** - 采用$sidecar$模式附着主进程 - 共享主机资源的监控策略: $$R_{alloc} = \sum_{i=1}^{n} (C_i \times t_i) + \epsilon$$ 其中$C_i$为任务资源需求,$t_i$为执行时长 2. **Remote MCP Server架构** - 实现$multi-tenant$架构设计 - 负载均衡算法建议采用改良的$WRR$(加权轮询): $$W_i = \frac{C_{curr}}{C_{max}} \times \alpha + L_{avg} \times \beta$$ ### 四、性能优化建议 1. 使用$RDMA$技术降低网络延迟 2. 采用$CQRS$模式分离读写操作 3. 实现基于$LRU-K$的缓存淘汰策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值