# API & MCP Reference

> 93 deterministic TradingCalc tools, 12 suites plus 3 system tools: full catalog, request/response examples, and access through MCP clients (Claude Desktop, Cursor, VS Code), direct HTTP JSON-RPC, or REST for the core futures calculators.

Source: https://docs.tradingcalc.io/api

Endpoint: https://tradingcalc.io/api/mcp

One JSON-RPC endpoint, 93 deterministic tools: 12 suites plus 3 system tools. This page is the full reference: install instructions, the complete tool catalog, and worked request/response examples.

## Install in 30 seconds

### Claude desktop

```json
{
  "mcpServers": {
    "tradingcalc": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://tradingcalc.io/api/mcp"]
    }
  }
}
```

### Cursor / vs code

```json
{
  "tradingcalc": {
    "url": "https://tradingcalc.io/api/mcp"
  }
}
```

### Langchain (python)

```python
# pip install langchain-tradingcalc
from langchain_tradingcalc import TradingCalcToolkit

tools = TradingCalcToolkit().get_tools()  # every TradingCalc tool as a LangChain tool
# in an event loop: await ...aget_tools()
# a dot in tool names becomes underscore
# then: create_agent(model, tools)
```

### Openai agents sdk (python)

```python
# pip install openai-agents
# Tool names have a dot, OpenAI function names
# reject it (400). The hosted MCP tool avoids it.
import asyncio
from agents import Agent, HostedMCPTool, Runner

async def main():
    agent = Agent(
        name="Assistant",
        instructions="Use the tradingcalc tools for option, forex and position math.",
        tools=[
            HostedMCPTool(
                tool_config={
                    "type": "mcp",
                    "server_label": "tradingcalc",
                    "server_url": "https://tradingcalc.io/api/mcp",
                    "require_approval": "never",
                }
            )
        ],
    )
    result = await Runner.run(agent, "What is a 30 day BTC 90000 call worth at 60% vol, spot 85000?")
    print(result.final_output)

asyncio.run(main())
```

### Anthropic api, mcp connector (python)

```python
# pip install anthropic
# The API calls the server, so dots are fine.
import anthropic

client = anthropic.Anthropic()
response = client.beta.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1024,
    betas=["mcp-client-2025-11-20"],
    mcp_servers=[{"type": "url", "name": "tradingcalc", "url": "https://tradingcalc.io/api/mcp"}],
    tools=[{
        "type": "mcp_toolset",
        "mcp_server_name": "tradingcalc",
        "default_config": {"enabled": False},
        "configs": {"workflow.run_black_scholes": {"enabled": True}},
    }],
    messages=[{"role": "user", "content": "What is a 30 day BTC 90000 call worth at 60% vol, spot 85000?"}],
)
print(response.content[-1].text)
```

### Vercel ai sdk (typescript)

```ts
// npm install ai @ai-sdk/mcp
import { createMCPClient } from '@ai-sdk/mcp';

const client = await createMCPClient({
  transport: { type: 'http', url: 'https://tradingcalc.io/api/mcp' },
});
const mcpTools = await client.tools();
// Tool names have a dot and model APIs reject it (400), so rename for the model
const tools = Object.fromEntries(
  Object.entries(mcpTools).map(([name, tool]) => [name.replace(/\./g, '_'), tool]),
);
// pass to generateText({ model, tools, prompt })
// await client.close() when you are done
```

### Mastra (typescript)

```ts
// npm install @mastra/mcp
import { MCPClient } from '@mastra/mcp';

const mcp = new MCPClient({
  id: 'tradingcalc',
  servers: { tradingcalc: { url: new URL('https://tradingcalc.io/api/mcp') } },
});
const tools = await mcp.listTools(); // pass to new Agent({ model, tools })
// Names get the server name as a prefix, for example tradingcalc_workflow.run_black_scholes;
// Mastra sends the model a dot-free name (tradingcalc_workflow_run_black_scholes)
```

### Crewai (python)

```python
# pip install "crewai-tools[mcp]"
# Python 3.12 or 3.13, not 3.14 (crewai limit)
from crewai import Agent, Crew, Task
from crewai_tools import MCPServerAdapter

server_params = {"url": "https://tradingcalc.io/api/mcp", "transport": "streamable-http"}

# Name the tools the agent needs (20 at most:
# Anthropic caps strict tools). CrewAI turns
# the dot into an underscore.
with MCPServerAdapter(server_params, "workflow_run_black_scholes") as tools:
    analyst = Agent(
        role="Options analyst",
        goal="Price options with the tradingcalc tools",
        backstory="Uses the tradingcalc tools for option math.",
        tools=tools,
    )
    task = Task(
        description="What is a 30 day BTC 90000 call worth at 60% vol, spot 85000?",
        expected_output="The call price in USD",
        agent=analyst,
    )
    print(Crew(agents=[analyst], tasks=[task]).kickoff())
```

### Gemini cli

```json
{
  "mcpServers": {
    "tradingcalc": {
      "httpUrl": "https://tradingcalc.io/api/mcp"
    }
  }
}
```

### Google adk (python)

```python
# pip install "google-adk[mcp]"
# export GOOGLE_API_KEY=<AI Studio key>
# __init__.py in the same folder holds:
# from . import agent
# run it with: adk run tradingcalc_agent
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams

root_agent = LlmAgent(
    model="gemini-3.5-flash",
    name="tradingcalc_agent",
    instruction="Use the tradingcalc tools for every number.",
    tools=[McpToolset(
        connection_params=StreamableHTTPConnectionParams(url="https://tradingcalc.io/api/mcp"),
    )],
)
```

### Microsoft copilot studio

```text
Agent, Tools, Add a tool, New tool, Model Context Protocol
Server name: TradingCalc
Server URL: https://tradingcalc.io/api/mcp
Authentication: None
Create, create the connection, add the tool to the agent
(generative orchestration must be on for the agent)
```

### Gemini enterprise

```text
Google Cloud console, Gemini Enterprise, Data stores,
Create data store, Custom MCP Server, Add MCP server
Server URL: https://tradingcalc.io/api/mcp
Authentication: No authentication
After creation: Actions tab, Reload custom actions,
enable the tools you want, then connect the data
store to your app (an admin may first need to lift
the organization policy that blocks custom MCP servers)
```

### Perplexity

```text
Settings, Connectors, + Custom connector, Remote
Name: TradingCalc
Server URL: https://tradingcalc.io/api/mcp
Authentication: none
Save, then enable the connector inside a thread
(availability depends on your plan; on Enterprise an
admin may need to allow custom connectors)
```

### Direct http (json-rpc, no mcp client needed)

```bash
curl -X POST https://tradingcalc.io/api/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "liquidation",
      "arguments": {
        "side": "long",
        "entryPrice": 95000,
        "leverage": 10,
        "marginType": "isolated"
      }
    }
  }'
```

### With an api key (higher rate limits)

```bash
curl -X POST https://tradingcalc.io/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", ... }'

// MCP config with key
{
  "mcpServers": {
    "tradingcalc": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://tradingcalc.io/api/mcp",
               "--header", "Authorization: Bearer YOUR_API_KEY"]
    }
  }
}
```

### Smaller tool list (one domain only)

```text
// The full list is large (tens of thousands of tokens of context). Add ?set= to list only the domains you use.
// Sets: options, forex, risk-stats, prediction-markets, onchain, finance, perps
https://tradingcalc.io/api/mcp?set=options
https://tradingcalc.io/api/mcp?set=options,forex

// Only the list shrinks: tools/call still accepts every tool, and without ?set= nothing changes.
// An unknown set name is an error (code -32602) that names the valid ones.
```

To get a key, email [s@tradingcalc.io](mailto:s@tradingcalc.io). Keys are issued manually: no self-serve signup or card required, no automated flow to abuse. Need more than the free limit? Paid plans with higher quotas are on [RapidAPI](https://rapidapi.com/SKalinin909/api/tradingcalc-new), or email the same address.

- Anonymous, no key: 100 calls/day, limited by IP
- Free API key: 200 calls/day
- Quota resets daily at 00:00 UTC
- REST `/api/actions/{calc}` also has a per-minute cap: 60 calls/min without a key (per IP), 300 calls/min per key or per user behind the Rapid gateway, counted per UTC minute; over it the reply is 429 with `Retry-After`
- Behind the Rapid gateway the quota is the one of the Rapid plan the user chose, applied by Rapid; our server adds only a high per-user safety cap and one shared per-minute cap over all Rapid users
- Same daily quota is shared across the MCP endpoint and the REST `/api/actions/{calc}` endpoint per key
- Only `tools/call` counts toward the quota. `initialize`, `tools/list`, `ping` and notifications are free, and so is a request the server rejects as malformed or for an unknown method
- Protocol: `initialize` answers with the MCP version the client asks for when it is 2025-06-18, 2025-03-26 or 2024-11-05, and with 2025-06-18 otherwise
- Tool sets: `/api/mcp?set=options` (several: `?set=options,forex`) narrows `tools/list` and the `initialize` instructions to those domains plus the system tools, so a client that needs one domain loads a fraction of the tokens. Calls are never narrowed
- One JSON-RPC message per POST: a batch array gets HTTP 400 with code -32600, malformed JSON gets -32700, an unknown method gets -32601. Notifications get an empty 202

## 93 MCP tools: 12 suites plus system.verify, system.pubkey and system.batch

### Trade Planning

- `workflow.run_pnl_planning`: Net PnL, ROE, fees and gross P&L for a futures trade
- `workflow.run_breakeven_planning`: Break-even price accounting for entry and exit fees
- `workflow.run_exit_target`: Exit price required to hit a target PnL or ROE
- `workflow.run_position_sizing`: Position size from account balance and max risk %
- `primitive.average_entry`: Average entry price after DCA into a position
- `workflow.run_scenario_planning`: Multi-scenario P&L table across price targets
- `workflow.run_dca_entry`: Weighted average entry, breakeven, and per-level contribution from multiple fills
- `workflow.run_average_down`: Should-I-average-down check: new average entry, liquidation, breakeven, and risk before/after, benchmarked against a fresh entry at today's price
- `workflow.run_scale_out`: P&L, ROI, and cumulative P&L for each partial exit level

### Risk & Margin

- `workflow.run_liquidation_safety`: Liquidation price for long/short, isolated margin, one flat maintenance rate
- `workflow.run_max_leverage`: Maximum safe leverage given account size and volatility
- `primitive.hedge_ratio`: Short perp size to fully hedge a spot position, including funding cost
- `workflow.run_risk_reward`: Full R:R analysis: position size, liquidation, breakeven, P&L at stop and target. Returns verdict.
- `workflow.run_portfolio_risk`: Aggregates P&L, margin usage, and liquidation distance across every open position. Returns verdict.

### Funding & Carry

- `workflow.run_funding_cost`: Cumulative funding cost over a holding period
- `workflow.run_funding_arbitrage`: Annualized funding arbitrage yield between two exchanges
- `workflow.run_compound_funding`: Capital growth from reinvested funding income, with withdrawn income and APY
- `workflow.run_carry_trade`: Delta-neutral carry: net yield, gross/net profit, breakeven days. Returns verdict.
- `workflow.run_funding_breakeven`: Price move needed to cover funding cost + fees over a holding period

### Integrated Decision

- `workflow.run_pre_trade_check`: Full pre-trade risk analysis: position size, liquidation price, breakeven, funding cost, and safety classification in one call

### Market Structure

- `workflow.run_open_analysis`: Market Profile open analysis: open location, open type (OD/OTD/ORR/OAIR), VAH/VAL/VPOC/IB, and scenario framing
- `workflow.run_session_structure`: Day-type classifier: trend / balance / neutral_trend / normal / normal_var
- `workflow.run_value_migration`: Value-area migration across sessions: directional conviction vs balance
- `workflow.run_breakout_acceptance`: Breakout acceptance vs rejection beyond the value area (with optional delta)

### Crypto Spot

- `workflow.run_crypto_profit`: Profit or loss on a spot buy and sell after both fees: coins bought, cost, proceeds, ROI, break-even sell price, annualized return for a hold of 30+ days

### Time Value of Money

- `workflow.run_present_value`: Present value of a lump sum, a level payment stream or both at a discount rate: ordinary annuity or annuity due, any compounding frequency
- `workflow.run_future_value`: Future value of a starting sum and regular contributions at a fixed rate, with total contributions and interest earned
- `workflow.run_npv`: Net present value of a list of cash flows at a rate per period; the first flow is at time 0 and is not discounted
- `workflow.run_irr`: Internal rate of return of a list of cash flows; with several sign changes it lists every rate found and gives no single answer
- `workflow.run_cagr`: Compound annual growth rate between a beginning and an ending value over a number of years
- `workflow.run_apy_apr_converter`: Convert an APR to an APY or back for a chosen compounding (periods per year or continuous)
- `workflow.run_bond_price`: Price, Macaulay and modified duration, convexity and DV01 of a fixed-rate bond at a yield to maturity

### On-Chain

- `workflow.run_token_risk_check`: Solana token rug-pull mechanism check: mint/freeze authority, LP lock, mutable metadata, named scam-pattern flags
- `workflow.run_swap_price_impact`: Live price-impact quote for a Solana swap, selling or buying, routed through Jupiter across every pool it knows about
- `workflow.run_bonding_curve`: Pump.fun-style bonding curve: exact tokens received, price impact, and graduation progress
- `workflow.run_market_cap_comparison`: Live market-cap ratio between two tokens (Solana or 5 EVM chains) projected onto an investment
- `workflow.run_wallet_flag_check`: Wallet address check against independent flag databases (GoPlus, Webacy, ScamSniffer): sanctions, phishing, exchange labels
- `workflow.run_impermanent_loss`: Impermanent loss for a liquidity-pool position, full-range or Uniswap-V3-style concentrated: LP value vs. holding, manual prices
- `workflow.run_impermanent_loss_live`: Live variant: fetches both tokens' current prices (Solana or 5 EVM chains) and derives the price ratio automatically

### Prediction Markets

- `workflow.run_odds_converter`: Converts one probability into decimal/American odds and breakeven win rate, manual or from one live market on Kalshi/Polymarket/ADI Predictstreet/Limitless/Myriad; one market per call, for the same bet on several venues see workflow.run_spread_reader
- `workflow.run_market_implied_odds`: Reads Kalshi's live BTC/ETH year-end price ladder: median and mode price bucket, probability at/above any boundary
- `workflow.run_prediction_market_edge`: Compares your probability estimate against a Kalshi/Limitless/Myriad market price and sizes a bet with fractional Kelly
- `workflow.run_window_fair_value`: Theoretical fair value for a time-windowed crypto up/down contract, priced as a cash-or-nothing digital option, for venues with no live market price yet
- `workflow.run_spread_reader`: Reads the same real-world bet's live price on 2-5 venues at once (Kalshi/Polymarket/ADI Predictstreet/Limitless/Myriad) and reports the spread and the venue with the lowest yes midpoint price, before fees and depth; for the odds or vig of one market see workflow.run_odds_converter
- `workflow.run_cross_venue_arbitrage`: Checks 2-5 venue quotes (or manual probabilities) for the same bet for a guaranteed, fee-aware, direction-independent profit; reports which side to buy where

### Options

- `workflow.run_options_payoff`: Payoff, P&L, and breakeven for a single-leg Deribit (coin-settled) or Binance (USDT-settled) option (long/short call/put)
- `workflow.run_black_scholes`: Theoretical option price and Greeks from Black-Scholes, manual inputs
- `workflow.run_option_greeks`: First and second order Greeks of a European option with a dividend yield: delta, gamma, vega, theta, rho, vanna, vomma, charm, veta, speed, zomma and color
- `workflow.run_black_scholes_live`: Black-Scholes price/Greeks for a real live Deribit, Binance or Bybit (USDT-settled) option, checked against its own quoted mark price
- `workflow.run_straddle_strangle`: Combined payoff, both breakevens, and max loss/profit for a Deribit (coin-settled) or Binance (USDT-settled) straddle or strangle
- `workflow.run_covered_call_protective_put`: Annualized yield (covered call) or insurance cost (protective put) for coin held against one Deribit or Binance option leg
- `workflow.run_implied_volatility`: Solves for the volatility Black-Scholes needs to reproduce an observed option price (Newton-Raphson + bisection fallback); the identifiable field is false when the price barely responds to volatility
- `workflow.run_strategy_picker`: Ranks option strategies (spreads, straddle, strangle, butterfly, iron condor, covered call, protective put and more) for a price target and a volatility view: legs at the best strikes, max profit and max loss (null = unlimited), breakevens, expected profit and probability of profit under a lognormal view, return on risk; Black-Scholes at one implied volatility, fetches nothing
- `workflow.run_cash_secured_put`: Premium income, cash held, period and annualized return, effective buy price, breakeven and loss below it for a cash-secured put on a stock or ETF (100-share contracts), optionally compared with buying the shares now
- `workflow.run_options_position`: Payoff at expiry in dollars for 1 to 4 stock, ETF or index option legs (100-share multiplier, premium per share) plus optional shares: every breakeven, max profit and max loss (null = unlimited), net debit or credit, strategy name; uses the prices given, fetches nothing; not the coin-settled Deribit payoff
- `workflow.run_barrier_touch`: Probability that price touches a target or stop level at any time within N days (geometric Brownian motion, continuous monitoring), next to the probability of finishing beyond it; not the end-of-window question
- `workflow.run_spread_payoff`: Payoff, breakeven(s), and max profit/loss for a vertical spread (2 legs) or iron condor/butterfly (4 legs): Deribit coin-settled or Binance USDT-settled

### Forex

- `workflow.run_forex_pip_value`: Value of 1 pip for a pair and position size, in that pair's own quote currency: no live FX rate needed
- `workflow.run_forex_margin_level`: Free margin and margin level % from account equity and used margin
- `workflow.run_forex_breakeven`: Breakeven price accounting for spread and round-trip commission, in pips and in price
- `workflow.run_forex_pnl`: Profit or loss for a forex trade, in pips and in the pair's own quote currency, long or short
- `workflow.run_fibonacci_levels`: Fibonacci retracement and extension price levels from a swing high and low, any asset
- `workflow.run_forex_risk_reward`: Risk and reward distance in pips from entry/stop/target, and the resulting ratio
- `workflow.run_forex_scenario`: PnL across a range of hypothetical price moves in pips, long or short
- `workflow.run_forex_average_entry`: Size-weighted average entry price across multiple fills: plain arithmetic mean
- `workflow.run_forex_margin_required`: Notional and margin required for a position, in the pair's own quote currency: no live FX rate needed
- `workflow.run_forex_currency_converter`: Converts an amount between currencies using a manually supplied rate
- `workflow.run_forex_pip_value_live`: Pip value converted to a given account currency via a live FX rate (TrueFX majors, frankfurter.app fallback)
- `workflow.run_forex_margin_required_live`: Margin required converted to a given account currency via a live FX rate
- `workflow.run_forex_position_size_live`: Position size from a risk amount and stop distance, sized in a given account currency via a live FX rate
- `workflow.run_forex_currency_converter_live`: Converts an amount between currencies using a live FX rate (TrueFX majors, frankfurter.app fallback)
- `workflow.run_forex_swap_cost`: Total swap/rollover cost for holding a position overnight, in the pair's own quote currency (swap rate is always a manual input: broker-set, no live feed)
- `workflow.run_forex_swap_cost_live`: Swap/rollover cost converted to a given account currency via a live FX rate
- `workflow.run_forex_correlation`: Correlation and minimum-variance hedge ratio between two price series, computed on daily % returns
- `workflow.run_forex_correlation_live`: Correlation and hedge ratio between two forex pairs, fetched live from frankfurter.app's daily historical rates

### Risk/Stats

- `workflow.run_var_cvar`: Parametric Value at Risk and Conditional VaR (Expected Shortfall) from a return series or a direct mean/stdev, at any confidence level
- `workflow.run_sharpe_stats`: Sharpe ratio with the Lo (2002) serial-correlation-aware annualization correction, plus the Probabilistic Sharpe Ratio (Bailey & Lopez de Prado)
- `workflow.run_hurst_exponent`: Hurst exponent via rescaled-range (R/S) analysis: trending, mean-reverting, or random walk
- `workflow.run_cointegration`: Engle-Granger two-step cointegration test for a pair of price series, with the hedge ratio from the cointegrating regression
- `workflow.run_portfolio_tearsheet`: Core risk/return tearsheet from a return series: annualized return/volatility, Sharpe (plain/Lo/Adjusted), Sortino, max drawdown, Calmar, Ulcer/Martin, Pain Index/ratio, Burke, Omega-Sharpe, Upside Potential Ratio, skew/kurtosis, PSR, win rate
- `workflow.run_garch`: GARCH(1,1) volatility model fit by maximum likelihood on a return series: omega/alpha/beta persistence and a one-period-ahead volatility forecast
- `workflow.run_risk_parity`: Risk-parity (equal or custom risk contribution) portfolio weights for N assets, from a covariance matrix or raw return series
- `workflow.run_dsr`: Deflated Sharpe Ratio: the Sharpe threshold the best of N tried strategy variants would clear by luck alone, corrected for correlated trials
- `workflow.run_kelly_frontier`: Kelly growth-security frontier: probability a fractional-Kelly strategy ever loses a given fraction of its starting capital, or the fraction of Kelly that keeps that probability under a target
- `workflow.run_unsmoothing`: Return unsmoothing: Getmansky-Lo-Makarov MA(2) smoothing index and Blundell-Ward AR(1) volatility inflation for infrequently-marked or appraisal-based return series
- `workflow.run_monte_carlo`: Monte Carlo simulation of a portfolio under geometric Brownian motion with periodic contributions or withdrawals: percentiles, mean with standard error, probability of ruin and a fan of bands, deterministic by seed
- `workflow.run_evt_tail_risk`: Extreme Value Theory tail risk: Peaks-Over-Threshold Generalized Pareto VaR/Expected Shortfall via Grimshaw's profile-likelihood MLE, without assuming a normal distribution
- `workflow.run_price_consensus`: Cross-exchange agreement for one perp price: median of a 7-exchange reference set, spread, and the deviation of the chosen exchange; says the exchanges disagree instead of guessing
- `workflow.run_orderbook_impact`: Order-book "walk the book" impact/capacity: VWAP and price impact in bps for a target notional, or the max notional within an impact budget via bisection

## Examples: request & response

### PnL on a BTC long

Tool: `workflow.run_pnl_planning`

```bash
curl -X POST https://tradingcalc.io/api/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "workflow.run_pnl_planning",
      "arguments": {
        "side": "long",
        "entryPrice": 83000,
        "exitPrice": 85000,
        "size": 0.1,
        "feeOpenPct": 0.0002,
        "feeClosePct": 0.0005
      }
    }
  }'
```

result.content[0].text:

```json
{
  "pnl": 194.09,
  "pnlPct": 0.02339,
  "fees": 5.91,
  "gross": 200.00
}
```

### Position size from risk %

Tool: `workflow.run_position_sizing`

```bash
curl -X POST https://tradingcalc.io/api/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "workflow.run_position_sizing",
      "arguments": {
        "side": "long",
        "entryPrice": 83000,
        "stopLoss": 81000,
        "riskUsdt": 100,
        "leverage": 5
      }
    }
  }'
```

result.content[0].text:

```json
{
  "sizeBase": 0.04861,
  "sizeQuote": 4034.56,
  "margin": 806.91,
  "stopDistPct": 2.41
}
```

### Full pre-trade risk check

Tool: `workflow.run_pre_trade_check`

```bash
curl -X POST https://tradingcalc.io/api/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "workflow.run_pre_trade_check",
      "arguments": {
        "side": "long",
        "entry_price": 83000,
        "stop_loss": 81000,
        "account_balance": 5000,
        "risk_pct": 2,
        "leverage": 5,
        "funding_rate": 0.0001,
        "hold_hours": 24
      }
    }
  }'
```

result.content[0].text:

```json
{
  "safety": "ok",
  "recommended_size": 0.04861,
  "notional": 4034.56,
  "margin_required": 806.91,
  "liquidation_price": 66895.00,
  "liquidation_distance_pct": 19.40,
  "breakeven_price": 83023.51,
  "funding_cost_24h": 1.21,
  "summary_a": "Notional 4034.56 USDT · margin 806.91 USDT",
  "summary_b": "Liquidation 19.4% away, stop 2.4%",
  "summary_c": "Over 24h breakeven rises: 83023.51 → 83123.51 USDT",
  "evidence": {
    "funding": { "payments_count": 3, "rate_per_interval": 0.0001, "interval_hours": 8, "interval_source": "default" }
  }
}
```

`funding_rate` is per funding interval, and some symbols pay every 4, 2 or 1 hours on venues that usually pay every 8. `evidence.funding.interval_hours` is the period the rate covers (0.25 to 24) and `interval_source` says where it came from: `input` (you passed `funding_interval_hours`), `exchange` (the venue reported it for this symbol, only when you omit `funding_rate` and give `exchange` and `symbol` so the rate is fetched live), `exchange_default` (the venue's usual interval: the venue gave none for this symbol, because it is not covered, the lookup failed, or no lookup was made) or `default` (8, no exchange named). With a live rate a `funding_interval_hours` you passed is not used, and a differing one comes back as `ignored_funding_interval_hours`. If you supply the rate yourself for a symbol that does not pay every 8 hours, pass `funding_interval_hours`.

## Self-verification

Agents can call `system.verify` before using results. Returns pass/fail for all 54 canonical test vectors. Every formula is traceable to exchange documentation: see [Methodology](https://docs.tradingcalc.io/methodology) for how.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "system.verify", "arguments": {} }
}

// result.content[0].text
{
  "status": "pass",
  "passed": 46,
  "failed": 0,
  "total": 46,
  "timestamp": "2026-09-18T..."
}
```

[Live proof page](https://tradingcalc.io/verification)

## Signed responses

`system.verify` proves the formulas are correct. Every `tools/call` result adds a second proof on top: an ECDSA P-256 signature over the result, so a client can confirm offline that this exact response came from tradingcalc.io and wasn't altered in transit, no callback required. Call `system.pubkey` (or `GET /api/mcp/pubkey`) for the public key and exact verification steps.

Most "deterministic" or "verified" claims from other agent tools stop at formula correctness: a test suite proves the math is right, once, in their repo. That does not prove the specific response your agent received a moment ago wasn't altered by a proxy, a cache, or something in between. The signature above closes that second gap, and it is checkable by anyone, offline, against a public key we publish. No trust required, just arithmetic.

Every `tools/call` result that is a JSON object also carries `_method.release` (the server release), inside the signed text, so a number can be tied to the release that produced it; an array result has no such field (no tool returns one today); `_method` is a reserved key: a value a tool already has under `_method` or `_methodOriginal` is returned inside `_methodOriginal`. The release is repeated in the `X-TradingCalc-Version` header and, when the host provides the deployed commit, its prefix in `X-TradingCalc-Build` (not signed, and not in the body, so identical calls keep identical bytes across deploys). `POST /api/actions/{calc}` is not signed; its JSON body carries the same `_method` and it sends the same two headers, so a stored body still names its release.

```json
{
  "_signature": {
    "alg": "ECDSA P-256, SHA-256, DER signature, base64",
    "kid": "1yH6lOSQMEpffjy8",
    "signedAt": "2026-09-19T12:00:00.000Z",
    "signature": "MEUCIGRC...WRN54=",
    "canonicalFormat": "tradingcalc-mcp-v1\n{tool}\n{signedAt}\n{resultText}"
  },
  "_verify": "Call tool system.pubkey (or GET /api/mcp/pubkey) for the public key and exact verification steps."
}
```

### Several tools in one request

`system.batch` runs up to 10 calls in one `tools/call` request and returns the results together, in the order sent. Arguments: `calls`, a list of `{ name, arguments }`, each exactly as for a single call. Every entry is run as an ordinary call: it counts as one call against your daily limit (the batch request itself is free), gets the same checks, and comes back with its own signature block, so each result verifies on its own with the steps above. The whole reply is signed too.

An entry that fails (bad arguments, unknown tool) comes back with an `error` and does not stop the others. Once the daily limit is reached, or the batch has run for about 20 seconds, the entries after that point are not run and not counted: each comes back with an `error` saying so, and you send them again. A batch cannot contain a batch. Entries run one after another, in order, and none sees the output of another. If the daily limit is reached, the entries after it are not run and not counted.

## Public daily anchor

Once a day the state of the live verification is signed and its SHA-256 is written to Solana mainnet in a Memo transaction. Two public, read-only endpoints expose the records; no key is needed. How to verify a record yourself, step by step, is in the [methodology](https://docs.tradingcalc.io/methodology#public-anchoring).

- `GET /api/anchors?limit=30`: Newest records first, 1 to 100 per call (default 30). Each has the exact record text, its hash, our signature, and the Solana transaction. Cached for 5 minutes.
- `GET /api/anchors/latest`: Only the newest finalized day: date, transaction signature, and explorer link. Cached for 5 minutes.

```json
{
  "address": "8Hi6TUCbcp7UShRcDD5FGP6K6y5DzhrCEa8YH7NWXmHL",
  "network": "solana-mainnet",
  "memoFormat": "tcalc1 {date} {hash}",
  "hashFormat": "sha256("tradingcalc-anchor-v1\n" + recordText), lowercase hex",
  "records": [{
    "date": "2026-09-30",
    "status": "finalized",
    "hash": "6466b0cf...ef50f",
    "memo": "tcalc1 2026-09-30 6466b0cf...ef50f",
    "recordText": "{"build":...,"prevHash":null,...}",
    "signature": { "kid": "1yH6lOSQMEpffjy8", "signedAt": "...", "signature": "MEUC..." },
    "txSignature": "3uwZGLEq...",
    "slot": 451878261,
    "blockTime": "2026-09-30T06:03:48.000Z",
    "explorerUrl": "https://explorer.solana.com/tx/3uwZGLEq..."
  }]
}
```
