When I first started using Claude with my Nix-managed development environment, I ran into an interesting issue. The default examples for starting a local MCP (Model Context Protocol) server with npx
were giving me cryptic error messages whenever I tried to restart Claude:
Error: spawn ENOENT
My first step was to check the Claude logs at ~/Library/Logs/Claude/mcp*.log
using tail
. I also used the MCP inspector tool (so snazzy) to verify that my API keys and tools were configured correctly. Running the tools manually with npx
in my terminal worked fine, so what was going on?
After digging through some issues reported my Windows brethren, I realized that ENOENT
indicates that an executable couldn’t be found. This led me to compare my local PATH
with what Claude was seeing.
To debug this, I used a shell script (suggested by Claude) to save the PATH
and environment variables at MCP startup:
{
"mcpServers": {
"filesystem": {
"command": "/bin/sh",
"args": [
"-c",
"echo $PATH > /tmp/claude_path.txt; env > /tmp/claude_env.txt"
]
}
}
}
After checking the output saved in these files, my suspicion was confirmed: my shell’s PATH
was different from Claude’s, and the npx
executable wasn’t available because it was being managed by Nix.
The solution was not to install npx
globally, but to modify how we call npx
by extending the PATH
in the MCP server configuration:
"filesystem": {
"command": "/bin/sh",
"args": [
"-c",
"PATH=/run/current-system/sw/bin:$PATH exec npx -y @modelcontextprotocol/server-filesystem /Users/b/Desktop /Users/b/Documents /Users/b/Downloads"
]
},
PATH
is set in your MCP configurationENOENT
error usually indicates a missing executable in your PATH
/run/current-system/sw/bin
) to the PATH
can resolve executables not being foundThis solution allows Claude to work seamlessly with Nix-managed development environments while maintaining the isolation and reproducibility that Nix provides.
I wanted to make a public note about this solution, so that others might benefit from my digging. I did a brain dump into Claude about what I did and discovered. It then created this blog post as a Markdown file and committed it to the repo where I store my posts. It got me 95% of the way there on the first try. I saw this, and literally laughed out loud with joy. What it missed was some formatting of the front matter, which I was alerted to after CI failed to generate the new post. I was able to quickly fix it after comparing this new post to an old post’s structure.
For posterity, my prompt-dump:
I'd like to add a new blog post about how I got Claude working with npx installed with Nix. My blog is in source control, on Github, at chrisbodhi/newschematic. The issue I was seeing was that using the default examples to start a local MDP server with npx were giving me cryptic error messages when restarting Claude: "Error: spawn ENOENT". I inspected the logs at ~/Library/Logs/Claude/mcp*.log with tail. I used the MCP inspector tool (so snazzy) to check that the API keys and tools worked as expected. I installed ran the tools manually with npx in my terminal. After digging through some issues from my Windows brethren and realizing that ENOENT means an executable wasn't being found, I compared my local PATH to what Claude was seeing. I used a slick shell script that Claude provided to save the PATH and env at MCP startup: json{
"mcpServers": {
"filesystem": {
"command": "/bin/sh",
"args": [
"-c",
"echo $PATH > /tmp/claude_path.txt; env > /tmp/claude_env.txt"
]
}
}
} That confirmed my shell's PATH different, and that my npx executable wasn't available, because it was being managed by Nix. Claude then suggested a different way of calling npx by extending the PATH. json"filesystem": {
"command": "/bin/sh",
"args": [
"-c",
"PATH=/run/current-system/sw/bin:$PATH exec npx -y @modelcontextprotocol/server-filesystem /Users/b/Desktop /Users/b/Documents /Users/b/Downloads"
]
},