API & MCP Reference
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.
https://tradingcalc.io/api/mcp
Install in 30 seconds
{ "mcpServers": { "tradingcalc": { "command": "npx", "args": ["-y", "mcp-remote", "https://tradingcalc.io/api/mcp"] } }}{ "tradingcalc": { "url": "https://tradingcalc.io/api/mcp" }}# pip install langchain-tradingcalcfrom 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)# pip install openai-agents# Tool names have a dot, OpenAI function names# reject it (400). The hosted MCP tool avoids it.import asynciofrom 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())# 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)// npm install ai @ai-sdk/mcpimport { 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 modelconst 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// npm install @mastra/mcpimport { 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)# pip install "crewai-tools[mcp]"# Python 3.12 or 3.13, not 3.14 (crewai limit)from crewai import Agent, Crew, Taskfrom 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()){ "mcpServers": { "tradingcalc": { "httpUrl": "https://tradingcalc.io/api/mcp" } }}# 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_agentfrom google.adk.agents import LlmAgentfrom google.adk.tools.mcp_tool import McpToolsetfrom 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"), )],)Agent, Tools, Add a tool, New tool, Model Context ProtocolServer name: TradingCalcServer URL: https://tradingcalc.io/api/mcpAuthentication: NoneCreate, create the connection, add the tool to the agent(generative orchestration must be on for the agent)Google Cloud console, Gemini Enterprise, Data stores,Create data store, Custom MCP Server, Add MCP serverServer URL: https://tradingcalc.io/api/mcpAuthentication: No authenticationAfter creation: Actions tab, Reload custom actions,enable the tools you want, then connect the datastore to your app (an admin may first need to liftthe organization policy that blocks custom MCP servers)Settings, Connectors, + Custom connector, RemoteName: TradingCalcServer URL: https://tradingcalc.io/api/mcpAuthentication: noneSave, then enable the connector inside a thread(availability depends on your plan; on Enterprise anadmin may need to allow custom connectors)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" } } }'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"] } }}// 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, perpshttps://tradingcalc.io/api/mcp?set=optionshttps://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. 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, 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 withRetry-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/callcounts toward the quota.initialize,tools/list,pingand notifications are free, and so is a request the server rejects as malformed or for an unknown method - Protocol:
initializeanswers 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) narrowstools/listand theinitializeinstructions 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
workflow.run_pnl_planningNet PnL, ROE, fees and gross P&L for a futures tradeworkflow.run_breakeven_planningBreak-even price accounting for entry and exit feesworkflow.run_exit_targetExit price required to hit a target PnL or ROEworkflow.run_position_sizingPosition size from account balance and max risk %primitive.average_entryAverage entry price after DCA into a positionworkflow.run_scenario_planningMulti-scenario P&L table across price targetsworkflow.run_dca_entryWeighted average entry, breakeven, and per-level contribution from multiple fillsworkflow.run_average_downShould-I-average-down check: new average entry, liquidation, breakeven, and risk before/after, benchmarked against a fresh entry at today's priceworkflow.run_scale_outP&L, ROI, and cumulative P&L for each partial exit levelworkflow.run_liquidation_safetyLiquidation price for long/short, isolated margin, one flat maintenance rateworkflow.run_max_leverageMaximum safe leverage given account size and volatilityprimitive.hedge_ratioShort perp size to fully hedge a spot position, including funding costworkflow.run_risk_rewardFull R:R analysis: position size, liquidation, breakeven, P&L at stop and target. Returns verdict.workflow.run_portfolio_riskAggregates P&L, margin usage, and liquidation distance across every open position. Returns verdict.workflow.run_funding_costCumulative funding cost over a holding periodworkflow.run_funding_arbitrageAnnualized funding arbitrage yield between two exchangesworkflow.run_compound_fundingCapital growth from reinvested funding income, with withdrawn income and APYworkflow.run_carry_tradeDelta-neutral carry: net yield, gross/net profit, breakeven days. Returns verdict.workflow.run_funding_breakevenPrice move needed to cover funding cost + fees over a holding periodworkflow.run_pre_trade_checkFull pre-trade risk analysis: position size, liquidation price, breakeven, funding cost, and safety classification in one callworkflow.run_open_analysisMarket Profile open analysis: open location, open type (OD/OTD/ORR/OAIR), VAH/VAL/VPOC/IB, and scenario framingworkflow.run_session_structureDay-type classifier: trend / balance / neutral_trend / normal / normal_varworkflow.run_value_migrationValue-area migration across sessions: directional conviction vs balanceworkflow.run_breakout_acceptanceBreakout acceptance vs rejection beyond the value area (with optional delta)workflow.run_crypto_profitProfit 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+ daysworkflow.run_present_valuePresent value of a lump sum, a level payment stream or both at a discount rate: ordinary annuity or annuity due, any compounding frequencyworkflow.run_future_valueFuture value of a starting sum and regular contributions at a fixed rate, with total contributions and interest earnedworkflow.run_npvNet present value of a list of cash flows at a rate per period; the first flow is at time 0 and is not discountedworkflow.run_irrInternal rate of return of a list of cash flows; with several sign changes it lists every rate found and gives no single answerworkflow.run_cagrCompound annual growth rate between a beginning and an ending value over a number of yearsworkflow.run_apy_apr_converterConvert an APR to an APY or back for a chosen compounding (periods per year or continuous)workflow.run_bond_pricePrice, Macaulay and modified duration, convexity and DV01 of a fixed-rate bond at a yield to maturityworkflow.run_token_risk_checkSolana token rug-pull mechanism check: mint/freeze authority, LP lock, mutable metadata, named scam-pattern flagsworkflow.run_swap_price_impactLive price-impact quote for a Solana swap, selling or buying, routed through Jupiter across every pool it knows aboutworkflow.run_bonding_curvePump.fun-style bonding curve: exact tokens received, price impact, and graduation progressworkflow.run_market_cap_comparisonLive market-cap ratio between two tokens (Solana or 5 EVM chains) projected onto an investmentworkflow.run_wallet_flag_checkWallet address check against independent flag databases (GoPlus, Webacy, ScamSniffer): sanctions, phishing, exchange labelsworkflow.run_impermanent_lossImpermanent loss for a liquidity-pool position, full-range or Uniswap-V3-style concentrated: LP value vs. holding, manual pricesworkflow.run_impermanent_loss_liveLive variant: fetches both tokens' current prices (Solana or 5 EVM chains) and derives the price ratio automaticallyworkflow.run_odds_converterConverts 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_readerworkflow.run_market_implied_oddsReads Kalshi's live BTC/ETH year-end price ladder: median and mode price bucket, probability at/above any boundaryworkflow.run_prediction_market_edgeCompares your probability estimate against a Kalshi/Limitless/Myriad market price and sizes a bet with fractional Kellyworkflow.run_window_fair_valueTheoretical 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 yetworkflow.run_spread_readerReads 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_converterworkflow.run_cross_venue_arbitrageChecks 2-5 venue quotes (or manual probabilities) for the same bet for a guaranteed, fee-aware, direction-independent profit; reports which side to buy whereworkflow.run_options_payoffPayoff, P&L, and breakeven for a single-leg Deribit (coin-settled) or Binance (USDT-settled) option (long/short call/put)workflow.run_black_scholesTheoretical option price and Greeks from Black-Scholes, manual inputsworkflow.run_option_greeksFirst and second order Greeks of a European option with a dividend yield: delta, gamma, vega, theta, rho, vanna, vomma, charm, veta, speed, zomma and colorworkflow.run_black_scholes_liveBlack-Scholes price/Greeks for a real live Deribit, Binance or Bybit (USDT-settled) option, checked against its own quoted mark priceworkflow.run_straddle_strangleCombined payoff, both breakevens, and max loss/profit for a Deribit (coin-settled) or Binance (USDT-settled) straddle or strangleworkflow.run_covered_call_protective_putAnnualized yield (covered call) or insurance cost (protective put) for coin held against one Deribit or Binance option legworkflow.run_implied_volatilitySolves 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 volatilityworkflow.run_strategy_pickerRanks 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 nothingworkflow.run_cash_secured_putPremium 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 nowworkflow.run_options_positionPayoff 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 payoffworkflow.run_barrier_touchProbability 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 questionworkflow.run_spread_payoffPayoff, breakeven(s), and max profit/loss for a vertical spread (2 legs) or iron condor/butterfly (4 legs): Deribit coin-settled or Binance USDT-settledworkflow.run_forex_pip_valueValue of 1 pip for a pair and position size, in that pair's own quote currency: no live FX rate neededworkflow.run_forex_margin_levelFree margin and margin level % from account equity and used marginworkflow.run_forex_breakevenBreakeven price accounting for spread and round-trip commission, in pips and in priceworkflow.run_forex_pnlProfit or loss for a forex trade, in pips and in the pair's own quote currency, long or shortworkflow.run_fibonacci_levelsFibonacci retracement and extension price levels from a swing high and low, any assetworkflow.run_forex_risk_rewardRisk and reward distance in pips from entry/stop/target, and the resulting ratioworkflow.run_forex_scenarioPnL across a range of hypothetical price moves in pips, long or shortworkflow.run_forex_average_entrySize-weighted average entry price across multiple fills: plain arithmetic meanworkflow.run_forex_margin_requiredNotional and margin required for a position, in the pair's own quote currency: no live FX rate neededworkflow.run_forex_currency_converterConverts an amount between currencies using a manually supplied rateworkflow.run_forex_pip_value_livePip value converted to a given account currency via a live FX rate (TrueFX majors, frankfurter.app fallback)workflow.run_forex_margin_required_liveMargin required converted to a given account currency via a live FX rateworkflow.run_forex_position_size_livePosition size from a risk amount and stop distance, sized in a given account currency via a live FX rateworkflow.run_forex_currency_converter_liveConverts an amount between currencies using a live FX rate (TrueFX majors, frankfurter.app fallback)workflow.run_forex_swap_costTotal 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_liveSwap/rollover cost converted to a given account currency via a live FX rateworkflow.run_forex_correlationCorrelation and minimum-variance hedge ratio between two price series, computed on daily % returnsworkflow.run_forex_correlation_liveCorrelation and hedge ratio between two forex pairs, fetched live from frankfurter.app's daily historical ratesworkflow.run_var_cvarParametric Value at Risk and Conditional VaR (Expected Shortfall) from a return series or a direct mean/stdev, at any confidence levelworkflow.run_sharpe_statsSharpe ratio with the Lo (2002) serial-correlation-aware annualization correction, plus the Probabilistic Sharpe Ratio (Bailey & Lopez de Prado)workflow.run_hurst_exponentHurst exponent via rescaled-range (R/S) analysis: trending, mean-reverting, or random walkworkflow.run_cointegrationEngle-Granger two-step cointegration test for a pair of price series, with the hedge ratio from the cointegrating regressionworkflow.run_portfolio_tearsheetCore 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 rateworkflow.run_garchGARCH(1,1) volatility model fit by maximum likelihood on a return series: omega/alpha/beta persistence and a one-period-ahead volatility forecastworkflow.run_risk_parityRisk-parity (equal or custom risk contribution) portfolio weights for N assets, from a covariance matrix or raw return seriesworkflow.run_dsrDeflated Sharpe Ratio: the Sharpe threshold the best of N tried strategy variants would clear by luck alone, corrected for correlated trialsworkflow.run_kelly_frontierKelly 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 targetworkflow.run_unsmoothingReturn unsmoothing: Getmansky-Lo-Makarov MA(2) smoothing index and Blundell-Ward AR(1) volatility inflation for infrequently-marked or appraisal-based return seriesworkflow.run_monte_carloMonte 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 seedworkflow.run_evt_tail_riskExtreme Value Theory tail risk: Peaks-Over-Threshold Generalized Pareto VaR/Expected Shortfall via Grimshaw's profile-likelihood MLE, without assuming a normal distributionworkflow.run_price_consensusCross-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 guessingworkflow.run_orderbook_impactOrder-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 bisectionExamples: request & response
workflow.run_pnl_planningcurl -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 } } }'{ "pnl": 194.09, "pnlPct": 0.02339, "fees": 5.91, "gross": 200.00}workflow.run_position_sizingcurl -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 } } }'{ "sizeBase": 0.04861, "sizeQuote": 4034.56, "margin": 806.91, "stopDistPct": 2.41}workflow.run_pre_trade_checkcurl -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 } } }'{ "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 for how.
{ "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..."}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.
{ "_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.
GET /api/anchors?limit=30Newest 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/latestOnly the newest finalized day: date, transaction signature, and explorer link. Cached for 5 minutes.
{ "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..." }]}