mcp server
mcp-keyring-injector
Session-scoped MCP credential security - keys auto-injected at startup, auto-removed at exit, zero config file exposure
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 21, 2026MCP Keyring Injector
Session-scoped credential management for Claude Code MCP servers. API keys are automatically injected from your OS keyring at startup and removed at exit - credentials exist in config files only while Claude Code runs.
The Problem
MCP servers in Claude Code require API keys in their environment configuration (~/.claude.json). Storing API keys in config files is a security risk:
- Keys are in plaintext on disk
- Easy to accidentally commit to git
- Shared across all projects
- Hard to rotate without editing configs
The Solution
This plugin solves the problem by:
- Storing API keys in your system keyring (encrypted)
- Dynamically injecting them into
~/.claude.jsonwhen Claude Code starts (SessionStart hook) - Automatically removing them when the session ends (SessionEnd hook)
- Working cross-platform (Linux, macOS, Windows)
Keys exist in config files only while Claude Code is running - true session-scoped security!
Features
- Secure: Keys stored encrypted in system keyring
- Cross-platform: Works on Linux (GNOME Keyring), macOS (Keychain), Windows (Credential Manager)
- Automatic: Runs on every Claude Code session start
- Flexible: Configure multiple MCP services from one file
- Minimal overhead: Negligible performance impact on session startup
Installation
1. Install the plugin
# Via Claude Code plugin system
/plugin marketplace add astrogilda/claude-plugins
/plugin install mcp-keyring-injector
# Or manually
git clone https://github.com/astrogilda/mcp-keyring-injector.git ~/Documents/mcp-keyring-injector
2. Install Python dependencies
uv pip install keyring
3. Store your first API key
Choose your platform:
Linux (GNOME Keyring):
python3 -c "import keyring; keyring.set_password('github', 'api-key', 'YOUR_API_KEY')"
macOS (Keychain):
security add-generic-password -s github -a api-key -w YOUR_API_KEY
Windows (PowerShell):
cmdkey /generic:github /user:api-key /pass:YOUR_API_KEY
4. Configure MCP credentials
Create ~/.claude/config/mcp-credentials.json:
{
"github": {
"env_var": "GITHUB_TOKEN",
"service": "github",
"account": "api-key",
"label": "GitHub API Token",
"mcp_server": "github-mcp"
}
}
See examples/mcp-credentials.json for more examples.
5. Verify it works
Restart Claude Code. You should see:
MCP credentials - Injected: GitHub API Token
Check your GitHub MCP tools are now available!
Upgrading from v1.0.0
If you're upgrading from v1.0.0, here's what changed in v1.1.0:
What's New
- SessionEnd cleanup hook: Credentials are now automatically removed when Claude Code exits
- Session-scoped security: Keys only exist in
~/.claude.jsonwhile Claude is running - Enhanced status messages: Better feedback on cleanup operations
Migration Steps
-
Update the plugin (automatic if using plugin marketplace):
/plugin update mcp-keyring-injector -
One-time cleanup - Remove old credentials from config (they won't auto-cleanup):
# Backup first cp ~/.claude.json ~/.claude.json.backup # Remove credentials manually from ~/.claude.json env sections # Or let them be removed on next session start -
No config changes needed - Your
mcp-credentials.jsonformat remains the same
Breaking Changes
- None! This is a fully backwards-compatible security enhancement
What Happens After Upgrade
- Next session: Credentials injected at start (as before)
- New behavior: Credentials automatically removed at session end
- Keys always remain safe in your system keyring
Configuration
Config File Format
~/.claude/config/mcp-credentials.json:
{
"service-name": {
"env_var": "ENVIRONMENT_VARIABLE_NAME",
"service": "keyring-service-name",
"account": "keyring-account-name",
"label": "Human Readable Label",
"mcp_server": "mcp-server-name-in-claude.json"
}
}
Fields:
env_var: Environment variable the MCP server expects (e.g.,GITHUB_TOKEN)service: Keyring service name (how you stored the key)account: Keyring account/username (how you stored the key)label: Display name in status messagesmcp_server: MCP server name from~/.claude.json(defaults to service-name if omitted)
Adding Multiple Services
{
"github": {
"env_var": "GITHUB_TOKEN",
"service": "github",
"account": "api-key",
"label": "GitHub API Token",
"mcp_server": "github-mcp"
},
"openai": {
"env_var": "OPENAI_API_KEY",
"service": "openai",
"account": "api-key",
"label": "OpenAI API Key",
"mcp_server": "openai-mcp"
}
}
How It Works
Claude Code Session Start
|
SessionStart hook triggered
|
Read ~/.claude/config/mcp-credentials.json
|
For each service:
|-- Retrieve API key from system keyring
|-- Inject into ~/.claude.json MCP server env
+-- Report success/failure
|
Claude Code continues startup
|
MCP servers start with injected credentials
|
[... Claude Code session runs ...]
|
Claude Code Session End
|
SessionEnd hook triggered
|
Read ~/.claude/config/mcp-credentials.json
|
For each service:
|-- Remove API key from ~/.claude.json MCP server env
+-- Report cleanup status
|
Keys removed from config
|
Keys remain only in system keyring
Security Considerations
What This Protects Against
- [YES] API keys in plaintext config files
- [YES] Accidental git commits of secrets
- [YES] Unauthorized file access (keyring requires user authentication)
- [YES] Session-scoped security (v1.1.0+): Keys automatically removed when Claude Code exits
What This Doesn't Protect Against
- [NO] Malicious code with your user permissions (can access keyring)
- [NO] Physical access to unlocked machine
- [NO] Memory dumps while Claude Code is running
Best Practices
- Use unique API keys per machine
- Rotate keys regularly
- Use least-privilege API keys (read-only when possible)
- Don't share
~/.claude/config/mcp-credentials.json(it's not secret, but lists your services)
Troubleshooting
"MCP credentials - Failed: X (not in keyring)"
The key isn't stored in your system keyring.
Solution:
python3 -c "import keyring; keyring.set_password('service', 'account', 'YOUR_KEY')"
"MCP credentials - Failed: X (MCP server 'Y' not found)"
The MCP server name doesn't match what's in ~/.claude.json.
Solution: Check your MCP server name:
jq '.mcpServers | keys' ~/.claude.json
Update mcp_server field in config to match.
"ERROR: keyring library not installed"
Python keyring library is missing.
Solution:
uv pip install keyring
Hook runs but tools still unavailable
Check MCP server logs:
ls ~/.cache/claude-cli-nodejs/*/mcp-logs-*/
cat ~/.cache/claude-cli-nodejs/*/mcp-logs-github-mcp/*.txt
Look for errors about missing API keys.
Development
Project Structure
mcp-keyring-injector/
.claude-plugin/
+-- plugin.json # Plugin metadata
hooks/
+-- hooks.json # Hook configuration
+-- inject-credentials.py # SessionStart hook
+-- remove-credentials.py # SessionEnd hook (v1.1.0+)
examples/
+-- mcp-credentials.json # Example config
docs/
+-- SECURITY.md # Security considerations
CHANGELOG.md # Version history
README.md
LICENSE
Testing Locally
# Test the hook directly
echo '{}' | ~/Documents/claude-mcp-credentials/hooks/inject-credentials.py
# Check if keys were injected
jq '.mcpServers."github-mcp".env' ~/.claude.json
Contributing
Contributions welcome! Please:
- Fork the repo
- Create a feature branch
- Add tests for new functionality
- Ensure code passes black + ruff
- Submit PR with clear description
License
MIT License - see LICENSE file for details.
Credits
Created by @astrogilda
Uses the excellent keyring library by Jason R. Coombs.