Content
# mcp-safe-run
**Secure, zero-leak secrets for IDE-integrated MCP servers in under a minute.**
mcp-safe-run lets you launch Model Context Protocol (MCP) servers for AI-powered IDEs (like Cursor, Windsurf, or Claude Desktop) using secrets that are never exposed in your shell, process list, or version control. Store secrets persistently in your OS keychain or a hidden file, reference them safely in your IDE config, and launch servers with a single click—no more copy-pasting tokens or risking accidental leaks.
---
## Quick Start
1. **Install:**
```sh
npm install -g mcp-safe-run
```
2. **Create a secrets directory:**
```sh
mkdir -p ./secrets
echo "/secrets/*" >> .gitignore
```
3. **Add your secret:**
```sh
echo "ghp_...TOKEN..." > ./secrets/github_token.txt
chmod 600 ./secrets/github_token.txt
```
4. **Configure your IDE:** Add the following to your IDE's MCP server settings (e.g., `mcp_settings.json`):
```json
{
"mcpServers": {
"github": {
"command": "mcp-safe-run",
"args": [
"--target-env",
"{\"GITHUB_TOKEN\": \"file:./secrets/github_token.txt\"}",
"--",
"npx",
"-y",
"@modelcontextprotocol/server-github"
],
"env": {}
}
}
}
```
5. **Launch the server from your IDE.**
---
## Setup for IDEs (Cursor, Windsurf, Claude Desktop)
To use this project with an IDE that supports Model Context Protocol (like Cursor, Windsurf, or Claude Desktop), add an `mcpServers` section to your settings (such as `mcp_settings.json`). This enables the IDE to launch the MCP server with secure environment resolution.
**Example configuration:**
```json
{
"mcpServers": {
"github": {
"command": "mcp-safe-run",
"args": [
"--target-env",
"{\"GITHUB_TOKEN\": \"keyring:mcp-github:personal-pat\"}",
"--",
"npx",
"-y",
"@modelcontextprotocol/server-github"
],
"env": {}
}
}
}
```
### Setting Up Secrets for IDE Integration
#### Option 1: Using a Key File (`file:`)
1. Create a hidden directory for your secrets (if it doesn't exist):
```sh
mkdir -p ./secrets
```
2. Add a `.gitignore` rule to keep secrets out of version control:
```
# .gitignore
/secrets/*
```
3. Create your secret file, e.g. `./secrets/github_token.txt`, and paste your token or secret value inside.
4. Secure the file so only your user can read it:
```sh
chmod 600 ./secrets/github_token.txt
```
5. In your configuration, use a `file:` placeholder, e.g.:
```json
{ "GITHUB_TOKEN": "file:./secrets/github_token.txt" }
```
#### Option 2: Using the OS Keychain (`keyring:`) on macOS
1. Open the **Keychain Access** app (Applications > Utilities > Keychain Access).
2. Click the `+` button to add a new password item.
3. Set the **Keychain Item Name** (service) and **Account Name** (account) to match your placeholder, for example:
- Service: `mcp-github`
- Account: `personal-pat`
4. Paste your secret/token into the "Password" field and save.
5. Alternatively, you can use the `keytar` Node.js CLI or API to add secrets programmatically:
```js
// Example using keytar in Node.js
const keytar = require('keytar');
keytar.setPassword('mcp-github', 'personal-pat', 'ghp_...your_token...');
```
6. In your configuration, use a `keyring:` placeholder, e.g.:
```json
{ "GITHUB_TOKEN": "keyring:mcp-github:personal-pat" }
```
### Notes:
- The `GITHUB_TOKEN` will be securely resolved from your OS keychain using the `keyring:` placeholder.
- You may need to add the secret to your keychain using a tool like `keytar` or your OS's secret manager.
- This pattern works for any MCP server; just adjust the command and arguments as needed for your use case.
- In these IDEs, `env:` placeholders are generally not supported (the IDE does not pass your shell environment), so prefer `keyring:` or `file:` placeholders.
---
## Installation
```sh
npm install -g mcp-safe-run
```
> **Note:** This CLI uses [keytar](https://github.com/atom/node-keytar) for OS keychain support. On macOS, install Xcode Command Line Tools. On Linux, install `libsecret-1-dev` and `build-essential` (or equivalent build tools). On Windows, install Visual Studio Build Tools (`npm install --global --production windows-build-tools`).
## Usage
```sh
mcp-safe-run [options] <targetCommand> [targetArgs...]
```
### Options
- `-V, --version` Output the current version.
- `-c, --config <path>` Path to a custom configuration file (.yaml or .yml).
- `-p, --profile <name>` Name of the profile to use from the configuration file.
- `--target-env <jsonString>` JSON mapping of target environment variables. **Overrides config file profile settings.**
- `-v, --verbose` Enable verbose logging (outputs diagnostic details).
- `-h, --help` Display help information.
### Placeholder Syntax
Placeholders can be used within the `--target-env` JSON string or in the `target-env` section of a configuration file profile.
- `env:VAR_NAME` Use the value of environment variable `VAR_NAME`.
- `file:/path/to/file` Read and trim the contents of the specified file (supports `~` for home directory).
- `keyring:service:account` Retrieve a secret from the OS keychain using the specified `service` and `account`.
- *Literal values* Any other string is passed through unchanged.
## Configuration File
For managing multiple configurations, you can use a YAML configuration file (e.g., `.mcp-saferun.yaml` or `.mcp-saferun.yml`). This is particularly useful when you need to switch between different sets of environment variables frequently, such as for different deployment environments (dev, staging, production) or distinct operational contexts.
**Note on Usage Context:** For simpler scenarios, like configuring a single MCP server within an IDE integration (e.g., via `mcp.json`), using the `--target-env` flag directly might be more straightforward than managing a separate configuration file. The primary benefit of configuration files comes when managing multiple distinct configurations (profiles) for the *same* target command.
**Search Order:**
1. Path specified by `-c, --config <path>`.
2. `.mcp-saferun.yaml` or `.mcp-saferun.yml` in the current working directory.
3. `config.yaml` or `config.yml` inside `~/.config/mcp-safe-run/` (the directory is created if it doesn't exist).
**Format:**
```yaml
# Example .mcp-saferun.yaml
profiles:
# Profile name (used with -p dev)
dev:
target-env:
API_KEY: "env:DEV_API_KEY"
SECRET: "keyring:my-service:dev-user"
DB_URL: "postgresql://localhost/dev_db"
staging:
target-env:
API_KEY: "file:./staging-key.txt"
SECRET: "keyring:my-service:staging-user"
DB_URL: "env:STAGING_DB_URL"
# Global settings can be added here if needed in the future
# global:
# setting: value
```
**Precedence:**
1. Environment variables provided via `--target-env` (highest precedence).
2. Environment variables defined in the selected profile (`-p <name>`) from the configuration file.
3. Environment variables inherited from the shell where `mcp-safe-run` is executed (lowest precedence).
## Examples
1. **Using `--target-env` (CLI only):**
```sh
export GH_TOKEN_FOR_MCP=ghp_...TOKEN...
mcp-safe-run --target-env '{"GITHUB_TOKEN":"env:GH_TOKEN_FOR_MCP", "OTHER_VAR":"literal_value"}' \
npx -y @modelcontextprotocol/server-github --port 8080
```
2. **Using a Config File Profile:**
*Create `.mcp-saferun.yaml` in your project:*
```yaml
profiles:
github_server:
target-env:
GITHUB_TOKEN: "keyring:mcp:github"
PORT: "8080"
```
*Run using the profile:*
```sh
# Make sure the keychain entry exists:
# keytar set mcp github ghp_...TOKEN...
mcp-safe-run -p github_server npx -y @modelcontextprotocol/server-github
# The target command will receive GITHUB_TOKEN and PORT in its environment
```
3. **Using a Specific Config File:**
```sh
mcp-safe-run -c ~/configs/mcp-servers.yaml -p prod_server node my_server.js
```
4. **Overriding a Config Profile with `--target-env`:**
*Assume `.mcp-saferun.yaml` exists with the `github_server` profile from example 2.*
```sh
# Temporarily override the PORT defined in the profile
mcp-safe-run -p github_server --target-env '{"PORT":"9000"}' \
npx -y @modelcontextprotocol/server-github
# GITHUB_TOKEN comes from the profile (keyring), but PORT is set to 9000 by the CLI flag.
```
5. **Verbose Mode:**
```sh
mcp-safe-run -v -p github_server npx -y @modelcontextprotocol/server-github
# Shows config loading, resolved values (if verbose), final environment, etc.
```
## Troubleshooting
- **Config File Not Found:** Check search paths and file names (`.mcp-saferun.yaml`/`.yml`). Ensure correct path with `-c`. Check permissions.
- **Profile Not Found:** Verify the profile name used with `-p` exists in the loaded config file.
- **YAML Errors:** Ensure the config file is valid YAML. Use an online validator if unsure.
- **Placeholder Errors:** (`env:`, `file:`, `keyring:`)
- **`env:`**: Check if the environment variable is actually set (`echo $VAR_NAME`).
- **`file:`**: Check file path (including `~` expansion), permissions (`ls -l`), and content (`cat`).
- **`keyring:`**: Verify the secret exists in the OS keychain (use OS tools or `keytar` CLI if installed). Ensure `keytar` prerequisites are met.
- **`keytar` Build/Runtime Issues:** Check platform notes below and ensure necessary build tools/libraries are installed.
- **Invalid JSON (`--target-env`):** Ensure proper quoting, especially when used in a shell.
- **Unsupported Placeholder (`env:`) in Some Clients (Cursor, Windsurf, Claude Desktop):** These environments don't pass shell environment variables to `mcp-safe-run`, so `env:` placeholders won't resolve. `file:` and `keyring:` placeholders still work. For example:
```sh
mcp-safe-run --target-env '{"API_KEY":"file:./api_key.txt","SECRET":"keyring:my-service:account","DB_URL":"file:./db_url.txt"}' <targetCommand> [args...]
```
## Platform Notes
- **macOS:** Requires Xcode Command Line Tools.
- **Linux:** Requires `libsecret-1-dev` and build tools like `build-essential`.
- **Windows:** Requires Visual Studio Build Tools (can be installed via `npm install --global --production windows-build-tools`).
---
## Setup for IDEs (Cursor, Windsurf, Claude Desktop)
To use this project with an IDE that supports Model Context Protocol (like Cursor, Windsurf, or Claude Desktop), add an `mcpServers` section to your settings (such as `mcp_settings.json`). This enables the IDE to launch the MCP server with secure environment resolution.
**Example configuration:**
```json
{
"mcpServers": {
"github": {
"command": "mcp-safe-run",
"args": [
"--target-env",
"{\"GITHUB_TOKEN\": \"keyring:mcp-github:personal-pat\"}",
"--",
"npx",
"-y",
"@modelcontextprotocol/server-github"
],
"env": {}
}
}
}
```
### Setting Up Secrets for IDE Integration
#### Option 1: Using a Key File (`file:`)
1. Create a hidden directory for your secrets (if it doesn't exist):
```sh
mkdir -p ./secrets
```
2. Add a `.gitignore` rule to keep secrets out of version control:
```
# .gitignore
/secrets/*
```
3. Create your secret file, e.g. `./secrets/github_token.txt`, and paste your token or secret value inside.
4. Secure the file so only your user can read it:
```sh
chmod 600 ./secrets/github_token.txt
```
5. In your configuration, use a `file:` placeholder, e.g.:
```json
{ "GITHUB_TOKEN": "file:./secrets/github_token.txt" }
```
#### Option 2: Using the OS Keychain (`keyring:`) on macOS
1. Open the **Keychain Access** app (Applications > Utilities > Keychain Access).
2. Click the `+` button to add a new password item.
3. Set the **Keychain Item Name** (service) and **Account Name** (account) to match your placeholder, for example:
- Service: `mcp-github`
- Account: `personal-pat`
4. Paste your secret/token into the "Password" field and save.
5. Alternatively, you can use the `keytar` Node.js CLI or API to add secrets programmatically:
```js
// Example using keytar in Node.js
const keytar = require('keytar');
keytar.setPassword('mcp-github', 'personal-pat', 'ghp_...your_token...');
```
6. In your configuration, use a `keyring:` placeholder, e.g.:
```json
{ "GITHUB_TOKEN": "keyring:mcp-github:personal-pat" }
```
### Notes:
- The `GITHUB_TOKEN` will be securely resolved from your OS keychain using the `keyring:` placeholder.
- You may need to add the secret to your keychain using a tool like `keytar` or your OS's secret manager.
- This pattern works for any MCP server; just adjust the command and arguments as needed for your use case.
- In these IDEs, `env:` placeholders are generally not supported (the IDE does not pass your shell environment), so prefer `keyring:` or `file:` placeholders.
---
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
Time
A Model Context Protocol server for time and timezone conversions.