Skip to content

[Bug] MCP servers from .agents/mcp.json are not loaded when the project is selected via the project picker (CLI started from an ancestor directory) #957

Description

@Fahell

Summary

When the Freebuff CLI is started from a directory outside the project and the project is then selected via the project picker, the MCP servers defined in the project's .agents/mcp.json are silently not exposed to the main agent. The mcpServers are only loaded if the CLI is started directly inside the project directory (e.g. cd ~/projects/foo && freebuff).

Environment

  • CLI: freebuff npm package 0.0.142 (native binary at ~/.config/manicode/freebuff)
  • OS: Linux
  • Tested: 2026-08-07

Steps to reproduce

  1. Create a project with an .agents/mcp.json containing one or more MCP servers, e.g.:

    {
      "mcpServers": {
        "context7": {
          "type": "http",
          "url": "https://mcp.context7.com/mcp",
          "headers": { "Authorization": "Bearer $CONTEXT7_API_KEY" }
        },
        "chrome-devtools": {
          "command": "npx",
          "args": ["-y", "chrome-devtools-mcp@latest", "--headless", "--isolated"]
        }
      }
    }
  2. Start the CLI from a directory above the project (e.g. cd ~ && freebuff).

  3. In the project picker, select the project.

  4. Ask the main agent which tools it has available.

Result: the MCP tools (context7__*, chrome-devtools__*) are not present.

  1. Now exit, and restart with cd ~/projects/<project> && freebuff (no project picker).
  2. Ask the same question.

Result: the MCP tools are present.

Expected behavior

MCP servers from the selected project's .agents/mcp.json should be available to the main agent regardless of which directory the CLI was launched from.

Actual behavior

MCP servers are only available when the CLI is launched inside the project directory. Selecting the project afterwards via the picker never exposes them.

Root cause analysis

The MCP config is loaded once, at boot time, using the then-current process.cwd():

  • cli/src/index.tsx (~line 260): await initializeAgentRegistry() runs during startup. This calls loadMCPConfigSync({ verbose: false }) (sdk/src/agents/load-mcp-config.ts), which resolves {cwd}/.agents/mcp.json against process.cwd() and populates a module-level mcpServersCache.
  • cli/src/index.tsx (~line 347): only later, when the user picks a project, does the CLI call process.chdir(newProjectPath) followed by resetCodebuffClient().
  • resetCodebuffClient() recreates the client but never reloads mcp.json — the mcpServersCache module variable was already populated (with an empty/absent config) at boot.

The merge itself is correct and does run afterwards:

  • cli/src/utils/local-agent-registry.ts merges mcpServersCache into every agent definition whose id.startsWith('base') (the Freebuff root agent base2-free-deepseek-flash qualifies):

    for (const agent of definitions) {
      if (agent.id.startsWith('base')) {
        if (!agent.mcpServers) agent.mcpServers = {};
        agent.mcpServers = { ...agent.mcpServers, ...mcpServersCache };
      }
    }

    (Confirmed in the installed binary's minified JS: if(Object.keys(VW).length>0){for(let D of A)if(D.id.startsWith("base")){if(!D.mcpServers)D.mcpServers={};D.mcpServers={...D.mcpServers,...VW}}}.)

Because the cache was populated at boot from the wrong cwd, the merge operates on an empty cache → the main agent template ends up with mcpServers missing/null.

Evidence

Session state (run-state.json) for the same chat, comparing both launch modes:

Launch mode Main agent template mcpServers
freebuff from ~, project picked via picker missing / null
cd ~/projects/mathema && freebuff { "context7": …, "chrome-devtools": … }

The agent's registered toolNames (from the session log) match: context7__resolve-library-id, context7__query-docs, and 29 chrome-devtools__* tools appear only in the second mode.

Suggested fixes

  1. Reload MCP config on project change — after process.chdir(newProjectPath) in the project-picker path, re-run the MCP config load (or invalidate/re-populate mcpServersCache and re-run loadAgentDefinitions() / initializeAgentRegistry()).
  2. Resolve mcp.json from an explicit project root — instead of process.cwd(), pass the resolved project path to loadMCPConfigSync so it is independent of launch directory and chdir timing.
  3. Load lazily — resolve the MCP config from the project root at session/run start rather than at process boot, so the picker path is naturally covered.

Workaround

Always launch the CLI from inside the project directory:

cd ~/projects/<project> && freebuff

Affected files (approx., from main)

  • cli/src/index.tsx — boot order: initializeAgentRegistry() before process.chdir() / resetCodebuffClient() in the project picker path
  • cli/src/utils/local-agent-registry.ts — the merge of mcpServersCache into base* agent definitions
  • sdk/src/agents/load-mcp-config.tsloadMCPConfigSync resolves config from process.cwd()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions