Ir al contenido

Why Your MCP Servers Suddenly Can't Find npx: Understanding Shell Initialization on macOS

A guided learning experience on .zshrc vs .zshenv, non-interactive shells, and why Gemini CLI's MCP servers lose their PATH — even when everything worked yesterday.
16 de marzo de 2026 por
Why Your MCP Servers Suddenly Can't Find npx: Understanding Shell Initialization on macOS
Nhomar Hernandez

You configured your MCP servers, tested them, everything worked perfectly. Then one day, you open your terminal and every single one of them throws the same cryptic error:

Error: exec: "npx": executable file not found in $PATH.


All of them. At the same time. What happened? Did Node.js uninstall itself? Did Homebrew break? The answer is simpler — and more instructive — than you might think. This post documents a real debugging session, the root cause, and the fundamental Unix concept that every developer working with AI tools should understand.

🔍 The Symptom

Every MCP server configured in Gemini CLI — Odoo MCP, NotebookLM MCP, Playwright, yt-dlp, Fetcher, Sequential Thinking — failed with the same error: npx was not found in $PATH.

But here's the confusing part: opening a regular terminal and typing which npx returned /opt/homebrew/bin/npx without any issue. Node.js was installed. npx was right there. So why couldn't the MCP servers find it?

🧠 The Root Cause: Interactive vs Non-Interactive Shells

To understand the issue, you need to understand how zsh (macOS's default shell since Catalina) loads its configuration files. Not all config files are created equal:

~/.zshrc

Loaded only for interactive shells — when you open a terminal window, type commands, and see output. This is where most people put their PATH modifications.

~/.zshenv

Loaded for ALL shells — interactive, non-interactive, login, non-login. This is the universal configuration file that runs in every context.

When Gemini CLI (or any IDE, CI/CD system, or background process) launches an MCP server, it does not open an interactive terminal. It spawns a non-interactive shell to execute the command. Therefore:

  • ~/.zshrc → ❌ NOT loaded (non-interactive shell)
  • ~/.zshenv → ✅ Always loaded

If your PATH additions (like /opt/homebrew/bin) only exist in ~/.zshrc, they will be invisible to every process that doesn't open a terminal. This includes MCP servers, VS Code tasks, cron jobs, launch agents, and more.

🤔 Wait — Why Did Antigravity Work Before?

Great question. If npx wasn't in the PATH for non-interactive shells, how were any MCP servers working at all?

The answer lies in how you launch Gemini CLI:

  • From a terminal window → The terminal loads ~/.zshrc first. When Gemini CLI starts within that terminal session, it inherits the terminal's environment, including the full $PATH. Child processes spawned by Gemini CLI in that session also inherit it.
  • From a system-level process or IDE integration → There's no parent interactive shell. The process starts with the bare system PATH, which typically only includes /usr/bin, /bin, /usr/sbin, /sbin. Homebrew's /opt/homebrew/bin is missing.

So if you always launched from a terminal, you never noticed the problem. The moment the process was started differently (a system restart, an IDE update, a launchd agent, etc.), the inherited PATH vanished and all MCP servers broke simultaneously.

✅ The Fix: One Line in ~/.zshenv

The solution is elegant and minimal. Create (or edit) ~/.zshenv and add the Homebrew path:

# ~/.zshenv
# Ensure Homebrew binaries (npx, node, npm) are available
# in ALL shell contexts (interactive AND non-interactive).
export PATH="/opt/homebrew/bin:$PATH"


Then restart the process that launches your MCP servers (Gemini CLI, your IDE, etc.).

That's it. One line. The npx binary is now available in every shell context, regardless of how the process is started.

📊 The Complete zsh Startup File Order

For reference, here is the complete order in which zsh loads its configuration files, and in which contexts each one applies:

FileInteractive ShellNon-Interactive ShellLogin Shell
~/.zshenv✅ Yes✅ Yes✅ Yes
~/.zprofile✅ Yes❌ No✅ Yes
~/.zshrc✅ Yes❌ No✅ Yes
~/.zlogin✅ Yes❌ No✅ Yes

The key insight: ~/.zshenv is the only file loaded in ALL contexts. It's the correct place for environment variables that must be universally available.

🎓 What We Learned

  1. Not all shell config files are equal. ~/.zshrc is for interactive customization (aliases, prompts, keybindings). ~/.zshenv is for universal environment variables (PATH, EDITOR, LANG).
  2. MCP servers run in non-interactive shells. They don't load your ~/.zshrc. If your tools (npx, python, node) depend on PATH modifications in ~/.zshrc, they will fail silently in MCP contexts.
  3. "It works in my terminal" is not enough. The fact that a command works when you type it doesn't mean it will work when a background process tries to execute it. Understanding the execution context is critical.
  4. Environment inheritance is fragile. A process inherits its parent's environment. If the parent (your terminal) had the right PATH, so do its children. But if the parent changes (system reboot, IDE restart, launchd), the chain breaks.
  5. Apple Silicon introduced a new variable. Before Apple Silicon Macs, Homebrew installed to /usr/local/bin, which was already in the default system PATH. With Apple Silicon, Homebrew moved to /opt/homebrew/bin, which is not in the default system PATH. This is why this problem is particularly common on modern Macs.

🛡️ Prevention Checklist

If you're setting up MCP servers on macOS, follow this checklist to avoid the same pitfall:

  • ✅ Create ~/.zshenv with your essential PATH entries
  • ✅ Keep ~/.zshrc for interactive-only settings (aliases, oh-my-zsh, prompts)
  • ✅ Test your setup by running zsh -c 'which npx' (simulates a non-interactive shell)
  • ✅ After changing ~/.zshenv, restart your CLI/IDE completely
  • ✅ If using nvm or pyenv, ensure their init scripts are also in ~/.zshenv

Working with AI-powered dev tools?

Understanding your environment is just as important as understanding your code. Small configuration details like this can save hours of debugging. Share this post with your team if they're using MCP servers, Gemini CLI, or any AI coding assistants on macOS.

en News

💬 Comentarios

🔒 Para dejar un comentario, necesitas iniciar sesión.

Identificarse
odoo-mcp-multi: Tu Odoo ahora habla con la IA 🤖
Cómo conectar múltiples instancias de Odoo con asistentes de IA usando un solo servidor MCP