Compare commits

...

2 Commits

Author SHA1 Message Date
github-actions[bot] 84106a059e bump: version 0.11.1 → 0.12.0 2025-09-11 15:02:22 +00:00
Chris Coutinho c1c5a61952 feat(server): Add support for streamable-http transport type 2025-09-11 17:01:29 +02:00
6 changed files with 32 additions and 16 deletions
+6
View File
@@ -1,3 +1,9 @@
## v0.12.0 (2025-09-11)
### Feat
- **server**: Add support for `streamable-http` transport type
## v0.11.1 (2025-09-11)
### Fix
+1 -1
View File
@@ -46,7 +46,7 @@ services:
mcp:
build: .
command: ["--host", "0.0.0.0"]
command: ["--host", "0.0.0.0", "--transport", "streamable-http"]
ports:
- 8000:8000
environment:
+13 -3
View File
@@ -2,7 +2,7 @@ import click
import logging
import uvicorn
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from contextlib import asynccontextmanager, AsyncExitStack
from dataclasses import dataclass
from starlette.applications import Starlette
@@ -83,9 +83,19 @@ def get_app(transport: str = "sse", enabled_apps: list[str] | None = None):
f"Unknown app: {app_name}. Available apps: {list(available_apps.keys())}"
)
mcp_app = mcp.sse_app() if transport == "sse" else mcp.streamable_http_app()
if transport == "sse":
mcp_app = mcp.sse_app()
lifespan = None
else:
mcp_app = mcp.streamable_http_app()
app = Starlette(routes=[Mount("/", app=mcp_app)])
@asynccontextmanager
async def lifespan(app: Starlette):
async with AsyncExitStack() as stack:
await stack.enter_async_context(mcp.session_manager.run())
yield
app = Starlette(routes=[Mount("/", app=mcp_app)], lifespan=lifespan)
return app
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "nextcloud-mcp-server"
version = "0.11.1"
version = "0.12.0"
description = ""
authors = [
{name = "Chris Coutinho",email = "chris@coutinho.io"}
+10 -10
View File
@@ -6,7 +6,7 @@ from typing import Any, AsyncGenerator
import pytest
from httpx import HTTPStatusError
from mcp import ClientSession
from mcp.client.sse import sse_client
from mcp.client.streamable_http import streamablehttp_client
from nextcloud_mcp_server.client import NextcloudClient
@@ -39,18 +39,18 @@ async def nc_client() -> AsyncGenerator[NextcloudClient, Any]:
await client.close()
@pytest.fixture
@pytest.fixture(scope="session")
async def nc_mcp_client() -> AsyncGenerator[ClientSession, Any]:
"""
Fixture to create an MCP client session for integration tests.
Fixture to create an MCP client session for integration tests using streamable-http.
"""
logger.info("Creating SSE client")
sse_context = sse_client(url="http://127.0.0.1:8000/sse")
logger.info("Creating Streamable HTTP client")
streamable_context = streamablehttp_client("http://127.0.0.1:8000/mcp")
session_context = None
try:
read, write = await sse_context.__aenter__()
session_context = ClientSession(read, write)
read_stream, write_stream, _ = await streamable_context.__aenter__()
session_context = ClientSession(read_stream, write_stream)
session = await session_context.__aenter__()
await session.initialize()
logger.info("MCP client session initialized successfully")
@@ -71,14 +71,14 @@ async def nc_mcp_client() -> AsyncGenerator[ClientSession, Any]:
logger.warning(f"Error closing session: {e}")
try:
await sse_context.__aexit__(None, None, None)
await streamable_context.__aexit__(None, None, None)
except RuntimeError as e:
if "cancel scope" in str(e):
logger.debug(f"Ignoring cancel scope teardown issue: {e}")
else:
logger.warning(f"Error closing SSE client: {e}")
logger.warning(f"Error closing streamable HTTP client: {e}")
except Exception as e:
logger.warning(f"Error closing SSE client: {e}")
logger.warning(f"Error closing streamable HTTP client: {e}")
@pytest.fixture
Generated
+1 -1
View File
@@ -506,7 +506,7 @@ wheels = [
[[package]]
name = "nextcloud-mcp-server"
version = "0.11.1"
version = "0.12.0"
source = { editable = "." }
dependencies = [
{ name = "click" },