mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-20 20:44:17 +02:00
Merge pull request #1018 from jlowin/stateless-arg
Expose stateless_http kwarg for mcp.run()
This commit is contained in:
commit
cfd4ab7969
3 changed files with 43 additions and 6 deletions
|
|
@ -1370,6 +1370,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
path: str | None = None,
|
||||
uvicorn_config: dict[str, Any] | None = None,
|
||||
middleware: list[ASGIMiddleware] | None = None,
|
||||
stateless_http: bool | None = None,
|
||||
) -> None:
|
||||
"""Run the server using HTTP transport.
|
||||
|
||||
|
|
@ -1380,6 +1381,8 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
log_level: Log level for the server (defaults to settings.log_level)
|
||||
path: Path for the endpoint (defaults to settings.streamable_http_path or settings.sse_path)
|
||||
uvicorn_config: Additional configuration for the Uvicorn server
|
||||
middleware: A list of middleware to apply to the app
|
||||
stateless_http: Whether to use stateless HTTP (defaults to settings.stateless_http)
|
||||
"""
|
||||
|
||||
host = host or self._deprecated_settings.host
|
||||
|
|
@ -1388,7 +1391,12 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
log_level or self._deprecated_settings.log_level
|
||||
).lower()
|
||||
|
||||
app = self.http_app(path=path, transport=transport, middleware=middleware)
|
||||
app = self.http_app(
|
||||
path=path,
|
||||
transport=transport,
|
||||
middleware=middleware,
|
||||
stateless_http=stateless_http,
|
||||
)
|
||||
|
||||
# Get the path for the server URL
|
||||
server_path = (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations as _annotations
|
||||
|
||||
import inspect
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
|
|
@ -258,4 +259,21 @@ class Settings(BaseSettings):
|
|||
] = None
|
||||
|
||||
|
||||
settings = Settings()
|
||||
def __getattr__(name: str):
|
||||
"""
|
||||
Used to deprecate the module-level Image class; can be removed once it is no longer imported to root.
|
||||
"""
|
||||
if name == "settings":
|
||||
import fastmcp
|
||||
|
||||
settings = fastmcp.settings
|
||||
# Deprecated in 2.10.2
|
||||
if settings.deprecation_warnings:
|
||||
warnings.warn(
|
||||
"`from fastmcp.settings import settings` is deprecated. use `fasmtpc.settings` instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return settings
|
||||
|
||||
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import asyncio
|
|||
import json
|
||||
import sys
|
||||
from collections.abc import AsyncGenerator
|
||||
from unittest.mock import AsyncMock
|
||||
from unittest.mock import AsyncMock, call
|
||||
|
||||
import pytest
|
||||
import uvicorn
|
||||
|
|
@ -53,6 +53,7 @@ def fastmcp_server():
|
|||
async def greet_with_progress(name: str, ctx: Context) -> str:
|
||||
"""Report progress for a greeting."""
|
||||
await ctx.report_progress(0.5, 1.0, "Greeting in progress")
|
||||
await ctx.report_progress(0.75, 1.0, "Almost there!")
|
||||
return f"Hello, {name}!"
|
||||
|
||||
# Add a resource
|
||||
|
|
@ -108,8 +109,9 @@ def run_nested_server(host: str, port: int) -> None:
|
|||
|
||||
@pytest.fixture()
|
||||
async def streamable_http_server(
|
||||
stateless_http: bool = False,
|
||||
request,
|
||||
) -> AsyncGenerator[str, None]:
|
||||
stateless_http = getattr(request, "param", False)
|
||||
with run_server_in_process(
|
||||
run_server, stateless_http=stateless_http, transport="http"
|
||||
) as url:
|
||||
|
|
@ -176,16 +178,25 @@ async def test_greet_with_progress_tool(streamable_http_server: str):
|
|||
result = await client.call_tool("greet_with_progress", {"name": "Alice"})
|
||||
assert result.data == "Hello, Alice!"
|
||||
|
||||
progress_handler.assert_called_once_with(0.5, 1.0, "Greeting in progress")
|
||||
progress_handler.assert_has_calls(
|
||||
[
|
||||
call(0.5, 1.0, "Greeting in progress"),
|
||||
call(0.75, 1.0, "Almost there!"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("streamable_http_server", [True, False], indirect=True)
|
||||
async def test_elicitation_tool(streamable_http_server: str):
|
||||
async def test_elicitation_tool(streamable_http_server: str, request):
|
||||
"""Test calling the elicitation tool in both stateless and stateful modes."""
|
||||
|
||||
async def elicitation_handler(message, response_type, params, ctx):
|
||||
return {"value": "Alice"}
|
||||
|
||||
stateless_http = request.node.callspec.params.get("streamable_http_server", False)
|
||||
if stateless_http:
|
||||
pytest.xfail("Elicitation is not supported in stateless HTTP mode")
|
||||
|
||||
async with Client(
|
||||
transport=StreamableHttpTransport(streamable_http_server),
|
||||
elicitation_handler=elicitation_handler,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue