sauce mcp --http <port> serves the MCP server over Streamable HTTP, for agents that connect to it by URL. This server:
- builds transactions but never signs them;
- keeps no wallet or Pot store;
- authenticates no one, so it has to sit behind your own authentication.
Prerequisites
- The
saucecommand on the host (npm install -g @eco-incorp/sauce, Node.js 24 or newer). - A reverse proxy that checks a token before it forwards a request, and serves TLS.
Run it
--http 0 picks a free port. To check that the server answers, list its tools:
result.tools lists 18 tools, from sauce_chains to sauce_install_skills. The HTTP server has no wallet tools, no sauce_sign and no Pot store tools (MCP tools).
How it answers
-
Stateless, at
/mcp. Each POST is answered as JSON, with no session, so any replica can answer any request. -
Other methods and paths are refused. A GET returns 405 with
this server is stateless: POST each JSON-RPC request to /mcp. Another path returns 404 withnot found: the MCP endpoint is /mcp. -
Loopback by default. Bound to
127.0.0.1, the server answers only a loopbackHost, and only a loopbackOriginwhen one is sent. Anything else gets 403: -
Off loopback,
--allowed-hostis required.--host <address>binds another interface. The server refuses to start beyond loopback until--allowed-host <name>names the host it is served as. The flag can be repeated, and--allowed-host '*'answers anyHost, for a proxy that checks it itself: -
Bounded bodies. A request body over
--max-bodybytes (default 2 MiB) is refused with 413 before it is read. Each tool also bounds its own inputs: at most 256 KiB of program text, 32 modules (512 KiB in all), 64 entries in any list or map such asargsordefines, and 1 MiB of hex. -
No files. The
pathinput is refused, and a program’s relative imports come only from the call’smodules.
Put your authentication in front of it
The server checks no token, so your reverse proxy has to. A typical setup:-
Keep the server on loopback, and name the public host it is served as:
-
In the proxy, check a bearer token, terminate TLS, rate-limit, pass the
Hostheader on, and forward/mcptohttp://127.0.0.1:3000. -
If the proxy runs on another machine, bind with
--host 0.0.0.0, and make sure the server’s port is reachable by the proxy alone.
https://<host>/mcp, with the header your proxy checks.
Guard what callers send
Over HTTP, a caller’srpcUrl is chosen by whoever calls. The server reaches it only through a guard:
- It takes
https:only:rpcUrl must be an https URL: this server reaches a caller's endpoint over TLS only. - It resolves the host and refuses any address that is not on the public internet: loopback, private (RFC 1918 and IPv6 ULA), link-local, CGNAT, unspecified, multicast, reserved, or a cloud metadata address.
- It resolves and checks the host again at every connection, so a name that changes to a private address after the first check is refused when it is used.
- It follows no redirect, times out (20 seconds a request), and bounds what it sends (2 MiB) and what it reads back (16 MiB).
--allow-private-rpc admits http: URLs and private addresses, for a deployment inside a private network. Link-local and metadata addresses stay refused:
rpcUrl passes through your server, so a key in a URL a caller passes is shared with you. The server never returns, logs or quotes a URL.
Endpoints and environment
--config <file> gives the server your own RPC endpoints:
--offline it uses none, and reads a chain only through a caller’s rpcUrl. How a tool reaches a chain gives the order.
The HTTP server reads no environment variable. It never shows a URL from the file, or the file’s path.
It holds no key and keeps no store. The wallet, password and store flags are refused at start:
Next steps
- Sign with a wallet’s MCP server: each person signs what the shared server builds with their own wallet.
- MCP tools: every tool and its inputs.
sauce mcp: every flag.
