refactor(examples): migrate all HTTP examples to streamable_http_app() (#2291)
This commit is contained in:
parent
e1fd62e0f3
commit
abfb482246
2 changed files with 43 additions and 271 deletions
|
|
@ -6,9 +6,7 @@ A simple MCP server example demonstrating the StreamableHttp transport, which en
|
|||
|
||||
- Uses the StreamableHTTP transport for server-client communication
|
||||
- Supports REST API operations (POST, GET, DELETE) for `/mcp` endpoint
|
||||
- Task management with anyio task groups
|
||||
- Ability to send multiple notifications over time to the client
|
||||
- Proper resource cleanup and lifespan management
|
||||
- Resumability support via InMemoryEventStore
|
||||
|
||||
## Usage
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
import contextlib
|
||||
import logging
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
import anyio
|
||||
import click
|
||||
import uvicorn
|
||||
from mcp import types
|
||||
from mcp.server import Server, ServerRequestContext
|
||||
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
|
||||
from starlette.applications import Starlette
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
from starlette.routing import Mount
|
||||
from starlette.types import Receive, Scope, Send
|
||||
|
||||
from .event_store import InMemoryEventStore
|
||||
|
||||
|
|
@ -127,47 +122,21 @@ def main(
|
|||
# For production, use a persistent storage solution.
|
||||
event_store = InMemoryEventStore()
|
||||
|
||||
# Create the session manager with our app and event store
|
||||
session_manager = StreamableHTTPSessionManager(
|
||||
app=app,
|
||||
event_store=event_store, # Enable resumability
|
||||
starlette_app = app.streamable_http_app(
|
||||
event_store=event_store,
|
||||
json_response=json_response,
|
||||
)
|
||||
|
||||
# ASGI handler for streamable HTTP connections
|
||||
async def handle_streamable_http(scope: Scope, receive: Receive, send: Send) -> None:
|
||||
await session_manager.handle_request(scope, receive, send)
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def lifespan(app: Starlette) -> AsyncIterator[None]:
|
||||
"""Context manager for managing session manager lifecycle."""
|
||||
async with session_manager.run():
|
||||
logger.info("Application started with StreamableHTTP session manager!")
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
logger.info("Application shutting down...")
|
||||
|
||||
# Create an ASGI application using the transport
|
||||
starlette_app = Starlette(
|
||||
debug=True,
|
||||
routes=[
|
||||
Mount("/mcp", app=handle_streamable_http),
|
||||
],
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
# Wrap ASGI application with CORS middleware to expose Mcp-Session-Id header
|
||||
# for browser-based clients (ensures 500 errors get proper CORS headers)
|
||||
starlette_app = CORSMiddleware(
|
||||
starlette_app,
|
||||
allow_origins=["*"], # Allow all origins - adjust as needed for production
|
||||
allow_origins=["*"], # Note: streamable_http_app() enforces localhost-only Origin by default
|
||||
allow_methods=["GET", "POST", "DELETE"], # MCP streamable HTTP methods
|
||||
expose_headers=["Mcp-Session-Id"],
|
||||
)
|
||||
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(starlette_app, host="127.0.0.1", port=port)
|
||||
|
||||
return 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue