Nava MCP server
Developer Preview
@navalabs/sdk ships a second binary, nava-mcp. It is a Model Context
Protocol server speaking stdio: an MCP host launches it as a subprocess and
injects credentials as environment variables. There is no HTTP transport and no
listening port.
The package is restricted during Developer Preview. Get package access and a provisioned agent API key from Nava before configuring a host.
Set up the Nava MCP server in this project for the Developer Preview. Inspect the MCP host, package manager, installed @navalabs packages, secret handling, and required protocols before changing anything. Confirm that I have access to the restricted packages. Run nava-mcp over stdio and inject credentials through the host's secret or environment configuration. Never paste or print an API key, private key, wallet credential, or RPC credential. Keep NAVA_PROTOCOLS limited to the protocols I name. For Guardian verification, call await-verification once for each exact proposed action. Continue only when success is true, status is APPROVED, canExecute is true, verdict.outcome is approved, and verdict.reasonCode is allowed. Never decide from isError alone. Treat any mismatch as blocked, and request a new verdict if the action changes. Guardian must not sign or submit the action. Preserve the documented execution boundary of each adapter, do not perform a real write while validating setup, run the relevant checks, and report changed files, checks run, manual credential steps, and anything left disabled.It registers the same 18 operations as the CLI: 4 base verification tools plus 14 from the enabled adapters. Every tool name matches its CLI command token exactly, and every field carries a description in the live tool listing. The parameter tables are on the operations reference; this page covers running the server.
Tool naming
- A protocol tool is
<protocol>.<token>: one dot, kebab-case token. - The four base verification tools are unprefixed. They are not
nava.request-verification. - There are no camelCase aliases. Naming is enforced when the surface descriptor loads, so an alias cannot exist.
Select protocols with NAVA_PROTOCOLS
NAVA_PROTOCOLS=uniswap,hyperliquid nava-mcpNAVA_PROTOCOLS is a comma-separated list. An unrecognized name is reported as
unknown and ignored; the server still starts.
NAVA_PROTOCOLS | Tools registered |
|---|---|
| unset | The base four, plus every protocol whose adapter is installed. |
| an explicit list | The base four, plus exactly the protocols listed that are installed. |
| empty string | The base four only. |
Leaving it unset is the usual choice: it matches what you installed, so a single-adapter install exposes 10 tools and both adapters expose 18, with no configuration. Set it explicitly to narrow the surface, for instance to expose only Uniswap tools from a project that has both adapters.
A protocol still needs its adapter installed. When the list was unset, a
protocol you never installed is simply absent and nothing is logged, because
you never asked for it. When you name a protocol explicitly and its adapter is
missing, nava-mcp says so and starts without those tools rather than failing:
[nava-mcp] @navalabs/uniswap-adapter/mcp is not installed; uniswap.* tools will
not register. Install @navalabs/uniswap-adapter to enable this protocol.
An adapter that is installed but broken is always reported, whether or not you named it: absence is expected, failure is not.
Host configuration
Most hosts take a command, arguments, and an environment block. Zero-install:
{
"mcpServers": {
"nava": {
"command": "pnpm",
"args": [
"--package=@navalabs/uniswap-adapter",
"dlx",
"nava-mcp"
],
"env": {
"NAVA_API_KEY": "…",
"WALLET_ADDRESS": "0x…",
"UNISWAP_RPC_URL": "https://…",
"UNISWAP_CHAIN_ID": "11155111",
"UNISWAP_WALLET_ADDRESS": "0x…"
}
}
}
}With the adapter already installed in the project, "command": "nava-mcp" is
enough.
NAVA_PROTOCOLS is omitted above on purpose: unset, the server registers
whatever adapters are installed.
nava-mcp reads WALLET_ADDRESS. NAVA_WALLET_ADDRESS is a CLI-side alias
that the MCP server does not consult; set both when one configuration serves
both transports. The full list is on
the configuration reference. Inject secrets through the
host's environment or secret store; never place a key in a page, a prompt, or
command output.
isError does not mean rejected
isError does not report the Guardian verdict, so isError: false can accompany a rejection.
isError tracks transport and operation kind, not outcome:
- Verified write tools (the three Hyperliquid writes) derive
isErrorfrom the payload'ssuccess. - Read and build tools (all six Uniswap operations and the five Hyperliquid
reads) always return
isError: falseunless the call threw. - The four base tools set
isErrorby hand, and it does not always tracksuccess. Most failure paths set both. The exception is the one that matters most:await-verificationreturns any terminal verdict, including REJECTED, asisError: falsewithsuccess: falseandcanExecute: false. Only a timeout, a transport failure, or a missing verdict setsisError: true.
So a REJECTED Guardian verdict and a failed uniswap.execute-swap build both
look non-error at the protocol level. An agent that keys its next step off
isError will read a rejection as a success.
Decide from the complete payload instead. Continue only when success is
true, status is "APPROVED", canExecute is true, verdict.outcome is
"approved", and verdict.reasonCode is "allowed". Any mismatch is blocked.
Report execution as complete only after the relevant tool returns terminal
execution success.
The CLI has the same trap in a different spelling; see exit code 0 does not mean approved.
Other transport differences
MCP validates shapes and bounds the CLI does not, and has no cross-field
rules the CLI enforces; notably, MCP will accept a limit order with no
limitPrice. Hyperliquid's network is a per-call field here and
environment-only on the CLI. The full list is under
transport asymmetries.