Anthropic’s Model Context Protocol shipped without standardized installation tooling. The protocol itself works fine. Getting an MCP server wired into Claude Desktop, Cline, or Zed requires hand-editing JSON config files in client-specific locations. The @incultnitollc/mcpr package addresses this with a cross-client installer. The implementation is a post-mortem of bugs encountered during the v0.2.0 release, exposing the real plumbing gap between protocol specification and developer adoption.
The Manual Config Problem
Installing an MCP server today means:
- Finding the server on GitHub
- Reading the README for the launch command
- Copying a JSON fragment
- Locating the correct config file for your client
- Pasting the fragment without breaking existing servers
- Restarting the client
Step 4 is the maze. Each client stores its config in a different location with a different schema.
| Client | macOS Path | Windows Path | Schema Key | Env Handling |
|---|---|---|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json | %APPDATA%\Claude\claude_desktop_config.json | mcpServers | Required object |
| Cline | ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json | %APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json | mcpServers | Optional, fails silently if missing |
| Zed | ~/.config/zed/settings.json | %APPDATA%\Zed\settings.json | context_servers | Inline strings accepted |
| VS Code MCP | ~/.vscode/mcp.json | %APPDATA%\Code\User\mcp.json | servers | Explicit object required |
The schemas overlap but are not identical. Some clients fail silently if the env key is missing, even when no environment variables are needed. Others crash if the command path is relative instead of absolute.
The mcpr Install Flow
The mcpr tool collapses this into two commands:
npx -y @incultnitollc/mcpr search filesystem
npx -y @incultnitollc/mcpr install npm-agent-infra-mcp-server-filesystem --client claude-desktop
The first command queries a registry and returns a slug. The second command resolves that slug, detects the client’s config location, merges the server definition, and writes atomically with a backup.
The slug is not a free-form string. It is a registry key that resolves to a validated server definition. This prevents typos and ensures the installer knows the correct command, args, and environment variables. The article emphasizes that install without a slug errors out, because the slug is a key the registry resolves, not an argument you invent.
Five Plumbing Challenges
The article documents five implementation details that caused bugs or required careful handling.
1. npm Resolution from the Registry
The installer does not trust user input for package names. It queries the registry API to confirm the package exists, then reads the package.json to extract the actual launch command. This prevents silent failures when a user types the wrong package name.
2. Cross-OS Path Matrix
Each client has three config paths (macOS, Windows, Linux). The installer checks all three in order and uses the first that exists. If none exist, it creates the default for the current OS.
3. JSON Deep-Merge Without Clobbering
The installer reads the existing config, parses it, and merges the new server definition. The merge strategy is: if the server key already exists, prompt the user to overwrite or skip. If the mcpServers object does not exist, create it. Preserve all other top-level keys (like theme, editor, extensions).
The merge uses a recursive strategy to avoid shallow-copy bugs when clients nest server definitions under multiple keys. The implementation walks the object tree and only overwrites leaf values when the new definition provides them.
4. Atomic Writes with Backups
The installer writes to a temp file first, then renames it over the original. This prevents corruption if the process crashes mid-write. Before writing, it copies the original config to a timestamped backup file.
The backup logic maintains a rollback path if the installer breaks an existing config. This matters because a malformed config file can prevent the entire client from launching.
5. File-Mode Preservation
The first version of the installer wrote configs with 0644 permissions, which broke clients that expected 0600 (user-only read/write). The fix reads the original file mode with fs.stat, then applies it to the new file with fs.chmod.
This matters on shared systems where config files contain API keys or other secrets. If the installer accidentally makes the config world-readable, it creates a security hole. The author shipped v0.1.0 without checking existing permissions, discovered the bug when a user reported that their config became world-readable, and fixed it in v0.2.0.
Schema Normalization
Each client expects a slightly different server definition. The article mentions that some clients nest server definitions under a mcpServers key, others use servers or context_servers. Some require explicit environment variable objects, others accept inline strings. Some fail silently if the env key is missing, even when no environment variables are needed.
The installer maintains a schema map per client. When writing a server definition, it transforms the canonical registry format into the client’s expected shape. Here is one concrete transformation from registry format to Claude Desktop format:
// Registry canonical format
{
"command": "npx",
"args": ["-y", "mcp-server-filesystem"],
"env": {
"FILESYSTEM_ROOT": "/home/user/documents"
}
}
// Claude Desktop format (mcpServers key)
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "mcp-server-filesystem"],
"env": {
"FILESYSTEM_ROOT": "/home/user/documents"
}
}
}
}
// Zed format (context_servers key, env as inline string)
{
"context_servers": {
"filesystem": {
"command": "npx -y mcp-server-filesystem",
"env": "FILESYSTEM_ROOT=/home/user/documents"
}
}
}
The schema differences are not cosmetic. Some clients fail silently if the env key is missing. Others crash if the command path is relative instead of absolute. The installer handles these edge cases by validating against per-client schemas before writing.
Technical Verdict
Use mcpr if:
- Your server is stateless and fully described by a JSON fragment (command, args, environment variables)
- You want to support multiple MCP clients without writing custom installers
- Your users are developers comfortable with CLI tools
- Your server has no runtime dependencies beyond npm packages
Avoid mcpr if:
- Your server requires OAuth flows or interactive wizard-style configuration
- You need to run database migrations or custom binary compilation during installation
- Your server depends on system packages or services that must be installed separately
- You need to prompt users for secrets or API keys during setup
The file-mode bug is particularly instructive. The author shipped v0.1.0 without checking existing permissions, discovered the bug when a user reported that their config became world-readable, and fixed it in v0.2.0. This is the kind of edge case that only surfaces when you test across multiple clients and operating systems. It is also the kind of bug that would not exist if MCP had shipped with a standard installer tool.
The implementation reveals three friction points in MCP’s current state. First, the protocol spec does not define a standard config schema, so every client invents its own. Second, there is no blessed installation tool, forcing server authors to document manual JSON edits or write custom installers. Third, the file-mode preservation bug shows that config security was not considered in the initial client implementations.