Repository navigation
[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
Description
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:
- The stdio transport spawns the child with
cwd = homedir()regardless of which session/agent triggered the call. - 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
- Install the CodeGraph MCP server (or any stdio MCP server that resolves a project root from cwd/roots) and index a project with
codegraph initso.codegraph/exists in the project root. - Start an agent session in MiniMax Code with that project as the workspace.
- From the agent, call any codegraph tool (e.g.
codegraph_search) without passingprojectPath. - Observe the server reports "No CodeGraph project is loaded … starting from: C:\Users<you>".
- 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, orroots/listreturning{ uri: "file:///path/to/active/workspace", name: "workspace" }for the calling session'sworkspaceDir.
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:
-
createStdioTransport— accept and forward an optionalcwdfromoptions(which already exists oncreateTransport's options), defaulting tohomedir()only when nothing else is available. -
ListRootsRequestSchemahandler — pull the active workspace from a session-aware context (e.g. anAsyncLocalStoragepopulated bycallToolfromsession.workspaceDir); fall back tohomedir()if no session is in flight. -
McpConnectionPool.callTool— extend theoptionsargument to accept{ timeout, workspaceDir, sessionId }, passworkspaceDirinto the transport factory, and store it on the connection soroots/listcan read it without global state. -
Connection caching — consider keying connections by
(serverName, workspaceDir)instead of justserverName, or at minimum guarantee that every call forwards the correctprojectPath(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
hetaoBackend commentedon Sep 21, 2026
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/listreflects that, so any per-workspace tool like codegraph loses workspace context.Agreed direction:
roots/listshould reflect the active workspace of the calling session (or servers should be spawnable per-workspace). Tracked. Thanks for the detailed writeup.hetaoBackend commentedon Oct 19, 2026
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。感谢反馈!