Securing Your AI Toolkit: MCP Version Control Strategy
How security-first thinking shaped my approach to managing AI development tools and MCP server version control to prevent potential disasters.
Securing Your AI Toolkit: MCP Version Control Strategy
How a security-first approach to MCP server management prevented potential disasters
When Model Context Protocol (MCP) emerged in late 2024, it felt like the Wild West. Powerful new capabilities, rapid community development, and the usual early-adopter trade-offs between innovation and stability. Having watched the evolution of package managers and open-source ecosystems, I knew that a security-first approach would be essential from day one.
The MCP Security Landscape
Understanding the Risk Surface
MCP servers run with significant privileges:
- File System Access: Most MCP servers can read and write files across your development environment
- Network Access: Many servers make external API calls with your credentials
- Process Execution: Terminal and command-line MCPs can execute arbitrary commands
- Data Access: Database MCPs connect to your production and development systems
Unlike traditional package dependencies that run in more constrained environments, MCP servers operate with the full privileges of your development environment. This makes security considerations paramount.
The Convenience vs Security Tension
The easiest way to install MCP servers is using npx
to download and run them on-demand:
npx @modelcontextprotocol/server-filesystem ~/Documents
This approach offers:
- Immediate gratification: Install and run any MCP server instantly
- Automatic updates: Always get the latest version
- Low maintenance: No local installation management
But it also creates significant security risks:
- Supply chain attacks: Compromised packages could execute malicious code
- Version instability: Automatic updates might break your workflows
- Network dependencies: Can’t work offline or in restricted environments
- Audit difficulties: Hard to track what code actually ran
The Local Installation Philosophy
After evaluating the trade-offs, I adopted a strict local installation strategy for all MCP servers. Here’s how and why:
Version Pinning Strategy
Instead of npx
downloads, I install specific versions locally:
# Instead of: npx @modelcontextprotocol/server-filesystem
# Do this:
npm install -g @modelcontextprotocol/server-filesystem@1.0.2
Benefits:
- Reproducible environments: Exact same versions across all development machines
- Change control: Updates happen deliberately, not automatically
- Offline capability: Can work without internet access
- Security review: Can audit specific versions before adoption
The Local MCP Registry
I maintain a controlled registry of approved MCP servers:
~/Workspace/tools/mcp/
├── approved-mcps.json # Registry of vetted servers
├── install-approved-mcps.sh # Batch installation script
├── version-lock.json # Exact version pins
└── security-audit.md # Security review notes
The approval process for new MCPs:
- Security review: Code inspection for obvious red flags
- Provenance check: Verify author and maintenance status
- Test installation: Install and test in isolated environment
- Version pinning: Lock to specific, tested version
- Documentation: Record security considerations and update procedures
Wrapper Scripts for Problematic Servers
Some MCP servers had issues that required custom solutions. Rather than abandoning them, I created wrapper scripts:
Example: SQLite MCP Path Issues The SQLite MCP had path resolution problems. Instead of hoping for upstream fixes, I created a wrapper:
#!/bin/bash
# fix-sqlite-mcp-path.sh
export SQLITE_DB_PATH="/absolute/path/to/database.db"
exec node /usr/local/lib/node_modules/mcp-server-sqlite/dist/index.js "$@"
This approach provided:
- Immediate problem resolution: Don’t wait for upstream fixes
- Custom configuration: Tailor servers to specific environments
- Debugging capability: Add logging and error handling
- Transition strategy: Easy to remove wrappers when upstream fixes arrive
Provider Hierarchy: Trust-Based Decision Making
Not all MCP servers are created equal. I developed a provider hierarchy based on trust and maintenance quality:
Tier 1: First-Party Providers
Highest Trust: MCPs maintained by the service provider themselves
- Azure MCP by Microsoft: Official Microsoft implementation
- Notion MCP by Notion: Direct from Notion’s team
- GitHub MCP by GitHub: Official GitHub tooling
Why Tier 1 matters:
- Aligned incentives: Providers have strong motivation to maintain quality
- Security resources: Large companies have dedicated security teams
- Support responsibility: Clear ownership when issues arise
- API compatibility: Most likely to stay current with API changes
Tier 2: Official MCP Repositories
High Trust: MCPs in official repositories with clear governance
- @modelcontextprotocol/server-*: Official MCP implementations
- Community-maintained servers with MCP organization oversight
Evaluation criteria:
- Consistent commit history
- Multiple contributors
- Clear documentation
- Security-conscious development practices
Real-World Security Incidents
The Malformed JSON Incident
One of my local MCP servers started producing malformed JSON responses after a system sleep/wake cycle. This could have been a sign of compromise, but investigation revealed:
- Root cause: Memory corruption after system suspend
- Solution: MCP server restart protocols
- Prevention: Systematic restart procedures after system wake
This incident validated the local installation approach - I could quickly isolate and analyze the problem without worrying about upstream package modifications.
The Dependency Confusion Attempt
While monitoring npm packages, I noticed a suspicious package with a similar name to a legitimate MCP server:
- Legitimate:
@modelcontextprotocol/server-github
- Suspicious:
@model-context-protocol/server-github
(note the hyphens)
This typosquatting attempt reinforced the importance of:
- Careful package name verification
- Official repository preference
- Local installation for audit capability
Lessons Learned
Security Pays Dividends
The extra effort in security-conscious MCP management paid off:
- Zero security incidents: No compromised servers or data breaches
- Stable development environment: Predictable behavior from known versions
- Faster debugging: Known configurations made troubleshooting easier
- Audit capability: Could verify what code was actually running
Balance Pragmatism with Security
The strategy evolved to balance security with productivity:
- Quick experimentation: Isolated test environment for trying new MCPs
- Graduated trust: Move promising servers through trust tiers over time
- Community engagement: Contribute back to improve security practices
Key Takeaways
- Local installation provides control and security over convenience and automatic updates
- Provider hierarchy helps make trust-based decisions about which MCPs to adopt
- Wrapper scripts solve immediate problems without waiting for upstream fixes
- Security monitoring must be proactive, not reactive
- Documentation prevents configuration drift and preserves security rationale
Implementation Checklist
- Establish local installation procedures for all MCP servers
- Define provider trust hierarchy for your organization
- Create version pinning and update control processes
- Implement security monitoring and audit procedures
- Document security decisions and rationale
- Create backup and recovery procedures for MCP configurations
Next in this series: “When AI Tools Talk to Each Other: Multi-LLM Integration Lessons” - Real-world challenges of orchestrating multiple AI services and the surprising overhead of context translation.
Written by Dean Keesey