Skip to content

fix(agent-environment): advertise MCP client roots during list_tools#58

Open
Abhishek21g wants to merge 2 commits into
scaleapi:mainfrom
Abhishek21g:fix/mcp-client-roots
Open

fix(agent-environment): advertise MCP client roots during list_tools#58
Abhishek21g wants to merge 2 commits into
scaleapi:mainfrom
Abhishek21g:fix/mcp-client-roots

Conversation

@Abhishek21g

@Abhishek21g Abhishek21g commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Register FastMCP client roots (default /data) so filesystem-related MCP servers get a timely roots/list response instead of timing out or logging List roots not supported.
  • Add parse_client_roots() with unit tests and document MCP_CLIENT_ROOTS in env.template.

Fixes #17, #18

Problem

During eval startup, MCP servers (notably filesystem) request initial roots from the client. The agent-environment Client was created without a roots handler, which produces intermittent:

Failed to request initial roots from client: MCP error -32001: Request timed out
Failed to request initial roots from client: MCP error -32603: List roots not supported

This can slow or destabilize list_tools when many servers start concurrently.

Solution

Pass roots=parse_client_roots() to fastmcp.Client. Default is /data, matching desktop-commander allowedDirectories and filesystem paths in mcp_server_template.json. Override via comma-separated MCP_CLIENT_ROOTS.

Test plan

  • cd services/agent-environment && PYTHONPATH=src python3 -m pytest tests/test_client_roots.py tests/test_mcp_config_sync.py -v
  • make build && make run-docker with ENABLED_SERVERS=filesystem,git — confirm no roots timeout spam in logs during startup
  • curl -X POST http://localhost:1984/list-tools succeeds

Greptile Summary

This PR fixes intermittent roots/list timeout errors during list_tools startup by registering filesystem roots with the fastmcp.Client. It adds a small, focused parse_client_roots() helper, wires it into mcp_client.py, and documents the MCP_CLIENT_ROOTS env var. Previously flagged issues (hardcoded default in os.getenv, env isolation in tests) have both been resolved.

  • client_roots.py: New module with DEFAULT_CLIENT_ROOTS = ["/data"] and parse_client_roots() that correctly references the constant as the os.getenv fallback, with a safe empty-list guard.
  • mcp_client.py: Calls parse_client_roots() at module level and passes the result to Client(roots=...), which FastMCP accepts as a list[str] and converts to mcp.types.Root objects internally.
  • test_client_roots.py: Covers default, single, multi-root, and whitespace-stripping cases; a test for the env-var-is-set code path is missing but the rest of the logic is well validated.

Confidence Score: 5/5

Safe to merge — the change is additive, touches only startup initialization, and both previously reported issues have been corrected.

The new code is small and isolated: a pure-function parser, a module-level call that reads an env var at startup, and a single extra kwarg on the existing Client constructor. FastMCP documents list[str] as a valid roots input and handles the conversion to mcp.types.Root internally. There are no data-path or auth changes, and the fix directly addresses a known startup race condition.

No files require special attention. The only gap is a missing test for the env-var-is-set code path in test_client_roots.py, but the runtime behavior is straightforward.

Important Files Changed

Filename Overview
services/agent-environment/src/agent_environment/client_roots.py New module exposing parse_client_roots() with correct DEFAULT_CLIENT_ROOTS reference in the os.getenv fallback and a safe fallback when the parsed list is empty.
services/agent-environment/src/agent_environment/mcp_client.py Adds module-level parse_client_roots() call and passes the result as roots= to fastmcp.Client; logger is already initialised at line 11, so the new logger.info call is safe.
services/agent-environment/tests/test_client_roots.py Unit tests cover default fallback (with env deletion via monkeypatch), single root, multiple roots, and whitespace stripping; the env-var-is-set path for parse_client_roots(None) is not tested but the core logic is validated.
env.template Documents MCP_CLIENT_ROOTS in the correct section with a commented-out example and a clear description of the default.
services/agent-environment/README.md Adds one sentence explaining the roots advertised to MCP servers and links to the relevant issues; no inaccuracies.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant E as Environment (MCP_CLIENT_ROOTS)
    participant CR as client_roots.py
    participant MC as mcp_client.py (module init)
    participant FC as fastmcp.Client
    participant MS as MCP Server (e.g. filesystem)

    MC->>CR: parse_client_roots()
    CR->>E: os.getenv("MCP_CLIENT_ROOTS", "/data")
    E-->>CR: "/data" (or custom paths)
    CR-->>MC: ["/data"]
    MC->>FC: "Client(config, roots=["/data"])"
    Note over FC: converts str to mcp.types.Root(uri=FileUrl)
    MS->>FC: roots/list request
    FC-->>MS: "[Root(uri="file:///data")]"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant E as Environment (MCP_CLIENT_ROOTS)
    participant CR as client_roots.py
    participant MC as mcp_client.py (module init)
    participant FC as fastmcp.Client
    participant MS as MCP Server (e.g. filesystem)

    MC->>CR: parse_client_roots()
    CR->>E: os.getenv("MCP_CLIENT_ROOTS", "/data")
    E-->>CR: "/data" (or custom paths)
    CR-->>MC: ["/data"]
    MC->>FC: "Client(config, roots=["/data"])"
    Note over FC: converts str to mcp.types.Root(uri=FileUrl)
    MS->>FC: roots/list request
    FC-->>MS: "[Root(uri="file:///data")]"
Loading

Reviews (2): Last reviewed commit: "test(agent-environment): isolate default..." | Re-trigger Greptile

…ols stalls

Filesystem MCP servers request roots during startup; without a roots handler
the FastMCP client times out or returns "List roots not supported".
Comment thread services/agent-environment/tests/test_client_roots.py
Comment thread services/agent-environment/src/agent_environment/client_roots.py Outdated
Derive os.getenv default from DEFAULT_CLIENT_ROOTS and monkeypatch
MCP_CLIENT_ROOTS in test_default_roots.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

After starting the MCP server and running the evaluation, this kind of bug sometimes occurs. How can it be fixed?

1 participant