A local stdio process that sits in front of the hosted /mcp connector (see the API Reference). It reads your API key from a gitignored .env.local file and forwards every call to the live server over MCP itself, so the key only ever lives in a file, never in .mcp.json or a shell environment variable. This is what's behind the .mcp.json example on the API Reference page.
In a folder of your choosing, not necessarily inside the project you'll use it from, create package.json:
{
"name": "cheatsheet-mcp-proxy",
"version": "1.0.0",
"private": true,
"type": "commonjs",
"main": "live-proxy.js",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.0"
}
}
And live-proxy.js next to it:
#!/usr/bin/env node
// Local stdio MCP proxy in front of the hosted /mcp Streamable HTTP connector.
//
// Why this exists: a "type": "http" .mcp.json entry can only fill a header value from a real
// environment variable already set before Claude Code starts (${VAR} expansion) - there's no
// built-in way for an http-type entry to read an API key out of a gitignored .env.local file
// itself. This script loads .env.local itself, then transparently forwards every request to the
// live server over MCP itself (not a REST re-implementation), so the key only ever has to live in
// a file, never in .mcp.json or a shell environment variable.
const fs = require('fs');
const path = require('path');
const { Client } = require('@modelcontextprotocol/sdk/client/index.js');
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
const { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
function loadEnvLocal(filePath) {
if (!fs.existsSync(filePath)) return {};
const vars = {};
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const eq = trimmed.indexOf('=');
if (eq === -1) continue;
const key = trimmed.slice(0, eq).trim();
let value = trimmed.slice(eq + 1).trim();
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
vars[key] = value;
}
return vars;
}
const envFilePath = process.env.CHEATSHEET_ENV_FILE
? path.resolve(process.env.CHEATSHEET_ENV_FILE)
: path.join(__dirname, '.env.local');
const envLocal = loadEnvLocal(envFilePath);
const LIVE_MCP_URL = envLocal.CHEATSHEET_LIVE_MCP_URL || process.env.CHEATSHEET_LIVE_MCP_URL || 'https://cheats.aarontrotter.com/mcp';
const API_KEY = envLocal.CHEATSHEET_API_KEY || process.env.CHEATSHEET_API_KEY;
if (!API_KEY) {
console.error(`CHEATSHEET_API_KEY is not set - add it to ${envFilePath}.`);
process.exit(1);
}
async function main() {
const remoteClient = new Client({ name: 'cheatsheet-live-proxy', version: '1.0.0' });
const remoteTransport = new StreamableHTTPClientTransport(new URL(LIVE_MCP_URL), {
requestInit: { headers: { Authorization: `Bearer ${API_KEY}` } }
});
await remoteClient.connect(remoteTransport);
const localServer = new Server({ name: 'cheatsheet', version: '1.0.0' }, { capabilities: { tools: {} } });
localServer.setRequestHandler(ListToolsRequestSchema, () => remoteClient.listTools());
localServer.setRequestHandler(CallToolRequestSchema, (request) => remoteClient.callTool(request.params));
const localTransport = new StdioServerTransport();
await localServer.connect(localTransport);
}
main().catch((error) => {
console.error('Fatal error running cheatsheet live MCP proxy:', error);
process.exit(1);
});
Then install dependencies:
npm install
Sign in and go to the User page's API Access section to generate a key, scoped read-only or read + write depending on what you want the client to be able to do.
Next to live-proxy.js (or anywhere else, referenced by path via CHEATSHEET_ENV_FILE below), create a .env.local file:
CHEATSHEET_API_KEY=csk_live_...
Make sure this file is gitignored wherever you keep it, since it holds the key in plain text.
In the project you want to use this from, add to that project's own .mcp.json:
{
"mcpServers": {
"cheatsheet": {
"command": "node",
"args": ["/path/to/live-proxy.js"],
"env": {
"CHEATSHEET_ENV_FILE": "/path/to/.env.local"
}
}
}
}
CHEATSHEET_ENV_FILE is just a path, not a secret, so this file is safe to commit. Point it at wherever you saved .env.local, using an absolute path or one relative to the project's own root. Without this variable it defaults to .env.local next to live-proxy.js itself.
Restart Claude Code (or start a new session) and approve the cheatsheet server when prompted.
The proxy defaults to https://cheats.aarontrotter.com/mcp. Set CHEATSHEET_LIVE_MCP_URL (in the same .env.local, or as a real environment variable) to point it elsewhere if that ever changes.