A lightweight MCP router that connects AI tools (Claude Desktop, Cursor, VS Code) to other MCP servers. It handles OAuth locally and forwards requests to downstream MCPs. It does NOT implement API-specific MCP tool wrappers itself.
Scope clarification: This projectβs responsibility is routing and auth. If you need API-specific tools (e.g., Gmail, Calendar, GitHub issues), run those as separate MCP servers and point mcp-switch at them. Avoid adding direct API wrappers here to prevent duplication and scope creep.
# 1. Clone and install
git clone https://github.com/BlueprintDesignLab/mcp-switch
cd mcp-switch
npm install
# 2. Authenticate with providers (opens browser)
npm run auth:google
npm run auth:github
npm run auth:slack
# 3. Start the gateway
npm start
# Server running on http://localhost:8042
# 4. Configure your AI client (see below)
That's it! No OAuth app creation, no credential downloads, no complex configuration.
- Single Gateway: Route requests from clients to one or more downstream MCP servers
- OAuth Automation: Handles token refresh, PKCE flows, provider quirks (for MCPs that require OAuth)
- Local & Private: All tokens stored encrypted on your machine
- Multi-Client: Multiple AI clients share the same server instance
- Out of scope: Implementing API-specific MCP tools; build or reuse dedicated MCP servers for that purpose
Claude Desktop βββ
βββ HTTP βββΆ MCP Switch (this repo) βββΆ Downstream MCP servers
VS Code βββββ€ (localhost:8042) (e.g., Gmail MCP, GitHub MCP)
β
Cursor βββββ
{
"@modelcontextprotocol/sdk": "^1.0.0",
"express": "^4.18.0",
"googleapis": "^131.0.0",
"@octokit/rest": "^20.0.0",
"@slack/web-api": "^7.0.0",
"@notionhq/client": "^2.2.0",
"open": "^10.0.0"
}
- Google: Calendar, Gmail, Drive APIs (read-only by default)
- GitHub: Repositories, Issues, Profile (public data + authorized private)
- Slack: Channels, Messages, Files (workspace you authorize)
- Notion: Databases, Pages (pages you share with the integration)
- Node.js 18+ (for ES modules and native fetch)
- macOS/Linux/Windows (cross-platform)
- Port 8042 available (configurable)
Use the included auth scripts only to obtain local tokens required to reach downstream MCP servers that rely on OAuth. Do not add direct API functionality here.
npm run auth:google
# Opens browser β Sign in β Allow permissions β Done!
npm run auth:github
# Opens browser β Sign in β Allow permissions β Done!
If a providerβs functionality is desired, run or install its dedicated MCP server and configure mcp-switch to route to it.
// ~/.config/claude-desktop/config.json
{
"mcpServers": {
"oauth-gateway": {
"url": "http://localhost:8042"
}
}
}
// settings.json
{
"mcp.servers": {
"oauth-gateway": {
"url": "http://localhost:8042"
}
}
}
- Asset: OAuth access/refresh tokens for your connected services
- Boundary: Your local machine (trusted environment)
- Risks: Token theft via malware, accidental exposure, token replay
// tokens.json is encrypted at rest
{
"google": {
"encrypted": "a1b2c3d4...",
"iv": "random_iv",
"authTag": "auth_tag"
}
}
// RFC 7636 - prevents authorization code interception
const codeChallenge = crypto
.createHash('sha256')
.update(randomCodeVerifier)
.digest('base64url');
// Request only necessary permissions
const googleScopes = [
'https://www.googleapis.com/auth/calendar.readonly',
'https://www.googleapis.com/auth/drive.readonly'
// NO write permissions by default
];
// Refresh tokens before expiry
if (token.expires_at - Date.now() < 5 * 60 * 1000) {
await refreshToken();
}
chmod 600 tokens.json # Owner read/write only
chmod 700 config/ # Owner access only
# Never commit secrets to git
echo "tokens.json" >> .gitignore
echo ".env" >> .gitignore
# Port 8042 already in use
# Fix: Use different port
PORT=8043 npm start
# Server won't start
# Check: Node.js version
node --version # Should be 18+
# "Browser didn't open"
# Fix: Manual browser navigation
npm run auth:google --manual
# "Token expired"
# Fix: Re-authenticate with provider
npm run auth:google
# Claude can't connect
# Check: Server is running
curl http://localhost:8042/health
# Should return: {"status": "ok"}
MCP Client ββHTTP/SSEβββΆ MCP Switch (router) ββHTTP/SSEβββΆ Downstream MCP servers
(Claude/Cursor/VS Code) (Express) (e.g., Gmail MCP, GitHub MCP)
- MCP Client calls tool via HTTP POST to
/message
- Gateway validates request and checks tokens
- OAuth Logic refreshes expired tokens automatically
- Provider API called with valid Bearer token
- Response streamed back via Server-Sent Events
- Initial Auth: User runs
npm run auth:google
β browser OAuth flow - Token Storage: Access/refresh tokens encrypted locally
- Auto-Refresh: Tokens refreshed automatically before expiry
- Shared Instance: All MCP clients use same server and tokens
src/
βββ server.js # Express server + MCP SSE transport
βββ providers/
β βββ google.js # Google OAuth + API integration
β βββ github.js # GitHub OAuth + API integration
β βββ base.js # Shared provider interface
βββ oauth/
β βββ manager.js # OAuth flow orchestration
β βββ storage.js # Encrypted token storage
β βββ pkce.js # PKCE implementation
βββ tools/
βββ registry.js # MCP tool registration
npm start # Start server (production)
npm run dev # Start with hot reload
npm run test # Run test suite
- Add routing targets for downstream MCP servers; do not add direct API wrappers.
- Expose configuration to map tool namespaces to external MCP endpoints.
- Keep OAuth handling limited to whatβs required to reach those MCPs.
MIT License - see LICENSE for details.
- Fork the repository
- Create feature branch:
git checkout -b feature/new-provider
- Add tests:
npm run test
- Submit pull request
This is a development tool for personal use. Review the code before using with sensitive data. Each OAuth provider has its own terms of service that you must follow.