Summary
All 11 mcp__ruvector__brain_* tools in the ruvector MCP server fail at runtime with:
ERR_PACKAGE_PATH_NOT_EXPORTED
No "exports" main defined in .../node_modules/@ruvector/pi-brain/package.json
The CLI (ruvector brain status, etc.) works — only the MCP tools are broken.
Environment
ruvector 0.2.22 (npm, global)
@ruvector/pi-brain 0.1.1 (npm, global; pulled in as a sibling install)
- Node.js v20.19.6
- Linux (WSL2)
Reproduction
npm i -g ruvector @ruvector/pi-brain
# Start the MCP server in any MCP client (Claude Code, etc.) and call:
# mcp__ruvector__brain_status
# Result:
# { "success": false, "error": "No \"exports\" main defined in .../@ruvector/pi-brain/package.json" }
Or reproduce directly without MCP:
cd $(npm root -g)/ruvector
node -e "try { require('@ruvector/pi-brain'); } catch (e) { console.log(e.code, e.message); }"
# ERR_PACKAGE_PATH_NOT_EXPORTED No "exports" main defined in .../@ruvector/pi-brain/package.json
Root cause
bin/mcp-server.js is CommonJS and uses synchronous require() in 11 brain handlers:
// bin/mcp-server.js, lines 3242, 3259, 3276, 3293, 3310, 3327, 3344, 3361, 3378, 3395, 3412
const piBrain = require('@ruvector/pi-brain');
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
But @ruvector/pi-brain@0.1.1 is ESM-only with no require condition in its export map:
// @ruvector/pi-brain/package.json
{
"type": "module",
"main": "dist/index.js",
"exports": {
".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" }
}
}
Since there is no "require" condition, Node refuses the CJS require() and throws ERR_PACKAGE_PATH_NOT_EXPORTED. The handler's catch block only converts MODULE_NOT_FOUND to the friendly "install @ruvector/pi-brain" hint, so this error falls through to the raw e.message path and the tool returns { success: false, error: "No \"exports\" main defined ..." }.
Affected tools (all 11 brain_* MCP tools)
brain_search, brain_share, brain_get, brain_vote, brain_list, brain_delete, brain_status, brain_drift, brain_partition, brain_transfer, brain_sync
Why the CLI is unaffected
ruvector brain <subcmd> calls pi.ruv.io over HTTPS without loading @ruvector/pi-brain, so the ESM interop path is never hit.
Suggested fix
The MCP handler is already async (server.setRequestHandler(CallToolRequestSchema, async (request) => {...})), so a one-line change in each handler is sufficient:
- const piBrain = require('@ruvector/pi-brain');
+ const piBrain = await import('@ruvector/pi-brain');
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
This is the same edit × 11 call sites. Verified locally:
cd $(npm root -g)/ruvector
node -e "(async () => { const p = await import('@ruvector/pi-brain'); console.log(Object.keys(p)); })()"
# [ 'PiBrainClient' ]
Alternative: publish @ruvector/pi-brain with a dual CJS/ESM build and add a "require" condition to the exports map. The dynamic-import fix in the consumer is the smaller diff and lets pi-brain stay ESM-only.
Workaround (for anyone hitting this now)
Patch the installed MCP server in place:
sed -i "s |require('@ruvector/pi-brain')|await import('@ruvector/pi-brain')|g" \
$(npm root -g)/ruvector/bin/mcp-server.js
# Restart the MCP server / reconnect from the client
Confirmed this unblocks all 11 tools locally. Any npm i -g ruvector upgrade will wipe the patch until this is fixed upstream.
Summary
All 11
mcp__ruvector__brain_*tools in the ruvector MCP server fail at runtime with:The CLI (
ruvector brain status, etc.) works — only the MCP tools are broken.Environment
ruvector0.2.22 (npm, global)@ruvector/pi-brain0.1.1 (npm, global; pulled in as a sibling install)Reproduction
Or reproduce directly without MCP:
Root cause
bin/mcp-server.jsis CommonJS and uses synchronousrequire()in 11 brain handlers:But
@ruvector/pi-brain@0.1.1is ESM-only with norequirecondition in its export map:Since there is no
"require"condition, Node refuses the CJSrequire()and throwsERR_PACKAGE_PATH_NOT_EXPORTED. The handler'scatchblock only convertsMODULE_NOT_FOUNDto the friendly "install @ruvector/pi-brain" hint, so this error falls through to the rawe.messagepath and the tool returns{ success: false, error: "No \"exports\" main defined ..." }.Affected tools (all 11
brain_*MCP tools)brain_search,brain_share,brain_get,brain_vote,brain_list,brain_delete,brain_status,brain_drift,brain_partition,brain_transfer,brain_syncWhy the CLI is unaffected
ruvector brain <subcmd>callspi.ruv.ioover HTTPS without loading@ruvector/pi-brain, so the ESM interop path is never hit.Suggested fix
The MCP handler is already
async(server.setRequestHandler(CallToolRequestSchema, async (request) => {...})), so a one-line change in each handler is sufficient:This is the same edit × 11 call sites. Verified locally:
Alternative: publish
@ruvector/pi-brainwith a dual CJS/ESM build and add a"require"condition to theexportsmap. The dynamic-importfix in the consumer is the smaller diff and letspi-brainstay ESM-only.Workaround (for anyone hitting this now)
Patch the installed MCP server in place:
Confirmed this unblocks all 11 tools locally. Any
npm i -g ruvectorupgrade will wipe the patch until this is fixed upstream.