Skip to content

[Bug]: MCP context variables can route tools to the wrong session workspace #82121

Description

@fangliquanflq

Bug Description

MCP server configurations that use ${workspaceFolder} or ${workspaceFolderBasename} can be bound to the backend default workspace instead of the workspace of the session making the tool call. In a gateway process serving multiple sessions, the same process-global MCP transport can then be reused across distinct session workspaces.

For filesystem-style MCP servers, this can make a tool read from or write to the wrong project without an obvious routing error.

Steps to Reproduce

  1. Configure a stdio MCP server whose fixed launch arguments include ${workspaceFolder} and ${workspaceFolderBasename}.
  2. Start one Hermes gateway process and record two active sessions with different working directories, such as session-alpha and session-beta.
  3. Invoke the same MCP server from each session and have the server report its fixed launch root and process identity.
  4. Observe that, before the fix, both variables expand to the backend default workspace and the later session reuses the original process-global server.

Expected Behavior

Each MCP call should expand workspace context variables from the active session's authoritative working directory. Calls may reuse a transport only when they resolve to the same canonical workspace.

Actual Behavior

Workspace context variables are expanded before a tool call has session identity. The resulting fixed transport is stored under the global server name, so distinct sessions can share a server configured for the wrong workspace.

Impact

  • Workspace-sensitive MCP tools can operate on the backend or another session's project instead of the caller's project.
  • Filesystem-style servers can therefore return incorrect files or modify the wrong workspace.
  • The reproduced scope is one process serving multiple session working directories; broader deployment frequency was not measured.

Affected Component

Tools (MCP client and generated MCP resource/prompt utilities)

Messaging Platform (if gateway-related)

Gateway sessions; platform-independent

Debug Report

N/A - reproduced locally with an isolated multi-session MCP probe. An accompanying PR includes automated coverage.

Operating System

Windows 10

Python Version

3.11.15

Hermes Version

Reproduced on main commit 372b3b7bba4b2b8f5880581984eedf685056dbdf.

Additional Logs / Traceback (optional)

session-alpha and session-beta had distinct recorded and runtime cwd values, but both workspace variables expanded to backend-workspace. Registering the same server name for session-beta reused the original fixed stdio launch root.

Root Cause Analysis (optional)

Trigger: tools/mcp_tool.py::_workspace_folder, _load_mcp_config, and the process-global server lookup used by MCP handlers.

Causal chain:

  1. Gateway startup loads MCP configuration before a tool call supplies its task/session identity.
  2. Workspace context variables are eagerly expanded from the backend/default root and the connected transport is cached by raw server name.
  3. A later session resolves the same public MCP tool to that transport and operates in the wrong workspace.

Why it is wrong: Workspace context is session-scoped, but interpolation and transport ownership were process-scoped. The public tool schema can be global; the fixed transport configuration cannot when it contains workspace variables.

Working sibling / contrast: File and terminal tools pass task/session identity into authoritative cwd resolution, so they select the session-specific root.

Ruled out: This is not stale session cwd persistence. The reproduction confirmed that both authoritative session roots were correct while only rootless MCP interpolation and transport reuse selected the backend workspace.

Verified on tip: The failure was reproduced against the stated main commit, and no open PR found by the duplicate search covers session-scoped MCP workspace interpolation and routing.

Proposed Fix (optional)

Preserve workspace-sensitive configuration templates, interpolate them with the active tool call's task/session identity, and route regular MCP tools plus generated resource/prompt utilities through transports keyed by canonical workspace. Keep one stable public tool schema while including scoped transports in availability, retry, probe, and shutdown lifecycle handling.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/sessionsSession lifecycle, resume, persistence, historycomp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpointsweeper:risk-session-stateSweeper risk: may lose/corrupt/mis-associate session or context statetool/mcpMCP client and OAuthtype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions