Skip to main content
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 sauce command 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:
The answer is one JSON object whose 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 with not found: the MCP endpoint is /mcp.
  • Loopback by default. Bound to 127.0.0.1, the server answers only a loopback Host, and only a loopback Origin when one is sent. Anything else gets 403:
  • Off loopback, --allowed-host is 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 any Host, for a proxy that checks it itself:
  • Bounded bodies. A request body over --max-body bytes (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 as args or defines, and 1 MiB of hex.
  • No files. The path input is refused, and a program’s relative imports come only from the call’s modules.

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 Host header on, and forward /mcp to http://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.
Rate limiting matters because every chain read spends your endpoints’ quota. The public endpoints’ limits are shared by every caller. Each person then adds the server to their agent as a remote (HTTP) MCP server at https://<host>/mcp, with the header your proxy checks.

Guard what callers send

Over HTTP, a caller’s rpcUrl 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:
A server over stdio has no guard. It is your own process, so an endpoint it reaches, a local node included, is one you can reach already. Every 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:
For a chain the file does not name, the server uses a built-in public endpoint. With --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