A lazy proxy for MCP (Model Context Protocol) servers over stdio. It defers starting the real server until a tool is actually called, serving discovery responses from a local cache in the meantime.
When an agent connects to an MCP server, it immediately starts the server process and queries its capabilities (initialize, tools/list, resources/list, prompts/list). This happens for every configured server, even if none of their tools are ever used during the session.
For setups with many MCP servers this means:
- Wasted resources — every server process runs for the entire session, consuming memory and CPU, even if never used.
- Slow startup — the agent blocks while each server initializes. Servers that pull dependencies (e.g.
uvx,npx) or connect to external services can take seconds each. - Unnecessary network traffic — servers that authenticate against APIs or fetch remote schemas do so eagerly, even when not needed.
lazy-mcp solves this by caching discovery responses and only starting the real server when a non-discovery request (like tools/call) arrives.
sequenceDiagram
participant Agent
participant lazy-mcp
participant Server as Real MCP Server
Note over lazy-mcp,Server: Server not started
Agent->>lazy-mcp: initialize
lazy-mcp-->>Agent: (from cache)
Agent->>lazy-mcp: tools/list
lazy-mcp-->>Agent: (from cache)
Agent->>lazy-mcp: tools/call
Note over lazy-mcp,Server: Starting server
lazy-mcp->>Server: initialize
lazy-mcp->>Server: tools/list
lazy-mcp->>Server: tools/call
Server-->>lazy-mcp: result
lazy-mcp-->>Agent: result
Note over Agent,Server: Bidirectional proxy from here on
On the first run (no cache), lazy-mcp proxies transparently and builds the cache. On subsequent runs, discovery responses are served instantly from cache — the real server is never started unless a tool is actually called.
Download a prebuilt binary (auto-detects OS and architecture):
curl -fsSL https://raw.githubusercontent.com/tkukushkin/lazy-mcp/master/install.sh | shOn Windows (PowerShell):
irm https://raw.githubusercontent.com/tkukushkin/lazy-mcp/master/install.ps1 | iexgo install github.com/tkukushkin/lazy-mcp@latestOr run without installing:
go run github.com/tkukushkin/lazy-mcp@latest -- uvx some-mcp-servergit clone https://github.com/tkukushkin/lazy-mcp.git
cd lazy-mcp
go build -o lazy-mcp .Wrap any MCP server command with lazy-mcp --:
Instead of:
{
"mcpServers": {
"some-server": {
"command": "uvx",
"args": ["some-mcp-server", "--arg1", "--arg2"]
}
}
}If your MCP server needs credentials (API tokens, passwords, etc.), you can use secret-box to inject them as environment variables. Combined with lazy-mcp, Touch ID confirmation will only be triggered when a tool is actually called — not at agent startup:
{
"mcpServers": {
"some-server": {
"command": "lazy-mcp",
"args": [
"--", "secret-box", "exec",
"-e", "API_TOKEN=some-server-token",
"--", "uvx", "some-mcp-server"
]
}
}
}Without lazy-mcp, the server would start immediately on agent launch, prompting for Touch ID even if none of its tools are ever used during the session.
Discovery responses are cached in the OS cache directory:
| OS | Path |
|---|---|
| macOS | ~/Library/Caches/lazy-mcp/ |
| Linux | ~/.cache/lazy-mcp/ |
| Windows | %LOCALAPPDATA%\lazy-mcp\ |
Each MCP server command gets its own cache file, keyed by a SHA-256 hash of the full command and arguments.
To clear the cache for all servers:
lazy-mcp clear-cacheThe cache is updated every time the real server is started, so it stays fresh automatically.
Set LAZY_MCP_CACHE_DIR to use a custom cache location:
LAZY_MCP_CACHE_DIR=/tmp/mcp-cache lazy-mcp -- uvx some-serverlazy-mcp is a single static binary with no external dependencies. It uses only the Go standard library.
MIT