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
-
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"]
}
}
}
-
Start the CLI from a directory above the project (e.g. cd ~ && freebuff).
-
In the project picker, select the project.
-
Ask the main agent which tools it has available.
Result: the MCP tools (context7__*, chrome-devtools__*) are not present.
- Now exit, and restart with
cd ~/projects/<project> && freebuff (no project picker).
- 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
- 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()).
- 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.
- 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.ts — loadMCPConfigSync resolves config from process.cwd()
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.jsonare silently not exposed to the main agent. ThemcpServersare only loaded if the CLI is started directly inside the project directory (e.g.cd ~/projects/foo && freebuff).Environment
freebuffnpm package0.0.142(native binary at~/.config/manicode/freebuff)Steps to reproduce
Create a project with an
.agents/mcp.jsoncontaining 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"] } } }Start the CLI from a directory above the project (e.g.
cd ~ && freebuff).In the project picker, select the project.
Ask the main agent which tools it has available.
Result: the MCP tools (
context7__*,chrome-devtools__*) are not present.cd ~/projects/<project> && freebuff(no project picker).Result: the MCP tools are present.
Expected behavior
MCP servers from the selected project's
.agents/mcp.jsonshould 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 callsloadMCPConfigSync({ verbose: false })(sdk/src/agents/load-mcp-config.ts), which resolves{cwd}/.agents/mcp.jsonagainstprocess.cwd()and populates a module-levelmcpServersCache.cli/src/index.tsx(~line 347): only later, when the user picks a project, does the CLI callprocess.chdir(newProjectPath)followed byresetCodebuffClient().resetCodebuffClient()recreates the client but never reloadsmcp.json— themcpServersCachemodule 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.tsmergesmcpServersCacheinto every agent definition whoseid.startsWith('base')(the Freebuff root agentbase2-free-deepseek-flashqualifies):(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
mcpServersmissing/null.Evidence
Session state (
run-state.json) for the same chat, comparing both launch modes:mcpServersfreebufffrom~, project picked via pickernullcd ~/projects/mathema && freebuff{ "context7": …, "chrome-devtools": … }The agent's registered
toolNames(from the session log) match:context7__resolve-library-id,context7__query-docs, and 29chrome-devtools__*tools appear only in the second mode.Suggested fixes
process.chdir(newProjectPath)in the project-picker path, re-run the MCP config load (or invalidate/re-populatemcpServersCacheand re-runloadAgentDefinitions()/initializeAgentRegistry()).mcp.jsonfrom an explicit project root — instead ofprocess.cwd(), pass the resolved project path toloadMCPConfigSyncso it is independent of launch directory andchdirtiming.Workaround
Always launch the CLI from inside the project directory:
Affected files (approx., from
main)cli/src/index.tsx— boot order:initializeAgentRegistry()beforeprocess.chdir()/resetCodebuffClient()in the project picker pathcli/src/utils/local-agent-registry.ts— the merge ofmcpServersCacheintobase*agent definitionssdk/src/agents/load-mcp-config.ts—loadMCPConfigSyncresolves config fromprocess.cwd()