diff --git a/pyproject.toml b/pyproject.toml index 593ddbf78f..9906523fa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "mcp>=1.24.0,<2.0", "openapi-pydantic>=0.5.1", "platformdirs>=4.0.0", - "pydocket>=0.16.3", + "pydocket>=0.16.4", "rich>=13.9.4", "cyclopts>=4.0.0", "authlib>=1.6.5", diff --git a/src/fastmcp/server/tasks/handlers.py b/src/fastmcp/server/tasks/handlers.py index 45d30d92ca..9c09090fdd 100644 --- a/src/fastmcp/server/tasks/handlers.py +++ b/src/fastmcp/server/tasks/handlers.py @@ -88,12 +88,16 @@ async def submit_to_docket( ttl_seconds = int(ttl_ms / 1000) + TASK_MAPPING_TTL_BUFFER_SECONDS # Store task metadata in Redis for protocol handlers - redis_key = f"fastmcp:task:{session_id}:{server_task_id}" - created_at_key = f"fastmcp:task:{session_id}:{server_task_id}:created_at" - poll_interval_key = f"fastmcp:task:{session_id}:{server_task_id}:poll_interval" + task_meta_key = docket.key(f"fastmcp:task:{session_id}:{server_task_id}") + created_at_key = docket.key( + f"fastmcp:task:{session_id}:{server_task_id}:created_at" + ) + poll_interval_key = docket.key( + f"fastmcp:task:{session_id}:{server_task_id}:poll_interval" + ) poll_interval_ms = int(component.task_config.poll_interval.total_seconds() * 1000) async with docket.redis() as redis: - await redis.set(redis_key, task_key, ex=ttl_seconds) + await redis.set(task_meta_key, task_key, ex=ttl_seconds) await redis.set(created_at_key, created_at.isoformat(), ex=ttl_seconds) await redis.set(poll_interval_key, str(poll_interval_ms), ex=ttl_seconds) diff --git a/src/fastmcp/server/tasks/requests.py b/src/fastmcp/server/tasks/requests.py index fa513df067..1f79a4eeb1 100644 --- a/src/fastmcp/server/tasks/requests.py +++ b/src/fastmcp/server/tasks/requests.py @@ -60,15 +60,18 @@ async def _lookup_task_execution( Raises: McpError: If task not found or execution not found """ - # Build Redis keys - redis_key = f"fastmcp:task:{session_id}:{client_task_id}" - created_at_key = f"{redis_key}:created_at" - poll_interval_key = f"{redis_key}:poll_interval" + task_meta_key = docket.key(f"fastmcp:task:{session_id}:{client_task_id}") + created_at_key = docket.key( + f"fastmcp:task:{session_id}:{client_task_id}:created_at" + ) + poll_interval_key = docket.key( + f"fastmcp:task:{session_id}:{client_task_id}:poll_interval" + ) # Fetch metadata (single round-trip with mget) async with docket.redis() as redis: task_key_bytes, created_at_bytes, poll_interval_bytes = await redis.mget( - redis_key, created_at_key, poll_interval_key + task_meta_key, created_at_key, poll_interval_key ) # Decode and validate task_key @@ -225,9 +228,9 @@ async def tasks_result_handler(server: FastMCP, params: dict[str, Any]) -> Any: ) # Look up full task key from Redis - redis_key = f"fastmcp:task:{session_id}:{client_task_id}" + task_meta_key = docket.key(f"fastmcp:task:{session_id}:{client_task_id}") async with docket.redis() as redis: - task_key_bytes = await redis.get(redis_key) + task_key_bytes = await redis.get(task_meta_key) task_key = None if task_key_bytes is None else task_key_bytes.decode("utf-8") diff --git a/src/fastmcp/server/tasks/subscriptions.py b/src/fastmcp/server/tasks/subscriptions.py index 2f07b2db87..b2c671d826 100644 --- a/src/fastmcp/server/tasks/subscriptions.py +++ b/src/fastmcp/server/tasks/subscriptions.py @@ -107,8 +107,7 @@ async def _send_status_notification( key_parts = parse_task_key(task_key) session_id = key_parts["session_id"] - # Retrieve createdAt timestamp from Redis - created_at_key = f"fastmcp:task:{session_id}:{task_id}:created_at" + created_at_key = docket.key(f"fastmcp:task:{session_id}:{task_id}:created_at") async with docket.redis() as redis: created_at_bytes = await redis.get(created_at_key) @@ -183,8 +182,7 @@ async def _send_progress_notification( key_parts = parse_task_key(task_key) session_id = key_parts["session_id"] - # Retrieve createdAt timestamp from Redis - created_at_key = f"fastmcp:task:{session_id}:{task_id}:created_at" + created_at_key = docket.key(f"fastmcp:task:{session_id}:{task_id}:created_at") async with docket.redis() as redis: created_at_bytes = await redis.get(created_at_key) diff --git a/uv.lock b/uv.lock index 092d02bdf0..f45e15ad1e 100644 --- a/uv.lock +++ b/uv.lock @@ -754,7 +754,7 @@ requires-dist = [ { name = "platformdirs", specifier = ">=4.0.0" }, { name = "py-key-value-aio", extras = ["disk", "keyring", "memory"], specifier = ">=0.3.0,<0.4.0" }, { name = "pydantic", extras = ["email"], specifier = ">=2.11.7" }, - { name = "pydocket", specifier = ">=0.16.3" }, + { name = "pydocket", specifier = ">=0.16.4" }, { name = "pyperclip", specifier = ">=1.9.0" }, { name = "python-dotenv", specifier = ">=1.1.0" }, { name = "rich", specifier = ">=13.9.4" }, @@ -1786,7 +1786,7 @@ wheels = [ [[package]] name = "pydocket" -version = "0.16.3" +version = "0.16.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cloudpickle" }, @@ -1803,9 +1803,9 @@ dependencies = [ { name = "typer" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e0/c5/61dcfce4d50b66a3f09743294d37fab598b81bb0975054b7f732da9243ec/pydocket-0.16.3.tar.gz", hash = "sha256:78e9da576de09e9f3f410d2471ef1c679b7741ddd21b586c97a13872b69bd265", size = 297080, upload-time = "2025-12-23T23:37:33.32Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/c6/eb7f3af72fa5c04b52a3f9390ff0c948987441987f9526dd992d2a6b3524/pydocket-0.16.4.tar.gz", hash = "sha256:d034d1ac75877560d86329fb3643e7b862fcbcdac407d876a62f5d9e386e8753", size = 297949, upload-time = "2026-01-08T21:58:31.637Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/94/93b7f5981aa04f922e0d9ce7326a4587866ec7e39f7c180ffcf408e66ee8/pydocket-0.16.3-py3-none-any.whl", hash = "sha256:e2b50925356e7cd535286255195458ac7bba15f25293356651b36d223db5dd7c", size = 67087, upload-time = "2025-12-23T23:37:31.829Z" }, + { url = "https://files.pythonhosted.org/packages/74/c5/e6ffed3902ead6cb906758749c42211f7f24ea6d8fdd772f531f5a81c9fa/pydocket-0.16.4-py3-none-any.whl", hash = "sha256:cdcdf74b987c2cd5d03c7353d15f8dd2ac9bd43f2a91f7441748d5a8ebd617c9", size = 67374, upload-time = "2026-01-08T21:58:30.01Z" }, ] [[package]]