Skip to content

[Bug]: MCP stdio server always runs with cwd=homedir() and returns home as roots; workspace context is dropped, breaking per-project tools like codegraph #76

Closed as not planned

Description

@jianga0801-ui

Issue 内容(MiniMax-AI/minimax-code · [Bug]: MCP stdio server 始终以 home 目录作为 cwd/roots,跨 workspace 不可用)

仓库: MiniMax-AI/minimax-code
模板: 01-bug-report.yml (Bug report / 问题反馈)
Issue area: MCP / OAuth / integration
Version: v3.0.43
Platform: Windows
OS version: Windows 11 23H2
Upload ID: cannot upload (no crash, behavior bug)


Title

[Bug]: MCP stdio server always runs with cwd=homedir() and returns home as roots; workspace context is dropped, breaking per-project tools like codegraph


What happened?

When the daemon starts an MCP server with transport.type === "stdio" and that server relies on the current working directory or the MCP roots/list request to discover the active workspace (e.g. the CodeGraph MCP server, which walks up from process.cwd() looking for .codegraph/), the server always sees the user's home directory instead of the agent's current workspace.

Symptom with the CodeGraph MCP server (configured in ~/.mavis/mcp/mcp.json):

> mavis mcp call codegraph codegraph_search '{"query":"Desktop"}'
No CodeGraph project is loaded for this session.
Searched for a .codegraph/ directory starting from: C:\Users\14378

The user has a valid .codegraph/ index at C:\Users\14378\Documents\Code\Claude\Windows-MCP\.codegraph\, but the server only ever walks up from $HOME, so it never finds it. Switching to a different workspace does not change behavior — every workspace reports the same "starting from home" message.

Workaround: passing projectPath explicitly in the tool args works (e.g. {"query":"Desktop","projectPath":"C:/Users/.../Windows-MCP"}), which confirms the server itself is healthy; the daemon is what is dropping the workspace context.


Root cause (from inspecting daemon.js)

The daemon bundles createStdioTransport and a hard-coded ListRootsRequestSchema handler that both ignore the calling session entirely:

// packages/daemon/src/mcp/runtime/transport/stdio.ts  (in daemon.js ~line 493289)
function createStdioTransport(config, options) {
  return new StdioClientTransport({
    command: config.command,
    args: config.args,
    env: buildProcessEnv(config.env, options?.env),
    cwd: homedir(),                  // ← always homedir, ignores session
    stderr: "pipe"
  });
}

// packages/daemon/src/mcp/runtime/connection-pool.ts  (in daemon.js ~line 493515)
client.setRequestHandler(ListRootsRequestSchema, async () => ({
  roots: [{ uri: pathToFileURL(homedir()).href, name: "home" }]   // ← always home
}));

Two related issues:

  1. The stdio transport spawns the child with cwd = homedir() regardless of which session/agent triggered the call.
  2. When the server requests roots/list (the spec-blessed way to learn the workspace), the handler always returns the home directory.

McpConnectionPool.callTool(serverName, toolName, args, overrides, options) accepts an options object, but only options.timeout is read — there is no plumbing for workspace context from session → transport.

Additionally, McpConnectionPool.connections = new Map<serverName, connection>() caches one connection per server name globally, so even if transport were fixed naively, two sessions in different workspaces would share the same child process. CodeGraph supports per-call projectPath to multiplex, but other servers may not.

The session layer already has the data — session.workspaceDir is plumbed everywhere (e.g. agentProcessManager.ensureAgentProcess(ctx, agentName, workspaceDir), spawnSessionProcess(..., { cwd: workspaceDir }), ~235 hits in daemon.js), it just doesn't reach MCP.


Steps to reproduce

  1. Install the CodeGraph MCP server (or any stdio MCP server that resolves a project root from cwd/roots) and index a project with codegraph init so .codegraph/ exists in the project root.
  2. Start an agent session in MiniMax Code with that project as the workspace.
  3. From the agent, call any codegraph tool (e.g. codegraph_search) without passing projectPath.
  4. Observe the server reports "No CodeGraph project is loaded … starting from: C:\Users<you>".
  5. Switch to a different project workspace, repeat the call — the error message still says C:\Users\<you>.

Reproduction from CLI:

mavis mcp call codegraph codegraph_search '{"query":"Desktop"}'
# → No CodeGraph project is loaded for this session.
#   Searched for a .codegraph/ directory starting from: C:\Users\14378

echo '{"query":"Desktop","projectPath":"C:/Users/14378/Documents/Code/Claude/Windows-MCP"}' \
  | mavis mcp call codegraph codegraph_search --stdin
# → works (10 results)

Expected behavior

The MCP stdio server should be able to discover the active workspace via one of:

  • process.cwd() reflecting the calling session's workspace, or
  • roots/list returning { uri: "file:///path/to/active/workspace", name: "workspace" } for the calling session's workspaceDir.

Switching to a different project workspace should change which .codegraph/ (or equivalent per-project state) the server finds.


Actual behavior

Both cwd and roots/list always resolve to the user's home directory. Per-project MCP servers are effectively unusable without manual projectPath workarounds. The user has to inject workspace context into every tool call.


Suggested fix (sketch, not exhaustive)

The minimum changes are in two places, both in daemon.js:

  1. createStdioTransport — accept and forward an optional cwd from options (which already exists on createTransport's options), defaulting to homedir() only when nothing else is available.

  2. ListRootsRequestSchema handler — pull the active workspace from a session-aware context (e.g. an AsyncLocalStorage populated by callTool from session.workspaceDir); fall back to homedir() if no session is in flight.

  3. McpConnectionPool.callTool — extend the options argument to accept { timeout, workspaceDir, sessionId }, pass workspaceDir into the transport factory, and store it on the connection so roots/list can read it without global state.

  4. Connection caching — consider keying connections by (serverName, workspaceDir) instead of just serverName, or at minimum guarantee that every call forwards the correct projectPath (CodeGraph already supports this; the daemon should inject it). For servers that don't support per-call project selection, per-workspace child processes are required.

The session layer already has the data (session.workspaceDir) and threads it into agent process spawning — it just stops at the MCP boundary.


Logs / evidence

From the user's machine:

  • mavis mcp get codegraph:
    {
      "command": "C:\\Program Files\\nodejs\\node.exe",
      "args": [
        "C:\\Users\\14378\\AppData\\Roaming\\npm\\node_modules\\@colbymchenry\\codegraph\\npm-shim.js",
        "serve",
        "--mcp"
      ],
      "env": {},
      "enabled": true,
      "configured": true
    }
  • mavis --version → 3.0.43
  • CodeGraph server's own daemon log (<project>/.codegraph/daemon.log) shows the server starts fine, just at the wrong root.

Before submitting

  • I have searched existing issues. (Searched: "MCP workspace", "roots/list", "stdio cwd" — no matches in open issues)
  • I am using the latest version available to me. (3.0.43)
  • I have removed sensitive information from logs/screenshots. (paths and tool names only)

Activity

  1. added
    bugSomething isn't working
    desktopMiniMax Code desktop app
    needs-triageAwaiting maintainer assessment
    and removed
    desktopMiniMax Code desktop app
    on Sep 19, 2026
  2. hetaoBackend commented on Sep 21, 2026

    @hetaoBackend
    Collaborator

    This was generated by AI during triage.

    Confirmed as a real gap. Daemon-spawned stdio MCP servers are currently user-scoped, long-lived processes — they get the daemon's cwd (home) and roots/list reflects that, so any per-workspace tool like codegraph loses workspace context.

    Agreed direction: roots/list should reflect the active workspace of the calling session (or servers should be spawnable per-workspace). Tracked. Thanks for the detailed writeup.

  3. hetaoBackend commented on Oct 19, 2026

    @hetaoBackend
    Collaborator

    Closing as part of a backlog cleanup: this issue was filed more than a month ago against an older release, and the codebase has changed substantially since then. If it still reproduces on the latest version, please open a new issue with the current version and reproduction steps. Thank you for the report!

    批量清理积压:该 issue 创建已超过一个月,针对的是较旧版本,代码已有较大变化。如果在最新版本上仍能复现,欢迎附上当前版本号和复现步骤重新提交 issue。感谢反馈!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdesktopMiniMax Code desktop appneeds-triageAwaiting maintainer assessment

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions