Skip to content

Commit 04bac41

Browse files
committed
Pass AsyncOperations from FastMCP to Server
1 parent 2079230 commit 04bac41

File tree

1 file changed

+51
-2
lines changed

1 file changed

+51
-2
lines changed

src/mcp/server/fastmcp/server.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,15 @@
4545
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
4646
from mcp.server.transport_security import TransportSecuritySettings
4747
from mcp.shared.context import LifespanContextT, RequestContext, RequestT
48-
from mcp.types import NEXT_PROTOCOL_VERSION, AnyFunction, ContentBlock, GetPromptResult, ToolAnnotations
48+
from mcp.types import (
49+
NEXT_PROTOCOL_VERSION,
50+
AnyFunction,
51+
ContentBlock,
52+
GetOperationPayloadResult,
53+
GetOperationStatusResult,
54+
GetPromptResult,
55+
ToolAnnotations,
56+
)
4957
from mcp.types import Prompt as MCPPrompt
5058
from mcp.types import PromptArgument as MCPPromptArgument
5159
from mcp.types import Resource as MCPResource
@@ -170,17 +178,19 @@ def __init__(
170178
transport_security=transport_security,
171179
)
172180

181+
self._async_operations = async_operations or AsyncOperationManager()
182+
173183
self._mcp_server = MCPServer(
174184
name=name or "FastMCP",
175185
instructions=instructions,
186+
async_operations=self._async_operations,
176187
# TODO(Marcelo): It seems there's a type mismatch between the lifespan type from an FastMCP and Server.
177188
# We need to create a Lifespan type that is a generic on the server type, like Starlette does.
178189
lifespan=(lifespan_wrapper(self, self.settings.lifespan) if self.settings.lifespan else default_lifespan), # type: ignore
179190
)
180191
self._tool_manager = ToolManager(tools=tools, warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools)
181192
self._resource_manager = ResourceManager(warn_on_duplicate_resources=self.settings.warn_on_duplicate_resources)
182193
self._prompt_manager = PromptManager(warn_on_duplicate_prompts=self.settings.warn_on_duplicate_prompts)
183-
self.async_operations = async_operations or AsyncOperationManager()
184194
# Validate auth configuration
185195
if self.settings.auth is not None:
186196
if auth_server_provider and token_verifier:
@@ -270,6 +280,45 @@ def _setup_handlers(self) -> None:
270280
self._mcp_server.get_prompt()(self.get_prompt)
271281
self._mcp_server.list_resource_templates()(self.list_resource_templates)
272282

283+
# Register async operation handlers
284+
logger.info(f"Async operations manager: {self._async_operations}")
285+
logger.info("Registering async operation handlers")
286+
self._mcp_server.get_operation_status()(self.get_operation_status)
287+
self._mcp_server.get_operation_result()(self.get_operation_result)
288+
289+
async def get_operation_status(self, token: str) -> GetOperationStatusResult:
290+
"""Get the status of an async operation."""
291+
try:
292+
operation = self._async_operations.get_operation(token)
293+
if not operation:
294+
raise ValueError(f"Operation not found: {token}")
295+
296+
return GetOperationStatusResult(
297+
status=operation.status,
298+
error=operation.error if operation.status == "failed" else None,
299+
)
300+
except Exception:
301+
logger.exception(f"Error getting operation status for token {token}")
302+
raise
303+
304+
async def get_operation_result(self, token: str) -> GetOperationPayloadResult:
305+
"""Get the result of a completed async operation."""
306+
try:
307+
operation = self._async_operations.get_operation(token)
308+
if not operation:
309+
raise ValueError(f"Operation not found: {token}")
310+
311+
if operation.status != "completed":
312+
raise ValueError(f"Operation not completed: {operation.status}")
313+
314+
if not operation.result:
315+
raise ValueError("Operation completed but no result available")
316+
317+
return GetOperationPayloadResult(result=operation.result)
318+
except Exception:
319+
logger.exception(f"Error getting operation result for token {token}")
320+
raise
321+
273322
def _client_supports_async(self) -> bool:
274323
"""Check if the current client supports async tools based on protocol version."""
275324
try:

0 commit comments

Comments
 (0)