diff --git a/docs/servers/dependency-injection.mdx b/docs/servers/dependency-injection.mdx
index c9ada083b..8d10b0ca0 100644
--- a/docs/servers/dependency-injection.mdx
+++ b/docs/servers/dependency-injection.mdx
@@ -430,4 +430,57 @@ async def call_api(endpoint: str, client: dict = Depends(get_api_client)) -> str
return f"Calling {client['base_url']}/{client['version']}/{endpoint}"
```
+### Call Arguments
+
+
+
+A dependency factory can read the arguments of the function it serves. Declare the reference with `CallArgument()`:
+
+```python
+from fastmcp import FastMCP
+from fastmcp.dependencies import CallArgument, Depends
+
+mcp = FastMCP("Call Arguments Demo")
+
+
+def get_account(user_id: str = CallArgument()) -> dict:
+ return {"id": user_id, "plan": "pro"}
+
+
+@mcp.tool
+async def show_account(user_id: str, account: dict = Depends(get_account)) -> str:
+ return f"{account['id']} is on {account['plan']}"
+```
+
+When a client calls `show_account`, the factory receives the same `user_id` value the tool receives. The bare form takes the name of the parameter it is declared on. `CallArgument("user_id")` names the parameter explicitly. The reference also sees a value that another dependency on the tool's signature produced. `CallArgument("tenant", optional=True)` yields `None` when the function has no such parameter. References that form a cycle raise `CycleError`, importable from `fastmcp.dependencies`.
+
+Clients still cannot override dependencies this way: an argument whose name collides with a dependency parameter is stripped before resolution, so a `CallArgument` reference to that parameter resolves the dependency itself.
+
+### Bindings
+
+
+
+`Depends()` accepts keyword bindings, so you can wire up a factory without changing it:
+
+```python
+from fastmcp import FastMCP
+from fastmcp.dependencies import CallArgument, Depends
+
+mcp = FastMCP("Bindings Demo")
+
+
+def get_account(user_id: str) -> dict:
+ return {"id": user_id, "plan": "pro"}
+
+
+@mcp.tool
+async def show_account(
+ owner: str,
+ account: dict = Depends(get_account, user_id=CallArgument("owner")),
+) -> str:
+ return f"{account['id']} is on {account['plan']}"
+```
+
+A binding that is a `Dependency`, such as `CallArgument(...)` or another `Depends(...)`, resolves first and the factory receives its value. Any other value passes through as it is. A binding replaces the default of the factory's own parameter, which is then never resolved. Two dependencies on the same factory share one cached result only when their bindings match. See the [Docket dependency documentation](https://docket.lol/en/latest/dependency-injection/) for more detail on call arguments and bindings.
+
For advanced dependency patterns—like `TaskArgument()` for accessing task parameters, or custom `Dependency` subclasses—see the [Docket dependency documentation](https://chrisguidry.github.io/docket/dependencies/).
diff --git a/fastmcp_slim/fastmcp/dependencies.py b/fastmcp_slim/fastmcp/dependencies.py
index 138486f88..2f0ac00eb 100644
--- a/fastmcp_slim/fastmcp/dependencies.py
+++ b/fastmcp_slim/fastmcp/dependencies.py
@@ -11,7 +11,7 @@ using the uncalled-for DI engine. The docket-specific dependencies
from typing import Any
-from uncalled_for import Dependency, Depends, Shared
+from uncalled_for import CallArgument, CycleError, Dependency, Depends, Shared
from fastmcp.server.dependencies import (
CurrentAccessToken,
@@ -25,11 +25,13 @@ from fastmcp.server.dependencies import (
)
__all__ = [
+ "CallArgument",
"CurrentAccessToken",
"CurrentContext",
"CurrentFastMCP",
"CurrentHeaders",
"CurrentRequest",
+ "CycleError",
"Dependency",
"Depends",
"Progress",
diff --git a/fastmcp_slim/fastmcp/server/dependencies.py b/fastmcp_slim/fastmcp/server/dependencies.py
index 32d8ba183..a6f06778b 100644
--- a/fastmcp_slim/fastmcp/server/dependencies.py
+++ b/fastmcp_slim/fastmcp/server/dependencies.py
@@ -30,7 +30,12 @@ from mcp.server.context import ServerRequestContext
from mcp.server.session import ServerSession
from packaging.version import Version
from starlette.requests import Request
-from uncalled_for import Dependency, get_dependency_parameters
+from uncalled_for import (
+ CycleError,
+ Dependency,
+ frame_scope,
+ get_dependency_parameters,
+)
from uncalled_for.resolution import _Depends
from fastmcp.exceptions import FastMCPError
@@ -751,11 +756,12 @@ def without_injected_parameters(
async def _resolve_fastmcp_dependencies(
fn: Callable[..., Any], arguments: dict[str, Any]
) -> AsyncGenerator[dict[str, Any], None]:
- """Resolve Docket dependencies for a FastMCP function.
+ """Resolve uncalled-for dependencies for a FastMCP function.
- Sets up the minimal context needed for Docket's Depends() to work:
+ Sets up the context that uncalled-for's Depends() needs:
- A cache for resolved dependencies
- An AsyncExitStack for managing context manager lifetimes
+ - A resolution frame, so CallArgument() can read the call's arguments
The Docket instance (for CurrentDocket dependency) is managed separately
by the server's lifespan and made available via ContextVar.
@@ -783,33 +789,35 @@ async def _resolve_fastmcp_dependencies(
async with AsyncExitStack() as stack:
stack_token = _Depends.stack.set(stack)
try:
- resolved: dict[str, Any] = {}
+ # The frame memoizes each parameter per call, so a
+ # CallArgument() that references a sibling dependency gets
+ # the same value the function receives for it.
+ with frame_scope(fn, arguments) as frame:
+ resolved: dict[str, Any] = {}
- for parameter, dependency in dependency_params.items():
- # If argument was explicitly provided, use that instead
- if parameter in arguments:
- resolved[parameter] = arguments[parameter]
- continue
+ for parameter in dependency_params:
+ # Resolve the dependency. The frame returns an
+ # explicitly provided argument as-is.
+ try:
+ resolved[parameter] = await frame.resolve(parameter)
+ except (FastMCPError, CycleError):
+ # Let FastMCPError subclasses (ToolError,
+ # ResourceError, etc.) propagate unchanged so they
+ # can be handled appropriately. CycleError already
+ # names the cyclic reference path, so wrapping it
+ # would only hide that.
+ raise
+ except Exception as error:
+ fn_name = getattr(fn, "__name__", repr(fn))
+ raise RuntimeError(
+ f"Failed to resolve dependency '{parameter}' "
+ f"for {fn_name}"
+ ) from error
- # Resolve the dependency
- try:
- resolved[parameter] = await stack.enter_async_context(
- dependency
- )
- except FastMCPError:
- # Let FastMCPError subclasses (ToolError, ResourceError, etc.)
- # propagate unchanged so they can be handled appropriately
- raise
- except Exception as error:
- fn_name = getattr(fn, "__name__", repr(fn))
- raise RuntimeError(
- f"Failed to resolve dependency '{parameter}' for {fn_name}"
- ) from error
+ # Merge resolved dependencies with provided arguments
+ final_arguments = {**arguments, **resolved}
- # Merge resolved dependencies with provided arguments
- final_arguments = {**arguments, **resolved}
-
- yield final_arguments
+ yield final_arguments
finally:
_Depends.stack.reset(stack_token)
finally:
@@ -828,6 +836,9 @@ async def resolve_dependencies(
The filtering prevents external callers from overriding injected parameters by
providing values for dependency parameter names. This is a security feature.
+ The filtered arguments also feed the resolution frame, so a CallArgument()
+ reference to a dependency parameter resolves the dependency and never a
+ caller-supplied value.
Note: Context injection is handled via transform_context_annotations() which
converts `ctx: Context` to `ctx: Context = Depends(get_context)` at registration
diff --git a/fastmcp_slim/pyproject.toml b/fastmcp_slim/pyproject.toml
index 6d56f3e93..ea6b7b6ac 100644
--- a/fastmcp_slim/pyproject.toml
+++ b/fastmcp_slim/pyproject.toml
@@ -103,7 +103,7 @@ server = [
"pyperclip>=1.9.0",
"python-multipart>=0.0.26",
"pyyaml>=6.0,<7.0",
- "uncalled-for>=0.2.0",
+ "uncalled-for>=0.4.0",
"uvicorn>=0.35",
"watchfiles>=1.0.0",
"websockets>=15.0.1",
diff --git a/fastmcp_tasks/pyproject.toml b/fastmcp_tasks/pyproject.toml
index 6a1de018f..04353f8b3 100644
--- a/fastmcp_tasks/pyproject.toml
+++ b/fastmcp_tasks/pyproject.toml
@@ -56,16 +56,13 @@ dependencies = [
# Fernet and the PBKDF2 key derivation behind FASTMCP_TASKS_ENCRYPTION_KEY,
# which encrypts task context snapshots at rest.
"cryptography>=43.0.0",
- "pydocket>=0.20.0",
- # burner-redis 0.1.7's Windows build crashes the interpreter (native fault,
- # no Python traceback) running the memory:// backend under pytest-xdist —
- # reproduced on GitHub Actions windows-latest, confirmed absent on
- # macOS/Linux with the same versions (full suite green there under the
- # identical upgraded dependencies). pydocket only floors it at >=0.1.6, so
- # capping pydocket alone is not enough: a resolver is free to pick the
- # newest burner-redis satisfying that floor regardless. Pin burner-redis
- # directly on Windows only (which in turn caps pydocket to <0.20.2 there,
- # the last release that doesn't itself require burner-redis>=0.1.7) until
- # upstream ships a fix — other platforms are unaffected and stay unpinned.
- "burner-redis<0.1.7; sys_platform == 'win32'",
+ # pydocket 0.24.1 resolves CallArgument references through uncalled-for's
+ # call-scoped frames and shuts its worker down reliably when run_forever
+ # is cancelled on Python 3.10 and 3.11, which our lifespan does on every
+ # server shutdown. Without that fix a worker cancelled during teardown
+ # hangs; on Windows, pytest-timeout's hard kill of the hung xdist worker
+ # was misread as a burner-redis 0.1.7 interpreter crash, which is why a
+ # burner-redis pin and a platform-split floor used to live here
+ # (prefectlabs/burner-redis#7 has the exoneration).
+ "pydocket>=0.24.1",
]
diff --git a/pyproject.toml b/pyproject.toml
index 27b3596b0..f1badb7c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -73,10 +73,11 @@ members = ["fastmcp_slim", "fastmcp_remote", "fastmcp_tasks"]
default-groups = ["dev"]
exclude-newer = "1 week"
# The cooldown above refuses anything published in the last week. Exempt the
-# first-party packages, whose fresh releases we install deliberately, and the
+# first-party packages, whose fresh releases we install deliberately, the
# MCP SDK, where a new major is the only version satisfying our floor and so
-# has nothing older to fall back to.
-exclude-newer-package = { fastmcp = false, fastmcp-slim = false, fastmcp-remote = false, prefab-ui = false, mcp = false, mcp-types = false }
+# has nothing older to fall back to, and uncalled-for, the DI engine whose
+# releases we adopt deliberately.
+exclude-newer-package = { fastmcp = false, fastmcp-slim = false, fastmcp-remote = false, prefab-ui = false, mcp = false, mcp-types = false, uncalled-for = false, pydocket = false }
[dependency-groups]
dev = [
diff --git a/tests/server/test_call_arguments.py b/tests/server/test_call_arguments.py
new file mode 100644
index 000000000..6b1af08cb
--- /dev/null
+++ b/tests/server/test_call_arguments.py
@@ -0,0 +1,189 @@
+"""Tests for CallArgument and Depends bindings through FastMCP's resolution."""
+
+import pytest
+from mcp_types import TextContent
+
+from fastmcp import FastMCP
+from fastmcp.dependencies import CallArgument, CycleError, Depends
+from fastmcp.server.dependencies import resolve_dependencies
+
+
+@pytest.fixture
+def mcp():
+ """Create a FastMCP server for testing."""
+ return FastMCP("test-server")
+
+
+async def test_bare_call_argument_reads_tool_parameter(mcp: FastMCP):
+ """A bare CallArgument takes the value of the same-named tool parameter."""
+
+ def get_greeting(name: str = CallArgument()) -> str:
+ return f"Hello, {name}!"
+
+ @mcp.tool()
+ async def greet(name: str, greeting: str = Depends(get_greeting)) -> str:
+ return greeting
+
+ result = await mcp.call_tool("greet", {"name": "Alice"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "Hello, Alice!"
+
+
+async def test_named_call_argument_reads_tool_parameter(mcp: FastMCP):
+ """CallArgument("name") reads a tool parameter with a different name."""
+
+ def get_greeting(who: str = CallArgument("name")) -> str:
+ return f"Hello, {who}!"
+
+ @mcp.tool()
+ async def greet(name: str, greeting: str = Depends(get_greeting)) -> str:
+ return greeting
+
+ result = await mcp.call_tool("greet", {"name": "Bob"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "Hello, Bob!"
+
+
+async def test_call_argument_in_binding(mcp: FastMCP):
+ """A CallArgument binding wires a tool parameter to a factory parameter."""
+
+ def get_account(user_id: str) -> dict[str, str]:
+ return {"id": user_id, "plan": "pro"}
+
+ @mcp.tool()
+ async def show_account(
+ owner: str,
+ account: dict[str, str] = Depends(get_account, user_id=CallArgument("owner")),
+ ) -> str:
+ return f"{account['id']}:{account['plan']}"
+
+ result = await mcp.call_tool("show_account", {"owner": "alice"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "alice:pro"
+
+
+async def test_plain_value_binding(mcp: FastMCP):
+ """A binding that is not a Dependency passes through to the factory as-is."""
+
+ def get_url(scheme: str) -> str:
+ return f"{scheme}://example.com"
+
+ @mcp.tool()
+ async def fetch(path: str, url: str = Depends(get_url, scheme="https")) -> str:
+ return f"{url}/{path}"
+
+ result = await mcp.call_tool("fetch", {"path": "docs"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "https://example.com/docs"
+
+
+async def test_binding_replaces_factory_depends_default(mcp: FastMCP):
+ """A binding replaces the factory's own Depends default, which never runs."""
+
+ default_calls = 0
+
+ def get_default_region() -> str:
+ nonlocal default_calls
+ default_calls += 1
+ return "us-east-1"
+
+ def get_bucket(region: str = Depends(get_default_region)) -> str:
+ return f"bucket-{region}"
+
+ @mcp.tool()
+ async def store(
+ data: str, bucket: str = Depends(get_bucket, region="eu-west-1")
+ ) -> str:
+ return bucket
+
+ result = await mcp.call_tool("store", {"data": "payload"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "bucket-eu-west-1"
+ assert default_calls == 0
+
+
+async def test_optional_call_argument_yields_none(mcp: FastMCP):
+ """CallArgument(optional=True) yields None for a name the tool lacks."""
+
+ def get_note(tenant: str | None = CallArgument("tenant", optional=True)) -> str:
+ return f"tenant={tenant}"
+
+ @mcp.tool()
+ async def report(topic: str, note: str = Depends(get_note)) -> str:
+ return note
+
+ result = await mcp.call_tool("report", {"topic": "sales"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "tenant=None"
+
+
+async def test_sibling_dependency_resolves_once(mcp: FastMCP):
+ """A CallArgument reference to a dependency-backed sibling shares one value."""
+
+ session_calls = 0
+
+ def get_session() -> str:
+ nonlocal session_calls
+ session_calls += 1
+ return "session-1"
+
+ def audit(session: str = CallArgument()) -> str:
+ return f"audit:{session}"
+
+ @mcp.tool()
+ async def act(
+ step: str,
+ session: str = Depends(get_session),
+ log: str = Depends(audit),
+ ) -> str:
+ return f"{log}|{session}"
+
+ result = await mcp.call_tool("act", {"step": "one"})
+ assert result.structured_content is not None
+ assert result.structured_content["result"] == "audit:session-1|session-1"
+ assert session_calls == 1
+
+
+async def test_call_argument_cycle_raises_cycle_error():
+ """CallArgument references that form a cycle raise CycleError with the path."""
+
+ def get_a(b: str = CallArgument()) -> str:
+ return b
+
+ def get_b(a: str = CallArgument()) -> str:
+ return a
+
+ async def entangled(a: str = Depends(get_a), b: str = Depends(get_b)) -> str:
+ return f"{a}{b}"
+
+ with pytest.raises(CycleError, match="a -> b -> a"):
+ async with resolve_dependencies(entangled, {}):
+ pass
+
+
+async def test_colliding_argument_never_reaches_call_argument(mcp: FastMCP):
+ """A caller-supplied value for a dependency parameter name is stripped.
+
+ A CallArgument that references the dependency parameter resolves the
+ dependency itself, never the caller's value.
+ """
+
+ def get_role() -> str:
+ return "user"
+
+ def describe(role: str = CallArgument()) -> str:
+ return f"role={role}"
+
+ @mcp.prompt()
+ async def status(
+ topic: str,
+ role: str = Depends(get_role),
+ summary: str = Depends(describe),
+ ) -> str:
+ return f"{topic}: {summary}"
+
+ result = await mcp.render_prompt("status", {"topic": "audit", "role": "admin"})
+ content = result.messages[0].content
+ assert isinstance(content, TextContent)
+ assert "role=user" in content.text
+ assert "admin" not in content.text
diff --git a/uv.lock b/uv.lock
index a3d4ce109..c12f61615 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,20 +2,26 @@ version = 1
revision = 3
requires-python = ">=3.10"
resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version == '3.13.*'",
- "python_full_version >= '3.11' and python_full_version < '3.13'",
- "python_full_version < '3.11'",
+ "python_full_version >= '3.14' and sys_platform == 'win32'",
+ "python_full_version >= '3.14' and sys_platform != 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'win32'",
+ "python_full_version == '3.13.*' and sys_platform != 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'win32'",
+ "python_full_version < '3.11' and sys_platform == 'win32'",
+ "python_full_version < '3.11' and sys_platform != 'win32'",
]
[options]
-exclude-newer = "2026-07-21T14:39:05.08339Z"
+exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values.
exclude-newer-span = "P1W"
[options.exclude-newer-package]
mcp-types = false
-fastmcp = false
prefab-ui = false
+pydocket = false
+uncalled-for = false
+fastmcp = false
mcp = false
fastmcp-remote = false
fastmcp-slim = false
@@ -33,10 +39,11 @@ name = "aiofile"
version = "3.9.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version < '3.11'",
+ "python_full_version < '3.11' and sys_platform == 'win32'",
+ "python_full_version < '3.11' and sys_platform != 'win32'",
]
dependencies = [
- { name = "caio", marker = "python_full_version < '3.11'" },
+ { name = "caio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/67/e2/d7cb819de8df6b5c1968a2756c3cb4122d4fa2b8fc768b53b7c9e5edb646/aiofile-3.9.0.tar.gz", hash = "sha256:e5ad718bb148b265b6df1b3752c4d1d83024b93da9bd599df74b9d9ffcf7919b", size = 17943, upload-time = "2024-10-08T10:39:35.846Z" }
wheels = [
@@ -48,12 +55,15 @@ name = "aiofile"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version == '3.13.*'",
- "python_full_version >= '3.11' and python_full_version < '3.13'",
+ "python_full_version >= '3.14' and sys_platform == 'win32'",
+ "python_full_version >= '3.14' and sys_platform != 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'win32'",
+ "python_full_version == '3.13.*' and sys_platform != 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'win32'",
]
dependencies = [
- { name = "caio", marker = "python_full_version >= '3.11'" },
+ { name = "caio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/48/41/2fea7e193e061ce54eacc3b7bc0e6a99e4fcff43c78cf0a76dd781ed8334/aiofile-3.11.1.tar.gz", hash = "sha256:1f91912c6643d2a4e49ca4ae3514f0bf3867ce948a36d99a6411b8f4755f4cf9", size = 19342, upload-time = "2026-05-16T08:18:33.538Z" }
wheels = [
@@ -253,18 +263,18 @@ wheels = [
[[package]]
name = "burner-redis"
-version = "0.1.6"
+version = "0.1.7"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/c8/6f/ec3eeb9e3e9d7fedc51fcb56dd09da0f164495ab6fdf4caaa3754ceed659/burner_redis-0.1.6.tar.gz", hash = "sha256:362091d98c09953ef99be8bd026d75fad42599a0f153211e1a22d3e3029c7cfb", size = 843118, upload-time = "2026-04-27T17:11:41.879Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/89/54706febafc135095b2a9d797cfbd4eed2ab1ad7819808b99b587020471b/burner_redis-0.1.7.tar.gz", hash = "sha256:7474ff092669fd11ef765411572cdafcc3d89b8054aef4ca0617be6d6be4c680", size = 638644, upload-time = "2026-05-08T15:01:42.961Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d6/cc/061897380b88c637e4bea1f6715ffba851d10b16d6610f2832ab61fa15b5/burner_redis-0.1.6-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:5dc9c170b9994b8d57958041857f240d1b0b9ac1559d0d35473f03fb62386dea", size = 1275400, upload-time = "2026-04-27T17:11:27.07Z" },
- { url = "https://files.pythonhosted.org/packages/db/24/e4c6fb37d059b268c2a26b173d3f84b49547e837340983d3d018c08191c6/burner_redis-0.1.6-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f29caae7f80fea2e47350df24264a049aeaa934454210cddcadc2336ee8b423a", size = 1223570, upload-time = "2026-04-27T17:11:28.782Z" },
- { url = "https://files.pythonhosted.org/packages/2e/be/718af7f42bbebbfbfd771ba43697526c922dff54d1b0d62654e21418b25e/burner_redis-0.1.6-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ce82edea4ed1ec34448a8610c62665517b3d2030254f31af32828b070a92a8", size = 1325624, upload-time = "2026-04-27T17:11:30.648Z" },
- { url = "https://files.pythonhosted.org/packages/06/8a/4f72de7f967532d3739caa461625dc9122f0ca0d46faa883c153a10d0117/burner_redis-0.1.6-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e3dff7d691ab0035468c17f51632e452b075065a30e026278ed1b297441ce93", size = 1356531, upload-time = "2026-04-27T17:11:32.201Z" },
- { url = "https://files.pythonhosted.org/packages/bd/22/369338d6372abd12dee51965566428c06f3badd95f668ff1c11680b99b30/burner_redis-0.1.6-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3b43f983b6e8fbc208734f04b0bae8cf95323fc43105f977d20f0993fc28c1b3", size = 1526049, upload-time = "2026-04-27T17:11:33.93Z" },
- { url = "https://files.pythonhosted.org/packages/b3/23/0651cf86bc5ed390fef09e30ff4a4664cc3c5b88ddf4c6b8d905acc0d60e/burner_redis-0.1.6-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b6ba097d910effff00a4610160a4a759503ad590e2c47a580bdcdac9a325823", size = 1579068, upload-time = "2026-04-27T17:11:35.964Z" },
- { url = "https://files.pythonhosted.org/packages/a0/8c/302638fdad4476d4760d477b0f3c6b96c0f88d3f278e5f14d06eb048f788/burner_redis-0.1.6-cp310-abi3-win_amd64.whl", hash = "sha256:98c6b6fc397617cd5a6778ac020e4ed9985c393ad204f9f5cf524b68ae16070b", size = 1103735, upload-time = "2026-04-27T17:11:38.38Z" },
- { url = "https://files.pythonhosted.org/packages/c0/ba/18668d92e18210150f7f93e2930264ad77a82e4d3e5f74ca1aecc002f78f/burner_redis-0.1.6-cp310-abi3-win_arm64.whl", hash = "sha256:c2583e98f9a3836ac2c6243ea0c8d56b40e7017b46617991e329bc807c544bad", size = 1029386, upload-time = "2026-04-27T17:11:40.266Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/5d/198bd1d22e504b3034353430703afbdb3efe6e25cb90bf52d896e1d266a7/burner_redis-0.1.7-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f80c866996e0455d584eb3c0f3b067e411c632fb0519eab454e0968edf01e62c", size = 1288888, upload-time = "2026-05-08T15:01:26.103Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/4e/ce5c91b884ac37fcd380756402536f8810964014097950900517ce8bd30c/burner_redis-0.1.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a3d9569a376b690fb5876d454e4904443332dc3ad5c0057e149fc2ad220bf599", size = 1234282, upload-time = "2026-05-08T15:01:28.286Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/c0/31c25cc88143eac2dddcc394151a0db627923d44c94376a83768552c9f13/burner_redis-0.1.7-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20eba1917e3bca9eea5957d5700ff8defcb5a209e57a7841d005549aa0151f44", size = 1337341, upload-time = "2026-05-08T15:01:30.397Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/32/95cfa1833316ca2b6b2e58150a4900bc1ad256043cdd36198f1887618ccc/burner_redis-0.1.7-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39111467059b8a28f15ea061d2414ec25c3e57c65759983f90f4d358e7d6a72d", size = 1366800, upload-time = "2026-05-08T15:01:32.891Z" },
+ { url = "https://files.pythonhosted.org/packages/34/ad/93c3916f053f89b7b5760da5bf855cd78b7885d480f9cfcc64f3732c1dc2/burner_redis-0.1.7-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9b5adfe99aeb8407f468078f3769b2a63e9168fea12f7709df5d2a3b152706e4", size = 1538160, upload-time = "2026-05-08T15:01:34.667Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/b9/19bae42cb124932d71168bc8e5bcb1da33aa62b908e5e632b3d298d7cb15/burner_redis-0.1.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:591a9d20685f9d6d22bf0c863b50b12dfcf328b06111b3f62c33cd3185d48ce0", size = 1591491, upload-time = "2026-05-08T15:01:36.708Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/30/207f47f406619a5b564355d2946c3171f84231a28b800709b5645b06a5ae/burner_redis-0.1.7-cp310-abi3-win_amd64.whl", hash = "sha256:f6cf4ac666766b32fd63940aad0c120847905fd3102c17e5b6b305f91a21d079", size = 1117564, upload-time = "2026-05-08T15:01:39.221Z" },
+ { url = "https://files.pythonhosted.org/packages/76/6f/e9beaf46c5e9fd10dfcdb889ebf7d3aa85142c650c0ab17ab284194f58e1/burner_redis-0.1.7-cp310-abi3-win_arm64.whl", hash = "sha256:458f88feeddfb40a586cc3fcbd8e9384bbdfd2a4512a695af4900e06052570d4", size = 1040407, upload-time = "2026-05-08T15:01:41.235Z" },
]
[[package]]
@@ -1077,7 +1087,7 @@ requires-dist = [
{ name = "starlette", marker = "extra == 'mcp'", specifier = ">=1.0.1" },
{ name = "starlette", marker = "extra == 'server'", specifier = ">=1.0.1" },
{ name = "typing-extensions", specifier = ">=4.0.0" },
- { name = "uncalled-for", marker = "extra == 'server'", specifier = ">=0.2.0" },
+ { name = "uncalled-for", marker = "extra == 'server'", specifier = ">=0.4.0" },
{ name = "uvicorn", marker = "extra == 'server'", specifier = ">=0.35" },
{ name = "watchfiles", marker = "extra == 'server'", specifier = ">=1.0.0" },
{ name = "websockets", marker = "extra == 'server'", specifier = ">=15.0.1" },
@@ -1088,7 +1098,6 @@ provides-extras = ["anthropic", "apps", "azure", "client", "code-mode", "gemini"
name = "fastmcp-tasks"
source = { editable = "fastmcp_tasks" }
dependencies = [
- { name = "burner-redis", marker = "sys_platform == 'win32'" },
{ name = "cryptography" },
{ name = "fastmcp-slim", extra = ["server"] },
{ name = "pydocket" },
@@ -1096,10 +1105,9 @@ dependencies = [
[package.metadata]
requires-dist = [
- { name = "burner-redis", marker = "sys_platform == 'win32'", specifier = "<0.1.7" },
{ name = "cryptography", specifier = ">=43.0.0" },
{ name = "fastmcp-slim", extras = ["server"], editable = "fastmcp_slim" },
- { name = "pydocket", specifier = ">=0.20.0" },
+ { name = "pydocket", specifier = ">=0.24.1" },
]
[[package]]
@@ -1303,7 +1311,7 @@ name = "importlib-metadata"
version = "9.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "zipp", marker = "python_full_version < '3.13'" },
+ { name = "zipp" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
wheels = [
@@ -1346,20 +1354,21 @@ name = "ipython"
version = "8.39.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version < '3.11'",
+ "python_full_version < '3.11' and sys_platform == 'win32'",
+ "python_full_version < '3.11' and sys_platform != 'win32'",
]
dependencies = [
- { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" },
- { name = "decorator", marker = "python_full_version < '3.11'" },
- { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
- { name = "jedi", marker = "python_full_version < '3.11'" },
- { name = "matplotlib-inline", marker = "python_full_version < '3.11'" },
- { name = "pexpect", marker = "python_full_version < '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
- { name = "prompt-toolkit", marker = "python_full_version < '3.11'" },
- { name = "pygments", marker = "python_full_version < '3.11'" },
- { name = "stack-data", marker = "python_full_version < '3.11'" },
- { name = "traitlets", marker = "python_full_version < '3.11'" },
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "decorator" },
+ { name = "exceptiongroup" },
+ { name = "jedi" },
+ { name = "matplotlib-inline" },
+ { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit" },
+ { name = "pygments" },
+ { name = "stack-data" },
+ { name = "traitlets" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/40/18/f8598d287006885e7136451fdea0755af4ebcbfe342836f24deefaed1164/ipython-8.39.0.tar.gz", hash = "sha256:4110ae96012c379b8b6db898a07e186c40a2a1ef5d57a7fa83166047d9da7624", size = 5513971, upload-time = "2026-03-27T10:02:13.94Z" }
wheels = [
@@ -1371,23 +1380,26 @@ name = "ipython"
version = "9.15.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version == '3.13.*'",
- "python_full_version >= '3.11' and python_full_version < '3.13'",
+ "python_full_version >= '3.14' and sys_platform == 'win32'",
+ "python_full_version >= '3.14' and sys_platform != 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'win32'",
+ "python_full_version == '3.13.*' and sys_platform != 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'win32'",
]
dependencies = [
- { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" },
- { name = "decorator", marker = "python_full_version >= '3.11'" },
- { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" },
- { name = "jedi", marker = "python_full_version >= '3.11'" },
- { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" },
- { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
- { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" },
- { name = "psutil", marker = "python_full_version >= '3.11' and sys_platform != 'cygwin' and sys_platform != 'emscripten'" },
- { name = "pygments", marker = "python_full_version >= '3.11'" },
- { name = "stack-data", marker = "python_full_version >= '3.11'" },
- { name = "traitlets", marker = "python_full_version >= '3.11'" },
- { name = "typing-extensions", marker = "python_full_version == '3.11.*'" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "decorator" },
+ { name = "ipython-pygments-lexers" },
+ { name = "jedi" },
+ { name = "matplotlib-inline" },
+ { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit" },
+ { name = "psutil", marker = "sys_platform != 'cygwin' and sys_platform != 'emscripten'" },
+ { name = "pygments" },
+ { name = "stack-data" },
+ { name = "traitlets" },
+ { name = "typing-extensions", marker = "python_full_version < '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/53/59/165d3b4d75cc34add3122c4417ecb229085140ac573103c223cd01dde96f/ipython-9.15.0.tar.gz", hash = "sha256:da2819ce2aa83135257df830660b1176d986c3d2876db24df01974fa955b2756", size = 4442580, upload-time = "2026-06-26T11:03:35.913Z" }
wheels = [
@@ -1399,7 +1411,7 @@ name = "ipython-pygments-lexers"
version = "1.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pygments", marker = "python_full_version >= '3.11'" },
+ { name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
wheels = [
@@ -2367,7 +2379,7 @@ wheels = [
[[package]]
name = "pydocket"
-version = "0.20.1"
+version = "0.24.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "burner-redis" },
@@ -2386,9 +2398,9 @@ dependencies = [
{ name = "tzdata", marker = "sys_platform == 'win32'" },
{ name = "uncalled-for" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/72/bf/7f1134e990855f373e5ee6ba316db8fe654a2d7dd852b41ab890fcfb91e3/pydocket-0.20.1.tar.gz", hash = "sha256:d72b3784e4b5069b39e5f49f599d54a891e1b6222c27a8bcfbd4dee0f57d4895", size = 361993, upload-time = "2026-05-06T14:06:25.956Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b7/6b/a87c6e3fd197807f630af4270aa2ce8f4c1fca4e43bba783f273d298d646/pydocket-0.24.1.tar.gz", hash = "sha256:477d77be1fcfd10ee0c2d0b8aa8c6e97851b9c7f39bb6f2b4e6d42e9b4d6e95a", size = 430759, upload-time = "2026-08-10T19:50:03.368Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9d/9d/1bd873a0ea480dec388c40ac1a7500c129efbb9d61e2fef6b97236703458/pydocket-0.20.1-py3-none-any.whl", hash = "sha256:c886ece90ac93018f069d1eef9443f888404081d7258955e16847752575c95ae", size = 102774, upload-time = "2026-05-06T14:06:24.548Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/05/4e3b902bc0ca407188aa5fe38af49be634487aec242a77287103242e11b2/pydocket-0.24.1-py3-none-any.whl", hash = "sha256:1faa6c3d566f1f0431e35dfa12db4ccee515d945b913b516ee3e6279afb9e789", size = 130249, upload-time = "2026-08-10T19:50:01.627Z" },
]
[[package]]
@@ -2869,7 +2881,8 @@ name = "rpds-py"
version = "0.30.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version < '3.11'",
+ "python_full_version < '3.11' and sys_platform == 'win32'",
+ "python_full_version < '3.11' and sys_platform != 'win32'",
]
sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" }
wheels = [
@@ -2994,9 +3007,12 @@ name = "rpds-py"
version = "2026.6.3"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version == '3.13.*'",
- "python_full_version >= '3.11' and python_full_version < '3.13'",
+ "python_full_version >= '3.14' and sys_platform == 'win32'",
+ "python_full_version >= '3.14' and sys_platform != 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'win32'",
+ "python_full_version == '3.13.*' and sys_platform != 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'",
+ "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'win32'",
]
sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" }
wheels = [
@@ -3218,8 +3234,8 @@ name = "taskgroup"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "exceptiongroup" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504, upload-time = "2025-01-03T09:24:13.761Z" }
wheels = [
@@ -3391,11 +3407,11 @@ wheels = [
[[package]]
name = "uncalled-for"
-version = "0.3.2"
+version = "0.4.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b5/82/345cc927f7fbdae6065e7768759932fcc827fc20b29b45dfbafa2f1f7da4/uncalled_for-0.3.2.tar.gz", hash = "sha256:89f5dbcd71e2b8f47c030b1fa302e6cce2ec795d1ac565eeb6525c5fe55cb8a2", size = 50032, upload-time = "2026-05-06T13:38:25.204Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/6b/5a/92ce0b3ea5481915f55da994c2c2c5f7a3c09949afde196ee89f8ab961aa/uncalled_for-0.4.0.tar.gz", hash = "sha256:335b95bd2422332ec210d518f314a16e4c640921c39fc8bf2ad095bd3538f4af", size = 56979, upload-time = "2026-08-10T14:51:46.247Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3b/25/2c87754f3a9e692315f7b811244090e68f362979fc8886b3fbd2985a1d8c/uncalled_for-0.3.2-py3-none-any.whl", hash = "sha256:0ff60b142c7d1f8070bde9d42afaa70aedc77dcc10998c227687e9c15713418e", size = 11444, upload-time = "2026-05-06T13:38:24.025Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl", hash = "sha256:16c4bb3337532e4bd5569adc192285976f3ad5305402256d34c67a12b5c968bd", size = 15502, upload-time = "2026-08-10T14:51:45.068Z" },
]
[[package]]