Skip to main content
Glama

TAS Guard

A trading-aware safety proxy for AI agents. Put it between your AI client (Claude, ChatGPT, Cursor, your own agent) and any broker or exchange MCP server. It enforces per-order and daily limits, symbol allowlists, human approvals, a kill switch and a tamper-evident audit log, before an order ever reaches your broker.

An agent's over-limit order is blocked, a market order is held, approved on the phone, then sent to the broker

AI client  ──►  TAS Guard  ──►  Alpaca / CCXT / any trading MCP server  ──►  your account
                   │
                   ├─ blocks: over-limit orders, off-list symbols, withdrawals, leverage changes
                   ├─ asks you: large orders, live money, "close everything"
                   └─ logs: every decision, hash-chained

Zero dependencies. About 2,000 lines of plain JavaScript you can read in one sitting.

New in 0.3: onchain (EVM) mode. The same limits, approvals, kill switch and audit log for agents that hold their own wallet: tas-guard rpc is a local JSON-RPC endpoint your agent uses as its RPC URL.

Try it in 10 seconds (no broker account)

tas-guard demo runs the guard in front of a built-in paper broker with simulated prices. Add it to your AI app as an MCP server:

{ "mcpServers": { "tas-guard-demo": { "command": "npx", "args": ["-y", "tas-guard", "demo"] } } }

(On Windows use "command": "cmd", "args": ["/c", "npx", "-y", "tas-guard", "demo"].) Then ask your agent to buy 1 SPY at $580 (allowed), 2 SPY at $580 (held for your approval), 10 SPY (blocked: over the $2,000 per-order limit) or 1 TSLA (blocked: not on the allow list). Approve held orders with npx tas-guard approve <id>.

Related MCP server: mm-ibkr-mcp

Why not a generic MCP gateway?

Generic gateways decide per tool: "createOrder is critical, require approval." They can't tell a $50 order from a $50,000 one, so you end up approving everything or nothing.

TAS Guard reads the order itself. It knows that Alpaca's place_option_order has a 100x contract multiplier, that ccxt's cost is a quote-currency value while amount is base units, and that ccxt answers the first live order with a preview. That's what makes "allow small orders, ask for big ones, never exceed $2,000 a day" possible.

Broker connector

What it does on its own

With TAS Guard

Alpaca MCP (TAS safety score 68)

AI can place orders directly; toolsets can limit it

Per-order and daily caps, symbol allowlist, approval above a threshold

CCXT MCP

Has its own caps and confirm step

One policy and one audit log across every exchange you use

Any other trading MCP

Varies

Heuristic profile; anything unrecognized is blocked

Safety scores and order-gating facts: tradingagentstack.com.

Quick start (Alpaca, paper trading)

  1. Write ~/tas-guard/alpaca.json (or run npx tas-guard init alpaca-mcp-server):

{
  "name": "alpaca",
  "profile": "alpaca-mcp-server",
  "upstream": {
    "command": "uvx",
    "args": ["alpaca-mcp-server"],
    "env": {
      "ALPACA_API_KEY": "${ALPACA_API_KEY}",
      "ALPACA_SECRET_KEY": "${ALPACA_SECRET_KEY}",
      "ALPACA_PAPER_TRADE": "true"
    }
  },
  "policy": {
    "max_order_value": 500,
    "max_daily_value": 2000,
    "approve_over": 250,
    "symbols_allow": ["SPY", "QQQ", "AAPL", "MSFT"]
  }
}

${VAR} is read from the environment, so keys don't have to live in the file.

  1. Point your MCP client at the guard instead of at Alpaca. For Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "alpaca": {
      "command": "npx",
      "args": ["-y", "tas-guard", "run", "--config", "/Users/you/tas-guard/alpaca.json"],
      "env": { "ALPACA_API_KEY": "...", "ALPACA_SECRET_KEY": "..." }
    }
  }
}

For Claude Code: claude mcp add alpaca -- npx -y tas-guard run --config ~/tas-guard/alpaca.json

  1. Ask the agent to call tas_guard_status to see the limits it's working under.

No config file? npx tas-guard run --profile alpaca-mcp-server -- uvx alpaca-mcp-server uses the default policy.

What it decides

Every tool is put in a class, from a verified connector profile or, for servers without one, from name heuristics and MCP annotations.

Class

Examples

Default

read

quotes, positions, balances

allow

benign_write

watchlists

allow

cancel, close

cancel one order, close one position

allow (also during kill switch)

order

place an order

check limits

modify, cancel_all, close_all, other_write

replace order, cancel everything (stop-losses too), exercise options

ask a human

leverage, funds_out, account, raw_write, unknown

set leverage, withdraw, transfer, account settings, "call any endpoint", anything unrecognized

block (and hide from the agent)

For order calls, in this order:

  1. Kill switch on → block.

  2. Symbol on symbols_block, or not on symbols_allow (if set) → block. Globs work: "BTC/*".

  3. Side not in sides_allow (if set) → block.

  4. More than max_orders_per_minute or max_orders_per_day → block.

  5. Value over max_order_value, or today's total would pass max_daily_value → block. These are hard limits; approval can't override them.

  6. Value over approve_over, value unknown (market order by quantity, multi-leg), or live money with live_requires_approval → ask a human.

  7. Otherwise → allow.

Only orders the broker actually accepted count toward daily totals. Rejected orders and ccxt previews don't. Orders execute one at a time and limits are re-checked just before sending, so parallel calls can't slip past the daily cap.

Policy reference

{
  "max_order_value": 500,          // hard, per order, in the profile's quote currency
  "max_daily_value": 2000,         // hard, sum of executed orders today (local time)
  "max_orders_per_day": 20,
  "max_orders_per_minute": 3,
  "approve_over": 250,             // soft: above this, a human approves
  "symbols_allow": [],             // empty = any symbol
  "symbols_block": [],
  "sides_allow": [],               // e.g. ["buy"] for no selling
  "unknown_value": "approve",      // allow | approve | block when the value can't be computed
  "live_requires_approval": true,  // every live-money order needs a human
  "classes": { "close_all": "allow", "unknown": "approve" },  // override any class
  "hide_blocked_tools": true,
  "approval_ttl_minutes": 15
}

Approvals

When an action needs approval, the guard asks you, never the agent.

  • In the client: if your MCP client supports elicitation, a prompt appears in the app ("Approve this action?"). Only a human can answer it.

  • From a terminal: otherwise the call is held with an id. Run npx tas-guard approve <id> (or deny <id>), and the agent repeats the call. Each approval works once, for that exact call, within 15 minutes.

Tested with Claude Desktop (Windows, October 2026) against an Alpaca paper account: Claude Desktop doesn't show the in-app prompt, so approvals there go through npx tas-guard approve <id>. Claude relays the request id and waits for you.

npx tas-guard pending
npx tas-guard approve 3f9a1c

Phone approvals and kill switch (Telegram)

Get held actions on your phone with Approve and Deny buttons, alerts when an order is blocked, and a kill switch you can hit from anywhere. It uses your own Telegram bot, so nothing goes through our servers.

npx tas-guard telegram-setup --config ~/tas-guard/alpaca.json

It walks you through creating a bot with @BotFather, waits for you to press Start in your bot, then saves the bot token and your chat id into the guard config. Restart your AI app afterwards.

What you get:

  • Approve / Deny buttons. The agent's call waits up to 45 seconds (wait_seconds) for your tap and then goes through in the same call. If you're slower, the agent is told to retry after you approve.

  • Alerts when an order-type call is blocked (notify_blocked, on by default) and, optionally, when an order is sent to the broker (notify_executed).

  • Phone commands: /status (limits and today's usage), /pending (re-sends anything waiting), /kill, /resume.

  • Only you: taps and commands from any other Telegram account are ignored.

  • Phone-only approvals: set "cli": false so tas-guard approve refuses requests from this guard. That closes the gap where an agent with shell access could run the approve command itself.

"approvals": {
  "cli": false,
  "telegram": {
    "bot_token": "${TAS_TELEGRAM_BOT_TOKEN}",
    "chat_id": "123456789",
    "wait_seconds": 45,
    "notify_blocked": true,
    "notify_executed": false
  }
}

Several guards can share one bot. Whichever one is listening handles the tap, and the others pick up the decision from the shared state.

Kill switch

npx tas-guard kill "market looks wrong"   # every guard blocks new orders immediately
npx tas-guard resume

Reads, cancels and closing positions keep working while it's on, so you (or the agent) can still flatten.

Audit log

Every decision is appended to ~/.tas-guard/audit.jsonl: tool, class, arguments (secrets redacted), decision, reason, order value, and whether it executed. Each line includes the hash of the previous line.

npx tas-guard log --tail 20
npx tas-guard verify-log      # detects edited or deleted lines

Connector profiles

A profile says what each tool of a server can do with money and where its order fields live. The schema is schema/connector-profile.v1.json. Built-in profiles are verified against each server's source code or official docs, with the commit or page recorded:

  • alpaca-mcp-server: alpacahq/alpaca-mcp-server @ 2a973a0

  • ccxt-mcp-server: ccxt/ccxt mcp/ @ 310bf4b

  • robinhood-trading-mcp: Robinhood's hosted Trading MCP, from the 94-tool table in Robinhood's "Trading with your agent" article (2026-10-21). The server is closed source and Robinhood publishes no argument names, so order values can't be read: every order needs approval, and a symbols_allow list blocks orders.

Using a server without a profile? "profile": "auto" classifies tools by name and MCP annotations, and blocks anything it doesn't recognize. Profiles for more brokers are welcome as PRs.

Onchain (EVM) mode

For agents that sign and send their own transactions (AgentKit, viem, ethers, web3.py, your own bot), tas-guard rpc runs a local JSON-RPC endpoint. Point the agent's RPC URL at it instead of at your provider:

AI agent ──► http://127.0.0.1:8547 (TAS Guard) ──► your RPC provider (Alchemy, Infura, a node...)
                   │
                   ├─ reads (balances, calls, logs, gas...): passed through untouched
                   ├─ sends and signatures: decoded, checked, then forwarded, held for you, or refused
                   └─ logs: every decision, in the same hash-chained audit log

Try it with no chain, no keys and no money: npx tas-guard rpc-demo starts the guard in front of a built-in mock Base node and prints curl commands that get allowed, held, and blocked.

What it checks

Only the methods that can move money are touched; everything else goes straight to your provider.

Method

What the guard reads

eth_sendRawTransaction

Decodes the signed transaction (legacy, EIP-2930, EIP-1559): chain id, to, value, calldata. Its nonce must match one of your wallets.

eth_sendTransaction

The transaction object; from must be one of your wallets.

eth_signTypedData_v4 (and v1/v3)

ERC-2612 and DAI permits and Uniswap Permit2 (PermitSingle, PermitBatch, PermitTransferFrom) are treated as token approvals: spender, token, amount, deadline. Other typed data asks you.

personal_sign / eth_sign

personal_sign asks you; eth_sign (signs a raw hash, which can be a transaction) is blocked.

Any other eth_send*, eth_sign*, personal_*, wallet_*

Blocked: the guard can't decode them (eth_signTransaction, eth_sendUserOperation, wallet_sendCalls, personal_sendTransaction...).

Calldata is read by 4-byte selector: native transfers, ERC-20 transfer, transferFrom, approve, increaseAllowance, ERC-721/1155 setApprovalForAll and Permit2 approve. Anything else is a generic contract call.

For each send or signature, in this order:

  1. Kill switch on → block (reads still work).

  2. Sender not one of your wallets → block.

  3. Chain not on chains_allow, signed for a different chain than the upstream, or no replay protection (pre-EIP-155) → block.

  4. More than max_tx_per_minute or max_tx_per_day → block.

  5. Unlimited allowance (≥ 2^255, max uint, Permit2 max uint160) → block. setApprovalForAll(…, true) → block. Revokes (approve(x, 0), setApprovalForAll(x, false)) are allowed.

  6. USD value over max_tx_usd, or today's total would pass max_daily_usd → block. An allowance worth more than max_tx_usd is blocked too. These are hard limits; approval can't override them.

  7. Pre-flight revert check: eth_call and eth_estimateGas from your wallet at latest. If either fails → block, with the revert reason (Vault: deposits are paused, ERC20: transfer amount exceeds balance...).

  8. Ask a human if: value over approve_over_usd, value can't be priced (unknown_value), recipient not on recipients_allow (new_recipient), contract or spender not on contracts_allow (unknown_contract), or it's an approval or permit (token_approval).

  9. Otherwise → forward.

USD values come from your config, not a price feed: native_usd per chain and a tokens list ("usd_price": "stable" for stablecoins). Only sends that the upstream accepted count toward daily totals. Sends run one at a time and limits are re-checked just before forwarding.

Config (Base, USDC)

{
  "name": "base-agent",
  "upstream_rpc": "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
  "listen": "127.0.0.1:8547",
  "wallets": ["0xYourAgentWalletAddress"],
  "onchain": {
    "chains_allow": [8453],
    "native_usd": { "8453": 3000 },
    "tokens": {
      "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": { "symbol": "USDC", "decimals": 6, "usd_price": "stable" }
    },
    "max_tx_usd": 100,
    "max_daily_usd": 500,
    "approve_over_usd": 25,
    "max_tx_per_minute": 3,
    "max_tx_per_day": 20,
    "recipients_allow": [],
    "contracts_allow": [],
    "unlimited_approval": "block"
  },
  "approvals": {
    "telegram": { "bot_token": "${TAS_TELEGRAM_BOT_TOKEN}", "chat_id": "123456789" }
  }
}
ALCHEMY_API_KEY=... npx tas-guard rpc --config ~/tas-guard/base.json

${VAR} is read from the environment. The upstream URL (and any key in it) is never logged, audited or returned to the agent; only its host is shown. The full schema, with every setting and its default, is schema/onchain-guard.v1.json. Unknown settings are rejected, so a typo can't silently fall back to a default.

Setting

Default

chains_allow

[] (any)

Chain ids; others are blocked

max_tx_usd, max_daily_usd

100, 500

Hard limits

max_tx_per_minute, max_tx_per_day

3, 20

Hard limits

approve_over_usd

50

Ask above this

unknown_value

approve

Value can't be priced

recipients_allow / new_recipient

[] / approve

Your own wallets always count as known

contracts_allow / unknown_contract

[] / approve

Contract calls and approval spenders

token_approval

approve

Any approve, permit or Permit2

unlimited_approval, approval_for_all

block, block

typed_data, personal_sign, eth_sign

approve, approve, block

unsupported_methods

block

preflight

true

approval_ttl_minutes

15

Point your agent at it

  • viem / AgentKit (ViemWalletProvider): http("http://127.0.0.1:8547", { timeout: 900_000 }). viem's default 10-second timeout is shorter than a human approval.

  • ethers v6: new JsonRpcProvider("http://127.0.0.1:8547"). Its requests time out after 5 minutes; if you approve later, the agent resending the same signed transaction picks up the approval.

  • web3.py: Web3(Web3.HTTPProvider("http://127.0.0.1:8547", request_kwargs={"timeout": 900})).

The agent can call tas_guardStatus on the RPC to see its limits and today's usage.

Approvals, kill switch and audit log

They work exactly as in MCP mode and share the same state. A held request stays open until you approve it with npx tas-guard approve <id> or on your phone (the Telegram message shows the chain, contract, token, amount, USD value and reason), then it's forwarded and the agent gets the transaction hash. Denied or unanswered within approval_ttl_minutes → the agent gets a JSON-RPC error. If the agent's client gives up first, sending the same signed transaction again after you approve goes through once.

npx tas-guard kill (or /kill on your phone) blocks every send and signature on every guard; reads keep working. npx tas-guard log and verify-log cover onchain decisions too.

Limitations (onchain)

  • Wallets must be configured. The guard has no secp256k1 public-key recovery, so it can't prove who signed a raw transaction. It matches the transaction's nonce against your wallets and blocks anything that doesn't fit. A transaction signed by another key whose nonce happens to match would be treated as yours, though every policy check on its contents still applies.

  • The pre-flight is a revert check, not a full simulation. eth_call + eth_estimateGas at latest catch reverts and missing funds. They don't show balance changes, and the chain can change between the check and inclusion.

  • Generic contract calls are priced by their native value only. Tokens moved inside a call (a swap through a router you already approved, say) don't count toward USD limits. That's why unknown contracts and every approval ask you by default; keep contracts_allow short.

  • Prices are static. native_usd and usd_price come from your config; tokens not listed are unpriced (unknown_value).

  • It only protects agents that use this RPC URL. Wallets that broadcast through their own API (Coinbase CDP server wallets, ERC-4337 bundlers, a second RPC) bypass it. User operations, EIP-7702 and blob transactions are blocked, not decoded.

  • EVM only. Solana isn't supported yet.

  • Same caveat as MCP mode: an agent with shell access could run tas-guard approve itself unless you use phone approvals with "cli": false.

Windows and Claude Desktop notes

Tested on Windows with the Microsoft Store version of Claude Desktop, October 2026.

  • Put API keys in your guard file (upstream.env in alpaca.json), not in Claude Desktop's config. Claude Desktop keeps its own copy of each server's settings, so keys you change in its config file may not reach the server. Keys in the guard file always win. The guard's log shows which key the upstream received (last 4 characters only), e.g. credential ALPACA_API_KEY: ...PBYR (from guard config).

  • Use cmd /c to start npx in claude_desktop_config.json: "command": "cmd", "args": ["/c", "npx", "-y", "tas-guard", "run", "--config", "C:\\Users\\you\\tas-guard\\alpaca.json"].

  • Edit Claude Desktop's config only while the app is fully quit (system tray, Quit). It rewrites the file while running. The Store version keeps it under %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\.

  • Faster startup: run uv tool install alpaca-mcp-server once and set "command": "alpaca-mcp-server", "args": [] in the guard file. uvx otherwise re-resolves the server on every launch, which adds 10 to 20 seconds.

  • Approvals: Claude Desktop doesn't show the in-app approval prompt. Use phone approvals (telegram-setup), or approve held actions with npx tas-guard approve <id>.

Limitations (read these)

  • An agent with shell access could run tas-guard approve itself, unless you use phone approvals with "cli": false. Even then, an agent that can edit files in ~/.tas-guard could tamper with state, so run trading agents without shell access to your home folder where you can.

  • Values use the order's own price. A market order by quantity has no price, so it needs approval by default. Live price lookup is on the roadmap.

  • No P&L-based stop yet. Daily limits cap how much the agent can trade, not how much it can lose.

  • Quote currency is per symbol for ccxt (BTC/USDT is in USDT, ETH/BTC is in BTC). Use symbols_allow to keep limits meaningful.

  • It's a seatbelt, not a guarantee. The broker's own controls still matter. Not financial advice.

Development

npm test        # 61 tests: unit, end to end through a mock broker over real MCP stdio, the phone flow against a mock Telegram API,
                # and onchain mode (transaction decoding, policy, and the RPC proxy against a mock EVM node)

MIT licensed. Built by TradingAgentStack, the independent directory of what AI trading tools can do with your money.

Available Tools

9 tools
cancel_all_ordersA
Destructive

[TAS Guard: needs human approval] Cancel every open demo order.

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 destructiveHint=true, so irreversibility is covered. The description adds genuinely new behavioral context beyond that: the TAS Guard human-approval gate, which tells the agent this call will not execute autonomously. It does not spell out the approval workflow or failure behavior if approval is denied.

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 the guard condition front-loaded in brackets and the action immediately after. Every element — approval gate, scope, object — earns its place; nothing is padded.

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 zero-parameter, no-output-schema destructive tool, the description supplies the two things an agent most needs: the exact scope of destruction and the fact that human approval is required. Only minor detail (what happens on denial, whether the action is reversible) is left to the destructiveHint annotation.

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 and schema coverage is 100%, so there is nothing for the description to clarify. Baseline 4 applies; no parameter meaning is missing or misstated.

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?

States a specific verb ('Cancel') and a precisely scoped resource ('every open demo order'), which implicitly separates it from the sibling cancel_order_by_id (singular). The scope words 'every open demo' do the differentiation work, but no sibling is named outright.

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 the scope: this is the bulk variant, to be used when all open demo orders should go, as opposed to cancel_order_by_id or close_all_positions. No explicit when/when-not or named alternative is given, so the agent must infer the routing.

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

cancel_order_by_idC
Destructive

Cancel one demo order.

NameRequiredDescriptionDefault
order_idYes

TDQS

C2.7/5.0
Behavior2/5

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

destructiveHint=true already tells the agent this is a destructive operation, so safety is covered by annotations. The description adds nothing beyond that — no irreversibility warning, no permission/auth requirements, no error or partial-failure behavior for a cancel of an unknown or already-cancelled 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?

A single front-loaded sentence with no padding or filler. It is efficient, though the terseness is under-specification rather than true conciseness.

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 destructive, parameter-taking tool with no output schema and zero parameter documentation, the description leaves an agent without enough to invoke it correctly. It does not identify the order_id source or say what happens on success or failure.

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% for the single required order_id parameter, and the description does not compensate at all — no format, source, or example for the identifier. The agent cannot tell where order_id comes from (get_orders presumably) or what shape is valid.

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?

States a specific verb+resource ('Cancel one demo order'), and the word 'one' implicitly contrasts with the sibling cancel_all_orders. However, it never names that sibling or explicitly marks the single-vs-bulk boundary, and the stray qualifier 'demo' leaves ambiguity about whether it works on real orders.

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?

No when-to-use guidance, no conditions distinguishing it from cancel_all_orders or close_all_positions, and no prerequisites stated. The agent must infer the routing entirely from the tool name.

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

close_all_positionsA
Destructive

[TAS Guard: needs human approval] Sell every demo position at the simulated price.

NameRequiredDescriptionDefault

No parameters

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. The description adds important context beyond that: human approval is required and the operation is on demo positions at simulated prices, which communicates the safety and sandbox profile. It stops short of explaining reversibility or behavior when no positions exist.

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?

One compact sentence with a guard prefix, front-loading the approval requirement before the action. No wasted words.

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 zero-param, destructive tool with no output schema, the description is complete enough: it covers the action, the simulated environment, and the approval requirement. A minor gap is the lack of detail about what happens if no positions are open.

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?

With zero parameters, the baseline is 4. The schema is fully covered (100%) and no parameter details are needed from the description.

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?

States a specific verb (Sell), resource (every demo position), and price context (simulated price). It clearly distinguishes itself from siblings like place_stock_order (single order) and cancel_all_orders (orders, not positions).

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?

Implied usage is to close all demo positions, and it notes the human approval requirement as a condition. It does not explicitly say when to choose this over alternatives or when not to use it, so guidance is only partial.

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

get_account_infoB
Read-only

Demo paper account: cash, equity and buying power.

NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds one genuinely useful behavioral fact — that this is a demo/paper account rather than a live one — but says nothing about auth, latency, or refresh behavior.

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 compact fragment with no filler, and the key qualifier ('Demo paper account') is front-loaded. It is not a full sentence, but nothing in it is wasted.

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 input parameters, no output schema, and a readOnly annotation, the description's enumeration of returned fields (cash, equity, buying power) fills the main gap a caller would have. Only the demo-vs-live caveat and any staleness/refresh behavior remain unstated.

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 there is nothing for the description to disambiguate; the baseline of 4 applies. The listed return fields (cash, equity, buying power) add a little value despite not being parameters.

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 (account) and the exact fields returned (cash, equity, buying power), which separates it from siblings like get_all_positions and get_orders. It lacks an explicit verb such as 'retrieve', but the data it exposes makes the purpose unambiguous.

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 the sibling tools (get_all_positions, get_orders, get_stock_latest_quote). The only contextual cue is 'Demo paper account', which hints at scope but is not framed as usage guidance.

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

get_all_positionsB
Read-only

Open positions in the demo account.

NameRequiredDescriptionDefault

No parameters

TDQS

B3.3/5.0
Behavior3/5

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

readOnlyHint=true already tells the agent this is a non-mutating read, so the description's burden is light. It does add one useful behavioral fact not in the annotations — that the data comes from the demo (sandbox) account, not a live one — but says nothing about ordering, empty-result behavior, or result shape.

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 short sentence with no filler, and the scope qualifier is front-loaded. It is arguably under-specified rather than verbose, but nothing in it wastes the reader's time.

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 zero-parameter read tool with readOnlyHint and no output schema, the description covers the essentials (what, which account). It stops short of describing the returned fields or whether the list can be paginated, which would help an agent decide whether a follow-up call is needed.

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 of 4 applies. There is nothing for the description to disambiguate beyond the account scope it already mentions.

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 resource ('open positions') and its scope ('the demo account') are stated clearly enough that an agent knows what data comes back. It is a noun-phrase label rather than a verb+resource statement, and it does not explicitly distinguish itself from close_all_positions, which operates on the same resource.

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 get_account_info, get_orders, or close_all_positions, nor any stated preconditions. The agent must infer that this is the read-side counterpart to close_all_positions purely from the name.

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

get_ordersC
Read-only

Orders in the demo account.

NameRequiredDescriptionDefault

No parameters

TDQS

C2.4/5.0
Behavior2/5

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

readOnlyHint=true already tells the agent this is a safe read, so the description need not restate safety. It contributes the 'demo account' scoping fact, which is real added context, but says nothing about what orders are returned, ordering, limits, or pagination behavior.

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, but the brevity comes from under-specification rather than disciplined editing; the whole description is a sentence fragment.

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?

There is no output schema and no parameters, so the description is the sole carrier of meaning, and 'Orders in the demo account' leaves an agent unable to tell what the return data covers or how it differs from get_all_positions. Inadequate for even a simple tool.

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 and schema coverage is 100%, so there is nothing for the description to disambiguate. Baseline for a no-parameter tool applies.

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

Purpose2/5

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

The description is a bare noun phrase ('Orders in the demo account') that essentially restates the tool name with an account scope qualifier. It contains no verb, and it does nothing to distinguish this from siblings such as get_all_positions or get_stock_latest_quote beyond the word 'orders' and the account scope.

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?

No guidance on when to use this versus alternatives, no exclusions, and no mention of prerequisites. The only signal is that the scope is the demo account, which is an implicit constraint rather than usage direction.

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

get_stock_latest_quoteB
Read-only

Simulated latest quote for a symbol (demo prices).

NameRequiredDescriptionDefault
symbolYes

TDQS

B3.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds genuinely useful context beyond that: the quote is 'simulated' with 'demo prices', warning the agent that the data is not real market data. It stops short of describing latency, refresh cadence, or error behavior.

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 short sentence that is front-loaded with the verb and resource, with the key caveat in parentheses. Nothing is wasted, though the parenthetical is slightly awkwardly placed relative to the main claim.

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 simple one-parameter read-only tool, the description is adequate to call the tool correctly, and annotations cover the safety profile. It omits any hint of the returned fields or symbol format, which would help an agent validate its call.

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 0% and there is one required parameter, so the description carries the burden. It only restates that a 'symbol' is required and adds no format, casing, or validity guidance (e.g., ticker format). Since the parameter name is self-explanatory, this is minimally adequate rather than helpful.

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 and resource ('latest quote for a symbol') and adds a meaningful qualifier that it is simulated/demo data, which separates it from any real-market sibling. It does not explicitly distinguish itself from the surrounding trading siblings (get_orders, place_stock_order), but the resource is unambiguous.

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 alternatives, no prerequisites, and no exclusions. An agent must infer usage purely from the name and the parenthetical about demo prices.

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

place_stock_orderA
Destructive

[TAS Guard: max 2000 USD per order, 5000 USD per day; orders over 1000 need human approval] Place a demo stock order. Market orders fill at the simulated price; limit orders rest until cancelled.

NameRequiredDescriptionDefault
qtyNo
sideYes
typeNo
symbolYes
notionalNo
limit_priceNo

TDQS

A4/5.0
Behavior5/5

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

With only destructiveHint=true from annotations, the description carries the burden and delivers: per-order and per-day notional caps, a human-approval threshold, and the execution semantics of each order type (market fills at simulated price, limit rests until cancelled). This is exactly the kind of risk and lifecycle context an agent needs before a mutating call.

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 sentences with zero waste; the risk guard is front-loaded in brackets ahead of the operational description, so the highest-stakes information is read first.

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?

The risk limits and order-type semantics are covered, but with six parameters, no schema descriptions, and no output schema, the description leaves the parameter contract substantially undocumented. It is adequate for a simple call but not complete for a tool whose fields are entirely self-describing only by name.

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% across six parameters, and the description adds nothing about them beyond order-type behavior. It never explains the relationship between qty and notional, whether either is optional in practice, the string-encoded numeric format, or how limit_price interacts with type.

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?

States a specific verb and resource ('Place a demo stock order') and clarifies the simulated nature of the operation, which separates it cleanly from the read-only and cancellation siblings. It also distinguishes market vs. limit order behavior, so an agent knows exactly which operation it is invoking.

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?

The TAS Guard preamble conveys real constraints (2000 USD/order, 5000 USD/day, human approval over 1000) that imply when an order is permissible. However, it never says when to use this tool versus alternatives such as tas_guard_status (to check limits beforehand) or the cancel tools, so routing is left to inference.

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

tas_guard_statusA
Read-only

TAS Guard: show the trading limits that apply to this connection, today's usage, the kill switch and pending approvals. Read-only.

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 destructiveHint=false, so safety is covered; the description's 'Read-only' is largely redundant. However, it adds genuine value with no output schema present by enumerating what is surfaced (limits, today's usage, kill switch, pending approvals), which is behavioral content beyond the annotations.

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 short sentences, front-loaded with the tool name and the exact content shown, with the safety note last. Every clause carries information; nothing is padded.

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 parameters, no output schema, and read-only annotations, the only open question is what the tool returns, and the description answers that by naming the four reported areas. It stops short of describing format or freshness beyond 'today's usage', but nothing required for correct invocation is missing.

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 schema has zero parameters, which is the baseline-4 case. There is nothing further for the description to clarify, and it correctly implies the tool operates on the ambient connection rather than taking arguments.

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 ('show') and an enumerated resource set (trading limits, today's usage, kill switch, pending approvals) scoped to 'this connection', which a reader can easily distinguish from get_account_info or get_orders. It does not explicitly name or contrast any sibling tool, which is what a 5 would require.

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 the content ('limits that apply to this connection'), so an agent can infer it answers a risk/limits check, but there is no statement of when to prefer it over get_account_info or when it is not appropriate. No prerequisites, timing, or exclusions are given.

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. 9 tool updatesv0.2.3
    • First observedcancel_all_orders
    • First observedcancel_order_by_id
    • First observedclose_all_positions
    • First observedget_account_info
    • First observedget_all_positions
    • First observedget_orders
    • First observedget_stock_latest_quote
    • First observedplace_stock_order
    • First observedtas_guard_status

TDQS

A3.5/5.0

Scored across 9 tools

Disambiguation5/5

Each tool targets a distinct resource and action: account info, quotes, positions, orders, order placement, cancellation (single and all), position closing, and guard status. No overlapping purposes that could cause misselection.

Naming Consistency4/5

Mostly consistent snake_case with clear verb_noun patterns (get_*, place_*, cancel_*, close_*). The outlier 'tas_guard_status' is a noun phrase rather than verb_noun, a minor deviation.

Tool Count5/5

9 tools is well within the ideal 3-15 range for a demo trading account with guardrails. Each tool earns its place, covering read operations, actions, and guard status without redundancy.

Completeness4/5

Core lifecycle is covered: account info, quotes, positions, orders (list, place, cancel one/all), close all positions, and guard status. Minor gaps exist (e.g., get order by ID, close single position, order update), but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Secure broker gateway and stateful trading SaaS that bridges LLM AI agents with brokerage accounts via MCP, encrypting credentials and supporting connectors for Bybit, MetaTrader 5, TradingView, and more.
    -
  • A
    license
    B
    quality
    C
    maintenance
    MCP server for Interactive Brokers that enables account monitoring, order preview, trade execution, and basket trading with human-in-the-loop approval via Telegram and SQLite-backed audit.
    39
    MIT
  • 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
    Not graded
    quality
    C
    maintenance
    Connects AI assistants to 16 crypto exchanges and MetaTrader 5 over a single MCP endpoint, enabling trading and account management with server-side risk controls, paper trading by default, and auditable signed receipts.
    3
    CC BY-4.0