langchain-ai/deepagents · error · ValueError
{self.scope} MCP config {need} a project root: {self.path}
Error message
{self.scope} MCP config {need} a project root: {self.path} What it means
MCP config references carry a scope (PROJECT or user/global). A PROJECT-scoped config must have a `project_root`, and a non-PROJECT config must NOT have one — exactly one of the two conditions must hold. `MCPConfigRef.__post_init__` raises this ValueError when scope and project_root disagree, templating the message with the scope, the required word ('requires'/'must not carry') and the path.
Source
Thrown at libs/code/deepagents_code/mcp_tools.py:1377
project_root: Path | None = None
def __post_init__(self) -> None:
"""Tie `project_root` to the scope that requires it.
`project_root` is the key that project-trust approvals are recorded
against, so a `PROJECT` config without one would be checked against a
re-derived fallback root instead of failing. Rejecting the combination
here keeps that from degrading into "trusted against the wrong root".
Raises:
ValueError: If the scope and `project_root` disagree.
"""
if (self.scope is MCPConfigScope.PROJECT) != (self.project_root is not None):
need = (
"requires" if self.scope is MCPConfigScope.PROJECT else "must not carry"
)
msg = f"{self.scope} MCP config {need} a project root: {self.path}"
raise ValueError(msg)
class MCPConfigIdentity(StrEnum):
"""Whether two discovered config paths are the same underlying file."""
SAME = "same"
"""The paths are lexically equal or resolve to one file."""
DIFFERENT = "different"
"""The paths resolve to distinct files."""
UNKNOWN = "unknown"
"""Resolution failed, so identity could not be determined."""
def _same_config_location(first: Path, second: Path) -> MCPConfigIdentity:
"""Return whether two discovered paths identify the same config.
View on GitHub (pinned to a1af029e6e)
Solutions
- For a project-scoped ref, set project_root to the directory owning the config: MCPConfigRef(scope=MCPConfigScope.PROJECT, project_root=Path.cwd(), ...).
- For a user/global-scoped ref, set project_root=None.
- Derive scope and project_root together from one code path so they can't diverge.
Example fix
// before
MCPConfigRef(scope=MCPConfigScope.PROJECT, path=cfg_path, project_root=None)
// after
MCPConfigRef(scope=MCPConfigScope.PROJECT, path=cfg_path, project_root=Path("/home/me/project")) Defensive patterns
Strategy: validation
Validate before calling
def make_ref(scope, path, project_root=None):
if (scope is MCPConfigScope.PROJECT) != (project_root is not None):
raise ValueError("scope and project_root are inconsistent")
return MCPConfigRef(scope=scope, path=path, project_root=project_root) Type guard
def ref_is_consistent(ref) -> bool:
return (ref.scope is MCPConfigScope.PROJECT) == (ref.project_root is not None) Try / catch
try:
ref = MCPConfigRef(scope=scope, path=p, project_root=root)
except ValueError as e:
if "project root" in str(e):
ref = MCPConfigRef(scope=scope, path=p, project_root=Path.cwd() if scope is MCPConfigScope.PROJECT else None)
else:
raise Prevention
- Build refs through one factory that sets scope and project_root together.
- Never attach project_root to user/global-scope refs to 'disambiguate' paths.
- When deserializing refs, recompute scope from project_root instead of storing both independently.
When it happens
Trigger: Constructing MCPConfigRef(scope=MCPConfigScope.PROJECT, project_root=None, ...) or MCPConfigRef(scope=MCPConfigScope.USER/<global>, project_root="/some/dir", ...) — the invariant (scope is PROJECT) == (project_root is not None) is violated in a dataclass post-init.
Common situations: Programmatically building config refs where the scope enum was changed but project_root wasn't updated; copying a user-scope ref and adding a project_root to disambiguate paths; deserializing refs from storage with mismatched fields.
Related errors
- MCPServerInfo {self.name!r}: status='ok' cannot carry an err
- MCPServerInfo {self.name!r}: status={self.status!r} requires
- ColdCacheWarning age_seconds={self.age_seconds!r} does not p
- `unreadable_reason` implies the token is not usable; `logged
- ConfigResolution must have at least one used path
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/a00e597610d6f2a7.
Report an issue: GitHub.