Any MCP host
stretto works with any MCP host that starts servers over stdio, which is how desktop apps, IDEs and agent frameworks run local servers. The change is always the same: in the host's configuration, replace the server's command with stretto-proxy, and put the server's command after --.
stretto init prints it
For Claude Code, Claude Desktop, Cursor and VS Code, stretto init prints the configuration in the host's own format. Give it the host, a name for the server, and the server's command after --:
stretto init --host cursor --domain orders -- npx -y some-mcp-serverIt prints (its arguments wrapped here):
{
"mcpServers": {
"orders": {
"command": "stretto-proxy",
"args": ["--record", "~/.stretto/logs/orders", "--domain", "orders",
"--", "npx", "-y", "some-mcp-server"]
}
}
}--hostisclaude-code,claude-desktop,cursororvscode. The configuration goes to stdout; where it goes, and the next steps, go to stderr.--domain NAMEis the server's name in the host, and the domain of its sessions and flows. The proxy records sessions in~/.stretto/logs/NAME, or where--record DIRsays.--write PATHwrites the configuration file instead of printing it. It leaves an existing file alone unless you add--force, which replaces the whole file, with any other servers in it; to add a server to a file that has others, merge the printed configuration by hand.- A server program named by a relative path is written with its absolute path, since the host starts servers in a directory of its own choosing.
init writes no env block. If the server needs environment variables, add them to its entry as before: the server inherits the proxy's environment. Every option is in the CLI reference.
In the console
The console's page for a server shows the same configuration for each host, from a registry of your servers. It also tests the connection, listing the server's tools as they are now.
Per host
| Host | --host | What init prints | Page |
|---|---|---|---|
| Claude Code | claude-code | a claude mcp add command; with --write .mcp.json, the project's file | Claude Code |
| Claude Desktop | claude-desktop | JSON for claude_desktop_config.json, with the proxy's full path | Claude Desktop |
| Cursor | cursor | JSON for ~/.cursor/mcp.json or .cursor/mcp.json | Cursor and VS Code |
| VS Code | vscode | JSON for .vscode/mcp.json, or the user mcp.json | Cursor and VS Code |
| A server reached over HTTP | none | write the entry by hand, with --upstream URL in place of the command | Streamable HTTP servers |
| A framework that exports OpenTelemetry spans | none | nothing to configure for learning: stretto learn --otel reads the export | OpenTelemetry spans |
In any other host, write the entry by hand. Before:
{
"mcpServers": {
"orders": {
"command": "npx",
"args": ["-y", "some-mcp-server"],
"env": { "SOME_API_KEY": "…" }
}
}
}After:
{
"mcpServers": {
"orders": {
"command": "stretto-proxy",
"args": ["--record", "~/.stretto/logs/orders", "--domain", "orders",
"--", "npx", "-y", "some-mcp-server"],
"env": { "SOME_API_KEY": "…" }
}
}
}The host still sees a stdio MCP server with the same tools.
The three stages
A deployment moves through three configurations, and stretto init prints each. Only the proxy's arguments change; the server's command after -- stays the same.
1. Record. Log sessions to learn from:
stretto init --host cursor --domain orders -- npx -y some-mcp-server"args": ["--record", "~/.stretto/logs/orders", "--domain", "orders",
"--", "npx", "-y", "some-mcp-server"]Then learn a flow and review it:
stretto learn --sessions ~/.stretto/logs/orders --domain orders \
--habit-only --out ~/.stretto/orders.flow.json
stretto flow-show ~/.stretto/orders.flow.json2. Shadow. Serve the flow so that it decides and logs, but makes no lookups (shadow mode):
stretto init --host cursor --domain orders \
--flow ~/.stretto/orders.flow.json --shadow \
-- npx -y some-mcp-server"args": ["--record", "~/.stretto/shadow/orders", "--domain", "orders",
"--flow", "/home/me/.stretto/orders.flow.json",
"--flow-decider", "reach", "--flow-shadow",
"--", "npx", "-y", "some-mcp-server"]Then keep the flow to the calls where its lookups were the agent's own:
stretto promote --flow ~/.stretto/orders.flow.json \
--sessions ~/.stretto/shadow/orders \
--out ~/.stretto/orders-promoted.flow.json3. Serve. Let the promoted flow act:
stretto init --host cursor --domain orders \
--flow ~/.stretto/orders-promoted.flow.json \
-- npx -y some-mcp-server"args": ["--record", "~/.stretto/logs/orders", "--domain", "orders",
"--flow", "/home/me/.stretto/orders-promoted.flow.json",
"--flow-decider", "reach",
"--", "npx", "-y", "some-mcp-server"]A flow learned with --habit-only has no arbiter, so init serves it with the reach decider (--flow-decider reach), which asks no model and needs no key (deciders). A flow with an arbiter is served with it, and init reminds you that the server then needs TYPESAFE_API_KEY in its env. To name the only tools the flow may call on its own, add --flow-tools to args by hand, or set it on the server in the console, whose configuration for each host includes it (lookups).
One proxy for every host
Each host above starts its own proxy over stdio. With --listen, init sets up one proxy that every host connects to by URL, over Streamable HTTP (hosts that connect by URL):
stretto init --host claude-code --domain orders --listen 127.0.0.1:8931 -- npx -y some-mcp-serverIt prints the host's configuration by URL, claude mcp add --transport http orders http://127.0.0.1:8931/mcp here, and its next steps start with the command that runs the proxy; keep it running. Each change after that, such as serving a flow, restarts the proxy, and leaves the host's configuration as it is.
- Beyond loopback, a token. Without
--listen-token-file FILE,initrefuses an address other than loopback, as the proxy does. With it, each host sends the token asAuthorization: Bearer: Claude Code reads it from the file when you runclaude mcp add, and the JSON configurations read it fromSTRETTO_PROXY_TOKEN, which you set to the token in the host's environment. - Every address. A proxy listening on
0.0.0.0is at127.0.0.1for this machine; a host on another one puts this machine's name in the URL. - Claude Desktop starts its servers as commands, so its configuration still starts a proxy of its own, over stdio.
The console sets the same on a server, under How hosts connect (the console).
What to watch for
- Paths. Hosts start servers without a shell. The proxy expands a leading
~in its own path options (--record,--flow,--context,--flow-log,--confirm-log,--oracle-cache), but the server's arguments after--are passed as written: give them as absolute paths. - Finding the program. Some hosts do not see your shell's
PATH.initwritesstretto-proxy's full path for Claude Desktop, which starts servers with a minimalPATH. If another host cannot start it, use its full path too, fromwhich stretto-proxy; the same goes fornpxor the server's own command. - Credentials. Put them in
env, not inargs. The proxy never records its environment; it replaces credential-looking arguments in the log's header with<redacted>, but only as a best effort. - One proxy per server. Wrap each server you want to record in its own proxy, with its own
--domain. For a flow across several servers, record them into one directory (several servers). - Its messages. The proxy writes to stderr, prefixed
stretto-proxy:; the first message says where the log is. Hosts usually keep a server's stderr in their MCP logs. - Exit status. The proxy exits with the server's status, or with 125 if the proxy itself fails, such as when the log cannot be created or the server cannot be started.
The conversation
MCP does not carry the conversation, and none of the hosts above hand it to a server. --context FILE reads it from a file that something else appends to, one JSON line per message; without it, a flow still works, but cannot prefer a value the user mentioned (the conversation). Leave it out unless your harness writes that file.
Related
stretto initandstretto-proxy's optionsstretto-proxyreference- Quick start
- The console: each server's host configuration and connection test