Skip to main content
Glama
Mishmar

Mishmar

Official

mishmar

Mishmar is a risk management layer for trading bots and AI agents: every order is checked against your limits before it reaches the exchange, large orders wait for your approval, and no key can trade alone. This is the client side: the API contract, the test vectors every SDK must pass, the agent's signer, the mishmar CLI and MCP server, and the SDKs themselves. The engine that enforces the rules is a separate, private repo; this one is what runs next to your agent.

Status: testnet. Mishmar runs on Hyperliquid testnet and Binance demo trading today; real money is not live yet. The contract, the Go packages, the agent's signer and the mishmar CLI are here, and so are the Python and TypeScript SDKs (mishmar on PyPI and npm). Binaries for Linux and macOS are on the Releases page.

Layout

spec/openapi.yaml     the API contract, the single source of truth for every client and the engine
spec/vectors/         cross-language test vectors: proposal signing, agent request signing (agentAuth)
api/                  the contract as Go types (generated; `make gen`)
canon/                canonical JSON: the bytes an agent signs
agentkey/             the agent's Ed25519 identity key: parse the secret, sign, verify, sign requests
proposal/             build, validate and sign a proposal for POST /v1/proposals
frost/                two-party FROST over Ed25519: the split key behind a Binance tradingAccount
ecdsa2p/              two-party ECDSA over secp256k1: the split key behind a Hyperliquid API wallet (keygen, presigning, signing)
signer/               the agent's signer: config, engine client, the checks, the signing rounds (FROST and two-party ECDSA), the poll loop
cmd/mishmar/          the CLI: keygen, add-agent, signer init|add-key|keygen|run, propose, mcp
mcp/                  the MCP server behind `mishmar mcp`: the signer's tools for a language model, over stdio
python/               the Python SDK (`mishmar` on PyPI)
typescript/           the TypeScript SDK (`mishmar` on npm); no runtime dependencies
examples/             bots to copy from: two minimal ones (Python, TypeScript) and two rule walk-throughs (Hyperliquid testnet, Binance demo trading)

Related MCP server: Reins

Run the checks

Two-party ECDSA (ecdsa2p, Hyperliquid API wallets) is Coinbase's cb-mpc, C++ behind cgo, through the mishmar-io fork of cb-mpc-go checked out next to this repo at the ref in cbmpc.ref (go.mod replaces the module with ../cb-mpc-go). Its scripts/build_cpp.sh builds the library once (CMake, a static OpenSSL 3.6.1 from its scripts/openssl), and make runs every Go command through its scripts/go_with_cpp.sh, which sets the cgo flags. Linux and macOS; Windows through WSL or Docker.

make test                                       # Go packages, including the vectors and both signers
make lint
cd python && python -m pytest                   # the Python SDK against the same vectors
cd python && python -m pytest                   # the Python SDK against the same vectors
cd typescript && npm test                       # the TypeScript SDK against the same vectors (Node 22+)
go test ./proposal -update                      # rewrite spec/vectors after changing the cases
make gen                                        # regenerate api/ and signerapi/ from spec/

A tag vX.Y.Z builds the binary on Linux and macOS, both architectures, and attaches it to the release (.github/workflows/release.yml); the Dockerfile builds the same binary for Linux, running the signer service by default.

How an agent talks to the engine

  1. The engine issues the agent a key and shows its secret once (msk_…). The engine keeps the public half.

  2. The agent builds a proposal (symbol, side, size, price or market, a deadline, a nonce), signs the canonical JSON of it with the key, and POSTs it to /v1/proposals.

  3. The engine checks the signature, evaluates every rule in scope, records the decision, and either forwards the order, parks it for a person, or blocks it. The response is the decision; a parked one resolves later and is read back from /v1/agent/decisions/{id}, a request the agent signs with the same key (the agentAuth headers).

  4. When the trading account's key is split, the engine asks the agent's signer to co-sign the venue request over the signer channel (/v1/agent/signer/…); the signer checks that it is the order it proposed before it signs.

The exact bytes signed are specified in proposal and agentkey and pinned in spec/vectors/.

The signer

When a trading account's venue key is split, the engine holds one share and the agent's signer the other, and a venue request is signed only when both sign it. The signer is the signer package as a library and mishmar signer run as a process. It long-polls POST /v1/agent/signer/poll with the agent's key and, for each request, refuses unless, in this order:

  • the scheme is frost-ed25519 (Binance) or ecdsa-2p (Hyperliquid); RSA and the proxy are not built yet;

  • the venue key is in its config, on the request's trading account and venue;

  • the request has not expired and was not answered already in this session (a request handed out again after it was answered is a replay, not a second signature);

  • the purpose is order, cancel or verify;

  • an order carries the agent's own proposal: signed by this signer's key, verifying with it, for this trading account, not yet expired;

  • the message, decoded, is that order and nothing more. On Binance the message is the parameter string the venue verifies: it may carry only the parameters the engine sends; newClientOrderId is the request's; symbol is the request's and starts with the proposal's; side is the proposal's; type is MARKET for a market proposal and LIMIT for a limit one; quantity is a decimal with 0 < quantity <= size (the engine floors to the lot step, never more); a limit price is within 1 % of the proposal's price and on its passive side (at most the price for a buy, at least for a sell), and a market order carries none; reduceOnly is the proposal's. A verify message must decode to a read and not an order: no symbol, side, type, quantity, price or client order id. On Hyperliquid the message is the EIP-712 digest, which cannot be read, so the request's body carries the action and nonce it came from: the signer decodes them with venues/hyperliquid, recomputes the digest for the key's network and compares, checks the nonce is fresh, and checks the action is the proposal's order (asset, side, size, a limit price on the tick rules within 1 % on the passive side, reduce-only, the cloid of the request's client order id) or the cancel of its target;

  • the hook, when the config names one, exits 0 (it gets the request's JSON on stdin and two seconds; its first line of output is the refusal reason).

Then it makes its half. FROST: it parses the engine's commitment, commits, makes its share of the signature over the exact bytes it checked, and answers {"kind":"share","commitment":…,"share":…}. Two-party ECDSA: it spends one of its presigned slots (a batch of nonces it ran the protocol's first three messages for with the engine's signer ahead of time, through POST /v1/agent/signer/presign), computes its last message over the digest, and answers {"kind":"share","share":…,"engineCommitmentId":<the slot>}; the engine's signer verifies that message and finishes the signature alone. On both venues an order the signer can build itself goes one-shot instead: the venue request and the signer's half travel inside the proposal (venueMessage), so an allowed order needs no round trip back. On Hyperliquid that is limit orders and cancels; a market order is priced by the engine at its mark and signed over the channel. A refusal is {"kind":"refusal","refusal":{"reason":…}} with a stable code first (message_mismatch: side "SELL" is not the proposed BUY), which the engine records on the decision's signing. Decimals are compared exactly; no float touches them.

The config file

~/.mishmar/agent.json, or the file MISHMAR_AGENT_CONFIG names, written with mode 0600:

{
  "engine": "http://localhost:8080/v1",
  "keyId": "key_acc1_abcdefghijkl",
  "secret": "msk_abcdef_…",
  "venueKeys": {
    "vk_…": {
      "tradingAccountId": "ta_…",
      "venue": "binance",
      "scheme": "frost-ed25519",
      "share": {"scheme": "frost-ed25519", "id": 1, "keyShare": "…", "group": "…"}
    }
  },
  "hook": "/usr/local/bin/check-order"
}

share is the agent's share as key generation left it (or as mishmar keygen wrote it). The file holds the identity secret and the agent's shares only; an engine share in it is refused on load.

The commands

go build ./cmd/mishmar

# Everything for a new agent in one go, with an operator token: create the
# agent, issue its key, make a venue key per trading account by two-party
# key generation with the engine's signer (FROST for Binance, ECDSA for
# Hyperliquid; no machine ever holds the whole key), write the config. It
# prints what to register or approve at the venue. The agent joins the
# account's default portfolio unless --portfolio pf_… names another.
mishmar add-agent --engine http://localhost:8080/v1 --token "$MISHMAR_OPERATOR_TOKEN" \
  --name momentum-1 --trading-account ta_…

# Or by hand, for an agent and key issued in the console: write the config
# from the key (the secret from MISHMAR_AGENT_SECRET or piped in), then add
# the venue key in the console without a share and run the key generation
# from this signer. Binance prints the public key to register at the
# exchange, Hyperliquid the API wallet address to approve from the master
# wallet.
echo "$MSK_SECRET" | mishmar signer init --engine http://localhost:8080/v1 --key-id key_… --agent agt_… --secret-stdin
mishmar signer keygen --venue-key vk_… --trading-account ta_… --venue binance
mishmar signer keygen --venue-key vk_… --trading-account ta_… --venue hyperliquid --network testnet

# The older way for Binance, which makes the whole key exist on this machine
# for the length of the call: deal a FROST key, paste the engine share when
# adding the venue key in the console, store the agent share under the id it
# returns.
mishmar keygen --scheme ed25519 --agent-share-out agent.share > engine.share
mishmar signer add-key --venue-key vk_… --trading-account ta_… --venue binance --share agent.share

# Run the signer; then register the key at the venue and verify it in the
# console (the verification is a read the signer co-signs). One signer runs
# per config: it holds <config>.lock while it runs, and a second one on the
# same config stops at once, naming the first one's pid. "signer keygen" and
# "signer add-key" say so when a signer is running, since it reads the config
# only when it starts: restart it to use the new key.
mishmar signer run

# Drive one order end to end with the signer running.
mishmar propose --config ~/.mishmar/agent.json --trading-account ta_… --symbol BTCUSDT --size 0.01 --price 60000

Restarts and rate limits

The engine answers 503 unavailable while it restarts (it drains for up to 28 s, so an order already in flight finishes) and 429 rate_limited with a Retry-After when a caller sends too much. Both mean the request did nothing, and every client here sends it again on its own: the Go client (signer.Client, which the signer's poll loop, mishmar propose and mishmar mcp use), the Python Client and the TypeScript Client. They wait the seconds in Retry-After when there is one, otherwise 0.25 s doubling to 8 s with jitter, for up to 45 s after the first attempt, then raise the last answer. A signed /agent request is signed anew for each attempt, so a retry is never a replay; a proposal goes again byte for byte. Nothing else is retried: 413 too_large would come back the same, and any other answer means the request was taken. Turn retries off or tune them with Client.Retries (Go), Client(..., retries=None) (Python) or new Client(..., { retries: false }) (TypeScript).

From an SDK, or from a model

The Python and TypeScript SDKs can run the signer as a child process, so the bot holds no secret at all: Signer starts mishmar signer run --local … with the config and talks to it over a private Unix socket (localhost with a token on Windows). An order is an intent; the child turns it into a proposal signed with the agent's key, sends it one-shot where it can and through the channel otherwise, and hands back the decision. Reads pass through the child the same way. The binary is found on the PATH, in MISHMAR_BIN or under ~/.mishmar/bin, or fetched from a release with download_binary / downloadBinary, checked against the release's checksums.

from mishmar import Signer

with Signer() as s:                                   # ~/.mishmar/agent.json
    d = s.order("ta_…", "BTC", "buy", "0.001", price="79500")
    if d["verdict"] == "require_approval":
        d = s.wait(d["id"])
import { Signer } from "mishmar";

const s = await new Signer().start();
const d = await s.order({ tradingAccountId: "ta_…", symbol: "BTC", side: "buy", size: "0.001", price: "79500" });
await s.stop();

The child lives and dies with the bot. The SDK starts it with --exit-on-stdin-close and a pipe on its stdin that it never writes to; the pipe closes when the bot's process ends, however it ends (a crash or a SIGKILL included), and the signer stops as it would on SIGTERM. So a signer never stays online for an agent whose bot is gone.

A signer can also run on its own, kept up by systemd, launchd or Docker, with mishmar signer run --local unix:/run/mishmar/signer.sock (or a loopback port with a token in MISHMAR_LOCAL_TOKEN), and the bot attaches to it instead of starting one: Signer.connect("unix:/run/mishmar/signer.sock") in Python, await Signer.connect("unix:/run/mishmar/signer.sock", { token }) in TypeScript. connect starts nothing and stop leaves the signer running. That is the way when several processes trade as one agent (one signer per config: a second Signer() on the same config fails, naming the process that holds it), or to keep the signer connected and its presigned slots warm while the bot restarts.

mishmar mcp is the same signer behind an MCP server on stdio: a language model gets tools to propose orders and cancels, follow a decision parked for a person, and read positions, PnL, approvals, the trading account and its venue rules. It never sees a key, and every order it proposes passes the engine's rules before anything reaches a venue. Point an MCP client at the command, with --config when the config is not at the default path:

{ "mcpServers": { "mishmar": { "command": "mishmar", "args": ["mcp"] } } }

In Claude Code, /plugin install mishmar --marketplace mishmar-io/mishmar adds the server together with a skill for writing bots against the SDK (skills/mishmar/SKILL.md; kit/ has the same guidance as an AGENTS.md snippet and a Cursor rule).

The npm and PyPI packages put the same command on the path, so a client needs no install step: npx -y mishmar mcp (Node 20 or later) or uvx mishmar mcp runs the binary found through MISHMAR_BIN, the PATH or ~/.mishmar/bin, and when there is none fetches the pinned release into ~/.mishmar/bin first, checked against the release's checksums. The MCP registry lists the server as io.github.mishmar-io/mishmar (server.json).

The engine's signer

mishmar signer serve is the same program in the engine's role (spec/signer-service.yaml, the signer/service package): the one process on Mishmar's side that holds the engine's share of every two-party ECDSA key, the Paillier keys and the presigned nonces. The engine holds no signing secret; it relays key generation and presigning between the agent's signer and this service, and asks it to finish one signature per order. The service signs only an order or a cancel it decoded itself and that matches a decision the engine signed with its own key (--engine-key, the public key GET /v1/ledger/head shows), rebuilding the venue digest from the action. Reach it from the engine alone: a Unix socket when the two share a machine, else mTLS; plain HTTP is for localhost. The shares are sealed at rest (AES-256-GCM, the key id bound as associated data) under the master key in MISHMAR_SIGNER_KEY, which must not live next to the store. On Google Cloud it can be wrapped by a KMS key instead: MISHMAR_KMS_KEY names the key and MISHMAR_SIGNER_KEY_WRAPPED holds the wrapped form (mishmar signer wrap-key makes it, from the raw key or anew). It is unwrapped at startup with the workload's identity, each time in the KMS audit log, and if KMS cannot unwrap, the service does not start: there is no fallback, and a raw key left beside it is refused. --store is where the sealed shares are kept, a file by default (mode 0600, replaced atomically) or object storage: s3://bucket/prefix on AWS S3 or any S3-compatible store (MISHMAR_S3_ENDPOINT, MISHMAR_S3_REGION, MISHMAR_S3_ACCESS_KEY, MISHMAR_S3_SECRET_KEY, or the AWS SDK's own variables and roles), gs://bucket/prefix on Google Cloud Storage as the workload itself, with no keys: its identity is granted the prefix, and the token comes from the metadata server as it does for KMS. Each key is one object, created conditionally so two replicas can never both create it; turn bucket versioning on for the history. Every share is opened into memory at startup, so no order waits on the store, and a wrong master key fails there rather than on the first order; replicas sharing a backend reconcile on --sync, and a key not yet in memory is fetched from the backend on first use, so a cell that takes on an account finds its shares at once. Slots and sessions live in memory and go with a restart; never snapshot, clone or live-migrate a running signer, since two copies of one presigned nonce would sign two messages and give the key away. Back up the store and the master key separately: losing either means every agent generates its key again and every owner approves again, nothing more, since the agent's half is useless alone and these keys hold no funds.

export MISHMAR_SIGNER_KEY=$(openssl rand -hex 32)   # keep it: it seals the shares
mishmar signer serve --listen unix:/var/run/mishmar/signer.sock --store /var/lib/mishmar/signer-keys.json --engine-key <base64>
# and on the engine: MISHMAR_SIGNER_URL=unix:/var/run/mishmar/signer.sock

Audit status

The two-party ECDSA comes from Coinbase's cb-mpc, which has had independent security reviews. Our change to it, which runs the first three of its four signing messages ahead of time so an order needs one round trip, has not been audited yet; docs/ecdsa-presign-review.md is the note for its reviewer, and SECURITY.md says how to report a flaw.

Available Tools

10 tools
cancel_orderCancel an orderA
DestructiveIdempotent

Cancel a resting order this agent placed, by the clientOrderId its decision carries. No rule runs on a cancel and a stopped account still lets it through.

NameRequiredDescriptionDefault
symbolYesThe order's symbol.
clientOrderIdYesThe resting order's client order id (msh-…).
tradingAccountIdYesThe trading account (ta_…).

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare destructiveHint=true, idempotentHint=true, and openWorldHint=true, so the safety profile is covered. The description adds genuinely non-obvious context beyond them: no rule evaluation runs on a cancel, and a halted account still permits it. It stops short of stating what happens on an unknown or already-executed order.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler, and the identifying scope ('by the clientOrderId') is front-loaded before the behavioral notes. Nothing redundant is included.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-required-parameter tool with full schema descriptions, rich annotations, and no output schema, the description covers scope and the two most surprising behavioral facts. Only edge-case outcomes (already filled, unknown id) are left unaddressed, which is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all three parameters are documented in the schema and the baseline is 3. The description adds a little meaning by tying clientOrderId to the decision record ('the clientOrderId its decision carries'), but says nothing extra about symbol or tradingAccountId.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('Cancel') and resource ('a resting order this agent placed') plus the key selector (clientOrderId). It scopes the tool to orders this agent owns, which implicitly separates it from propose_order and read-only siblings, though it never names an alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'resting order' signals the precondition, and the description makes clear it targets an existing order rather than creating one. There is no explicit when-to-use vs when-not statement, and no guidance on what to do if the order is already filled or unknown.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_decisionGet a decisionA
Read-only

Read one decision of this agent: its verdict, every rule's evaluation, the signing outcome, the venue's acknowledgement and, if it was parked, the approval's state.

NameRequiredDescriptionDefault
decisionIdYesThe decision (dec_…).

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish that this is a read-only, closed-world operation. The description adds useful behavioral context by spelling out the returned facets and the conditional approval state when a decision was parked, though it does not mention failure behavior such as an unknown or inaccessible decision ID.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is a single front-loaded sentence that states the operation and then efficiently enumerates the relevant return facets. Every clause contributes useful information without filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read tool with no output schema, the description does substantial work by explaining what the returned decision contains, including the conditional approval state. It could be more complete by noting behavior when the decision ID is not found, but the core reading contract is covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with decisionId documented as 'The decision (dec_…)'. The description adds no further parameter semantics beyond what the schema already provides, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource — 'Read one decision of this agent' — and enumerates the returned facets (verdict, rule evaluations, signing outcome, venue acknowledgement, approval state). It distinguishes well from list_decisions by emphasizing a single decision, but does not explicitly distinguish itself from wait_for_decision or get_venue_rules.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied: an agent should use this when it already has a decision ID and wants the full record. However, there is no explicit when-to-use guidance, no exclusion of alternatives, and no direction such as using list_decisions to find an ID or wait_for_decision to block until one exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_pnlGet PnLB
Read-only

This agent's daily PnL (realised, unrealised, fees, funding), by day.

NameRequiredDescriptionDefault
toNoLast day, YYYY-MM-DD.
fromNoFirst day, YYYY-MM-DD.

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds meaningful context about which PnL components are included and that results are bucketed by day, but says nothing about default date range, aggregation currency, or behavior when no data exists in the window.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no waste, listing the PnL components compactly. The phrasing 'This agent's' is slightly ambiguous about whose PnL is returned, which costs a point but not clarity of the core content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With only two optional params and a read-only annotation, the definition is close to sufficient, and no output schema means return values needn't be explained. However, the entirely optional date range leaves a real gap: the agent cannot know the default window or the response shape without calling it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with clear YYYY-MM-DD format notes on both bounds, so the schema carries parameter meaning. The description contributes the additional semantic that the output is grouped 'by day', which tells the agent how the range bounds map to result granularity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (daily PnL) and enumerates the components returned (realised, unrealised, fees, funding), so an agent knows what it retrieves. It lacks an explicit verb and does not contrast itself with siblings, but the resource is specific enough to distinguish it from get_venue_rules or list_positions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to call this versus other tools, and no statement about what happens when 'from'/'to' are omitted even though both are optional. An agent must infer the default window and cannot tell whether this is the right tool for historical versus current PnL.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_trading_accountGet a trading accountC
Read-only

A trading account this agent may trade on: its venue, kind, status and setup, without any secret.

NameRequiredDescriptionDefault
tradingAccountIdYesThe trading account (ta_…).

TDQS

C2.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety of the call is established. The description does add genuine behavioral context by promising the payload carries no secrets and is limited to accounts the agent may trade on, which matters for an agent reasoning about credentials. It still says nothing about not-found or permission-denied outcomes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One short sentence with no filler, and the field list comes early. The fragment lacking a verb slightly weakens clarity, but nothing needs trimming.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only single-parameter lookup with annotations covering safety, the description is close to adequate, and listing the returned facets (venue, kind, status, setup) partly compensates for the absent output schema. It remains silent on error conditions and on how the account relates to propose_order or get_venue_rules.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With a single parameter at 100% schema description coverage, the schema already documents that the id is a 'ta_…' string. The description adds no format, sourcing, or validation meaning beyond that, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource and enumerates what it exposes (venue, kind, status, setup), but it is a noun phrase with no verb, so the action ('get') has to be inferred from the name and title. It never distinguishes this from siblings like get_venue_rules, list_positions, or get_pnl, which also return account/venue context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to call this versus alternatives, no prerequisite (e.g. needing a tradingAccountId discovered elsewhere), and no mention of what to do if the id is unknown or inaccessible. The phrase 'this agent may trade on' hints at scoping but does not translate into usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_venue_rulesGet venue rulesA
Read-only

What the trading account's venue accepts per symbol: tick size, step size, minimums, as the engine last read them. Use it to size and price orders.

NameRequiredDescriptionDefault
symbolNoOne symbol; all when left out.
tradingAccountIdYesThe trading account (ta_…).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint and openWorldHint already declaring the safety profile, the description adds genuinely new context: "as the engine last read them" warns that values may be stale relative to the live venue. It doesn't cover refresh cadence or failure behavior if the account has no rules loaded.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: what is returned first, then what to use it for. No filler, and the practical guidance is front-loaded after the resource definition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Since there is no output schema, the description usefully names the returned fields, which is the main missing piece for a read tool. Minor gap: it doesn't say what happens for an unknown symbol or whether the response is keyed by symbol.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already says symbol is optional with "all when left out." The description's "per symbol" aligns with that but adds no format or default detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the concrete resource (venue rules for the trading account) and enumerates the fields returned (tick size, step size, minimums). It is clearly distinct from siblings like propose_order, but it doesn't explicitly name a sibling or state the difference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use it to size and price orders" gives a clear use context tied to real workflow steps (before propose_order). It stops short of explicit when-not conditions or naming the alternative tool, so it's clear rather than exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_approvalsList approvalsC
Read-only

This agent's proposals that wait for a person, or were decided by one.

NameRequiredDescriptionDefault
statusNo

TDQS

C2.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description contributes one genuinely useful fact beyond that — the results are limited to 'this agent's' proposals rather than all approvals — but says nothing about ordering, volume, pagination, or how pending and decided items are mixed in one response.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is short and front-loaded with no padding, which is good, but the compression has gone too far: a single elliptical clause carries the entire definition and reads as telegraphic rather than precise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with no output schema and a 0%-documented parameter, the description should explain what a result entry looks like, the default behavior when status is omitted, and whether results are paginated or ordered. None of that is present, so an agent must guess at the response shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description never mentions the status parameter or its pending/approved/rejected/expired values. The enum is largely self-explanatory, but the description does not state what omitting status returns, which is the one real ambiguity in a zero-required-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description identifies the resource (this agent's proposals awaiting or decided by a person) but is a sentence fragment with no verb such as 'list' or 'returns', and the phrase 'that wait for a person' is awkward. It does implicitly separate this from list_decisions by scoping to the agent's own proposals, but the distinction is left for the agent to infer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to call this versus list_decisions, get_decision, or wait_for_decision, all of which sit adjacent in the sibling list and cover overlapping territory. The only implied usage cue is the word 'wait,' which hints at polling but is never stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_decisionsList decisionsC
Read-only

This agent's recent decisions, newest first.

NameRequiredDescriptionDefault
limitNoHow many, default 20.
verdictNo
tradingAccountIdNoOnly this trading account.

TDQS

C2.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds two genuinely useful behavioral facts beyond that: results are scoped to "this agent's" decisions and are returned newest first. It stops short of covering pagination, whether pending decisions appear, or what a returned record contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded clause with no filler, and the ordering behavior is placed where an agent will read it first. It is efficient, though the extreme brevity borders on under-specification rather than tight writing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a low-complexity, three-optional-parameter read tool with annotations and no output schema, so the bar is modest. Still, an agent lacks guidance on result volume, default page size, and whether the verdict filter is applied before or after the agent scoping — gaps that a tool in an approval pipeline should close.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% — limit and tradingAccountId are documented in the schema while verdict relies on its enum alone. The description adds nothing about any of the three parameters (no default limit restatement, no explanation of verdict filtering, no note that tradingAccountId narrows the agent-scoped list), so it fails to compensate for the partial coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a verb and resource ("recent decisions") plus an ordering guarantee ("newest first"), so the agent knows this is a listing read. However, "decisions" is left undefined and there is no explicit contrast with get_decision or wait_for_decision, so the agent must infer the distinction from the tool names alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this tool versus get_decision (single item) or wait_for_decision (blocking wait), and no mention of prerequisites or exclusions. Usage is implied only by the word "list" and the sibling names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_positionsList positionsA
Read-only

This agent's open positions, with the mark price and unrealised PnL as the engine last saw them.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuinely new context with 'as the engine last saw them', warning that values are a snapshot and may be stale relative to live market state — a caveat the annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no waste, front-loading what is returned and closing with the staleness qualifier. Nothing could be removed without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of indicating return content, and it names the two most decision-relevant fields plus their freshness. It leaves the exact position record shape (symbol, size, entry price) unspecified, which is a minor gap for a zero-param read.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4; there is nothing for the description to disambiguate. It does not introduce any phantom filtering options, which is correct for a no-arg call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific resource (this agent's open positions) and the key payload fields (mark price, unrealised PnL), which distinguishes it from get_pnl and list_decisions. It stops short of naming a sibling explicitly, but the scoping to the calling agent's own book is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is the read path for current exposure, but there is no stated when-to-use, no exclusion against get_pnl, and no mention of whether it should be polled or called once per decision cycle.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

propose_orderPropose an orderA
Destructive

Propose an order on a trading account. The engine checks it against the account's rules and, when allowed, signs and sends it to the venue; the decision says what happened. A limit order needs a price; a market order is priced at the engine's mark. Sizes and prices are decimal strings.

NameRequiredDescriptionDefault
sideYes
sizeYesQuantity as a decimal string.
priceNoLimit price as a decimal string; not for a market order.
symbolYesThe venue's symbol: BTC on Hyperliquid, BTCUSDT on Binance.
leverageNoLeverage as a decimal string, where the venue takes it per order.
orderTypeNolimit (default) or market.
reduceOnlyNoThe order may only reduce the position (an exit).
validForSecondsNoHow long the proposal stands, at most 86400; default 60. An order parked for a person past it expires.
tradingAccountIdYesThe trading account (ta_…).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, openWorldHint=true and idempotentHint=false, so the safety profile is covered. The description adds meaningful behavior beyond that: the order is only signed and sent 'when allowed' after a rules check, and the outcome is reported via a decision — telling the agent this is not an unconditional submission. It omits any mention of the approval flow that validForSeconds hints at.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: what it does, what happens to it, and the type-specific pricing rule. The core action is front-loaded and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nine-parameter mutation with no output schema, the description covers the action, the asynchronous decision outcome, and the key pricing branch. The remaining gap is the approval/expiry workflow implied by validForSeconds and list_approvals, which an agent would have to infer from schema descriptions and siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 89%, so the schema already documents nearly every parameter including the price/market-order distinction and symbol formats. The description's only net addition is the conditional rule that a limit order requires a price while a market order is priced at the engine's mark, which is marginal over what the schema states. Baseline 3 applies when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Propose an order on a trading account') and goes further to explain the propose/check/sign/send pipeline, which distinguishes it from a raw order-submission tool and from siblings like cancel_order or get_decision. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear conditional guidance between order types ('A limit order needs a price; a market order is priced at the engine's mark') and implies the follow-up decision. It does not explicitly route the agent to get_decision or wait_for_decision after proposing, nor mention any exclusions, so it stops short of full when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_decisionWait for a decisionA
Read-only

Follow a decision parked for a person until it is approved, rejected or expired, or until the timeout; returns the decision as it then stands.

NameRequiredDescriptionDefault
decisionIdYesThe decision (dec_…).
timeoutSecondsNoHow long to wait, at most 600; default 60.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true and openWorldHint=false, so safety is covered; the description adds the genuinely new fact that this call blocks and can return a non-terminal result on timeout. It also discloses the three ways the wait ends, which is behavior an agent cannot get from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence that states the operation, the terminal conditions, the escape hatch, and the return value with no redundant wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly explains what comes back ("the decision as it then stands"), including the case where the timeout fires first. Only polling/blocking cost or concurrency implications are left unstated, which is a minor omission for a two-parameter read.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with decisionId and timeoutSeconds documented in-schema, including the 600 cap and default of 60. The description references the timeout only obliquely and adds no format or semantics beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ("follow") and resource (a parked decision) plus the terminal states it observes, which an agent can distinguish from a one-shot read. It does not name the sibling get_decision, so the contrast with a snapshot read must be inferred.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by "until it is approved, rejected or expired, or until the timeout" — i.e. use this when you need the outcome rather than the current value. There is no explicit when-not clause or named alternative such as get_decision for a non-blocking read.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 10 tool updatesv0.2.3
    • First observedcancel_order
    • First observedget_decision
    • First observedget_pnl
    • First observedget_trading_account
    • First observedget_venue_rules
    • First observedlist_approvals
    • First observedlist_decisions
    • First observedlist_positions
    • First observedpropose_order
    • First observedwait_for_decision

TDQS

A3.5/5.0

Scored across 10 tools

Disambiguation4/5

Each tool maps to a distinct resource+action: rules, propose, cancel, decision read, decision wait, decision list, positions, PnL, approvals, account. The only mild overlap is between get_decision, wait_for_decision and list_decisions, but the descriptions clearly separate single-read, parked-follow and recent-list semantics. get_venue_rules vs get_trading_account is also differentiated (per-symbol constraints vs account metadata).

Naming Consistency5/5

All names are snake_case verb_noun with a small, predictable verb set (get_, list_, propose_, cancel_, wait_for_), and the noun always names the resource. No camelCase or style mixing.

Tool Count5/5

Ten tools is well within the sweet spot and each covers a distinct concern (rules, order placement/cancel, decision inspection, approvals, positions, PnL, account). Nothing looks redundant or padded.

Completeness3/5

The order lifecycle is partially covered (propose, cancel, decision inspection), but there is no list_open_orders or get_order to discover resting orders and their clientOrderIds, so cancellation depends on remembering IDs from decisions. There is also no fills/trade-history tool, which limits reconciliation of the PnL and position data that is exposed.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI trading agents to trade safely through any broker MCP server by recording every tool call and reasoning in a local blackbox, while enforing configurable guardrails such as symbol whitelists, order size caps, rate limits, and daily-loss circuit breakers before orders reach the exchange.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to place and manage Hyperliquid trades through MCP with position, leverage, daily-loss, market, and stop-loss limits enforced outside the model, plus paper trading and an auditable decision log.
    9
    109 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that lets AI agents read Hyperliquid perpetual futures market data and their own account state, then place and cancel orders, adjust leverage, move USDC from spot to perp, and convert stablecoins to USDC. It holds no credentials and never contacts the exchange, routing every request through a runtime that enforces caps and signs server-side.
    9
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Local, advisory-only pre-trade risk gate for AI trading agents. 12 deterministic fail-closed rules return PASS/WARN/BLOCK with reasons and a local hash-chained audit log. Never places orders and needs no broker credentials. Early-stage open source (MIT).
    MIT