Server definition
- Hash
- sha256:521aac7d34e7be9c23b742a99a6a3508314761b1edcada668019fe5589937ee2
- What it is
- What a remote MCP server returned when asked what it offers: 20 tools
The blob, as servednamed by its sha256
{
"instructions": "Tools for the Backtest360 backtesting engine: discover indicators and reference catalogs, build and validate strategy documents, run historical backtests, compare strategies, and compute performance statistics. Recommended flow: engine_info once; get_catalog / list_indicators to ground every name and parameter in what actually exists; validate_strategy until valid; then run_backtest (response_detail='summary' first, deeper only as needed). All numbers come from the engine — never estimate or extrapolate results. The configured API key's plan governs permissions, rate limits, and data access.",
"tools": [
{
"description": "Run several strategies on the same data and compare side by side.\n\n One quota-counted call, but compute scales with the number of\n strategies. If the wall-clock compute budget is exceeded, the call\n fails with a tool error (504) instead of returning partial results —\n narrow the request (fewer strategies, shorter date range, coarser\n frequency) and retry.\n\n Args:\n data_source: Shared data source (same shape as run_backtest).\n strategies: List of {\"label\": str, \"strategy\": {...},\n \"execution\": {...}?} entries. Labels need not be unique or\n id-safe — they are echoed back verbatim in the result.\n include_benchmark: Add a buy-and-hold benchmark to the comparison.\n response_detail: Shaping level applied to each strategy's result.\n trades_limit: Max trades per strategy when detail is 'full'.\n\n Returns:\n {\"strategies\": [{\"label\", \"result\"}, ...], \"equity_curves\": {...},\n \"alignment\"?}, each result shaped at the requested detail. When a\n benchmark is included, non-benchmark entries also carry\n \"relative\" (beta, alpha, information ratio, etc.). A 400/422\n rejection returns {\"accepted\": false, \"error\": ...};\n capacity/timeout/permission failures raise a tool error.\n ",
"inputSchema": {
"properties": {
"data_source": {
"additionalProperties": true,
"title": "Data Source",
"type": "object"
},
"include_benchmark": {
"default": false,
"title": "Include Benchmark",
"type": "boolean"
},
"response_detail": {
"default": "summary",
"enum": [
"summary",
"stats",
"full"
],
"title": "Response Detail",
"type": "string"
},
"strategies": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Strategies",
"type": "array"
},
"trades_limit": {
"default": 50,
"title": "Trades Limit",
"type": "integer"
}
},
"required": [
"data_source",
"strategies"
],
"title": "compare_backtestsArguments",
"type": "object"
},
"name": "compare_backtests",
"outputSchema": {
"additionalProperties": true,
"title": "compare_backtestsDictOutput",
"type": "object"
}
},
{
"description": "Compute the engine's performance metrics from a returns series.\n\n Use when the returns came from somewhere\n other than run_backtest (an external system, a portfolio) — backtest\n results already include these statistics.\n\n Args:\n returns: Per-bar log returns as {\"dates\": [...], \"values\": [...]}\n parallel arrays (ISO-8601 dates).\n trading_days_per_year: Required annualization factor — 252 for a\n daily equities calendar, 365 for 24/7 crypto. Must match the bar\n calendar of the returns series; a wrong value silently\n mis-annualizes Sharpe, volatility, and CAGR.\n benchmark_returns: Optional benchmark series, same shape — adds\n alpha/beta/capture metrics.\n trades: Optional trade records (entry_date, exit_date, direction,\n return_net, ...) — adds trade-level metrics.\n risk_free_rate: Annual risk-free rate as a decimal.\n\n Returns:\n {\"stats\": {...}} — the metric set the API key's plan allows.\n See get_catalog('sections') for every metric's id and description.\n ",
"inputSchema": {
"properties": {
"benchmark_returns": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Benchmark Returns"
},
"returns": {
"additionalProperties": true,
"title": "Returns",
"type": "object"
},
"risk_free_rate": {
"default": 0,
"title": "Risk Free Rate",
"type": "number"
},
"trades": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Trades"
},
"trading_days_per_year": {
"title": "Trading Days Per Year",
"type": "integer"
}
},
"required": [
"returns",
"trading_days_per_year"
],
"title": "compute_statsArguments",
"type": "object"
},
"name": "compute_stats",
"outputSchema": {
"additionalProperties": true,
"title": "compute_statsDictOutput",
"type": "object"
}
},
{
"description": "Engine version, API contract number, and health.\n\n Free (not quota-counted). Call once at the start of a session\n to confirm the engine is reachable and which contract it serves.\n ",
"inputSchema": {
"properties": {},
"title": "engine_infoArguments",
"type": "object"
},
"name": "engine_info",
"outputSchema": {
"additionalProperties": true,
"title": "engine_infoDictOutput",
"type": "object"
}
},
{
"description": "Export a multi-strategy comparison as an Excel workbook.\n\n Quota-counted; needs a key whose plan includes full-metrics export\n (a 403 means the configured key's plan does not — do not retry).\n Returns the workbook base64-encoded — decode and write it to a\n ``.xlsx`` file.\n\n Args:\n data_source: Shared data source (same shape as run_backtest).\n strategies: Same shape as compare_backtests' ``strategies``.\n include_benchmark: Add a buy-and-hold benchmark to the export.\n\n Returns:\n {\"filename\", \"content_type\", \"size_bytes\", \"content_base64\"}. A\n 400/422 rejection returns {\"accepted\": false, \"error\": ...};\n capacity/timeout/permission failures raise a tool error. If the\n encoded workbook would exceed the output size limit, raises a\n tool error — narrow the request (shorter date range, fewer\n strategies, coarser frequency) and retry.\n ",
"inputSchema": {
"properties": {
"data_source": {
"additionalProperties": true,
"title": "Data Source",
"type": "object"
},
"include_benchmark": {
"default": false,
"title": "Include Benchmark",
"type": "boolean"
},
"strategies": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Strategies",
"type": "array"
}
},
"required": [
"data_source",
"strategies"
],
"title": "export_backtestArguments",
"type": "object"
},
"name": "export_backtest",
"outputSchema": {
"additionalProperties": true,
"title": "export_backtestDictOutput",
"type": "object"
}
},
{
"description": "Fetch one engine reference catalog.\n\n Catalogs (cheap, cacheable per session):\n - 'operators' — comparison operators for condition expressions\n - 'execution-modes' — entry/exit anchors and fill algorithms, with the\n validity matrix by market type\n - 'stop-types' — stop-loss types, re-entry modes, and their parameters\n - 'sizing-methods' — position-sizing methods and their parameters\n - 'bar-frequencies' — supported bar frequencies and the signal x\n execution validity matrix (which combinations are allowed)\n - 'sections' — the full metric catalog: every statistic's stable id,\n display label, section, and description\n - 'sampling-modes' — Monte-Carlo resampling modes, each with its\n status and parameters\n\n Fetch the relevant catalog BEFORE building a strategy or config; build\n only from values it lists — never guess parameter names or frequencies.\n ",
"inputSchema": {
"properties": {
"catalog": {
"enum": [
"operators",
"execution-modes",
"stop-types",
"sizing-methods",
"bar-frequencies",
"sections",
"sampling-modes"
],
"title": "Catalog",
"type": "string"
}
},
"required": [
"catalog"
],
"title": "get_catalogArguments",
"type": "object"
},
"name": "get_catalog",
"outputSchema": {
"additionalProperties": true,
"title": "get_catalogDictOutput",
"type": "object"
}
},
{
"description": "Available date range and estimated bar count for a symbol/frequency.\n\n Available on paid plans. Call before a server-side fetch so the\n requested start/end stay inside what the provider can deliver and the\n bar count stays inside the key's per-run limit.\n ",
"inputSchema": {
"properties": {
"frequency": {
"title": "Frequency",
"type": "string"
},
"symbol": {
"title": "Symbol",
"type": "string"
}
},
"required": [
"symbol",
"frequency"
],
"title": "get_data_rangeArguments",
"type": "object"
},
"name": "get_data_range",
"outputSchema": {
"additionalProperties": true,
"title": "get_data_rangeDictOutput",
"type": "object"
}
},
{
"description": "Evaluate the strategy on the most recent bar only — no P&L, no stats.\n\n Returns the latest signal (-1/0/1), which\n condition slots fired, and the bar timestamp. Use for \"what would this\n strategy do right now\" questions; use run_backtest for performance.\n ",
"inputSchema": {
"properties": {
"data_inputs": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Data Inputs"
},
"data_source": {
"additionalProperties": true,
"title": "Data Source",
"type": "object"
},
"execution": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Execution"
},
"strategy": {
"additionalProperties": true,
"title": "Strategy",
"type": "object"
}
},
"required": [
"data_source",
"strategy"
],
"title": "get_latest_signalArguments",
"type": "object"
},
"name": "get_latest_signal",
"outputSchema": {
"additionalProperties": true,
"title": "get_latest_signalDictOutput",
"type": "object"
}
},
{
"description": "Observations for one macroeconomic series over an optional date range.\n\n Free — no special plan. ``series`` is an ``id`` from list_macro_series\n (e.g. treasury_10y, cpi, unemployment_rate); arbitrary external ids are\n not accepted. ``start``/``end`` are ``YYYY-MM-DD``, inclusive, both\n optional (full history when omitted). Returns the value series at its\n native reporting frequency, with the series descriptor and an ``as_of``\n date. A long history is downsampled by the MCP server to a bounded\n number of points (first and last kept), marked with\n ``downsampled_from_bars`` and ``points_returned`` on the\n ``observations`` block.\n\n Note: values are the latest revised figures stamped by reference period,\n not point-in-time as-first-reported data — do not treat them as the\n values that were known at a past date.\n ",
"inputSchema": {
"properties": {
"end": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "End"
},
"series": {
"title": "Series",
"type": "string"
},
"start": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Start"
}
},
"required": [
"series"
],
"title": "get_macro_seriesArguments",
"type": "object"
},
"name": "get_macro_series",
"outputSchema": {
"additionalProperties": true,
"title": "get_macro_seriesDictOutput",
"type": "object"
}
},
{
"description": "The configured API key's permissions, limits, and current usage.\n\n Cheap. Call early in a session — before planning work — to learn what\n this key can do instead of discovering limits through failed calls.\n\n Returns:\n ``scopes``: the permission scopes the key carries. ``limits``:\n requests per minute and per day, max concurrent requests, and the\n per-run bar cap (null when uncapped). ``usage``: current\n consumption against those limits, with reset countdowns in\n seconds. ``capabilities``: feature flags such as server-side data\n fetch and the full metric set. A small fixed-shape record,\n returned as the engine sent it.\n ",
"inputSchema": {
"properties": {},
"title": "get_meArguments",
"type": "object"
},
"name": "get_me",
"outputSchema": {
"additionalProperties": true,
"title": "get_meDictOutput",
"type": "object"
}
},
{
"description": "OHLCV price history for a symbol over a date range.\n\n Requires a paid plan (managed market data). ``start`` is required\n (``YYYY-MM-DD``); ``end`` defaults to today. Returns a summary (symbol,\n resolved date range, total bar count, price range, gap flags),\n market-hours detection, and the OHLCV arrays. A long history is\n downsampled by the MCP server to a bounded number of points — first and\n last bar always kept, every column thinned on the same dates — with\n ``downsampled_from_bars`` and ``points_returned`` recorded on the\n ``ohlcv`` block; the untouched ``summary.total_bars`` still reports the\n true bar count. The window is bounded by the plan's per-request bar cap\n — call get_data_range first to size a request.\n ",
"inputSchema": {
"properties": {
"end": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "End"
},
"frequency": {
"default": "daily",
"title": "Frequency",
"type": "string"
},
"start": {
"title": "Start",
"type": "string"
},
"symbol": {
"title": "Symbol",
"type": "string"
}
},
"required": [
"symbol",
"start"
],
"title": "get_price_historyArguments",
"type": "object"
},
"name": "get_price_history",
"outputSchema": {
"additionalProperties": true,
"title": "get_price_historyDictOutput",
"type": "object"
}
},
{
"description": "Latest available price for a symbol.\n\n Requires a paid plan (managed market data). Returns the most recent\n *available* bar for the given frequency — the end-of-day close for\n daily, the last completed bar otherwise — as open/high/low/close/volume\n plus an ``as_of`` timestamp for that bar. This is a last-known price,\n not a live tick; read ``as_of`` to judge how stale it is.\n ",
"inputSchema": {
"properties": {
"frequency": {
"default": "daily",
"title": "Frequency",
"type": "string"
},
"symbol": {
"title": "Symbol",
"type": "string"
}
},
"required": [
"symbol"
],
"title": "get_quoteArguments",
"type": "object"
},
"name": "get_quote",
"outputSchema": {
"additionalProperties": true,
"title": "get_quoteDictOutput",
"type": "object"
}
},
{
"description": "JSON Schema for the strategy document (condition_tree + indicators).\n\n Fetch this before composing a strategy by hand; the\n validate_strategy tool checks against the same rules.\n ",
"inputSchema": {
"properties": {},
"title": "get_strategy_schemaArguments",
"type": "object"
},
"name": "get_strategy_schema",
"outputSchema": {
"additionalProperties": true,
"title": "get_strategy_schemaDictOutput",
"type": "object"
}
},
{
"description": "Identity and data coverage for one symbol, in a single call.\n\n Metadata only — no market data, so no paid plan is needed. Returns the\n asset's identity (name, asset class, exchange, currency, and whether it\n is still active) together with a coverage summary for the given\n frequency: the available date range and an estimated bar count. Use it\n to confirm a symbol resolves and that the history you need exists before\n requesting a quote or a price fetch. For the precise per-frequency range\n use get_data_range.\n ",
"inputSchema": {
"properties": {
"frequency": {
"default": "daily",
"title": "Frequency",
"type": "string"
},
"symbol": {
"title": "Symbol",
"type": "string"
}
},
"required": [
"symbol"
],
"title": "get_ticker_infoArguments",
"type": "object"
},
"name": "get_ticker_info",
"outputSchema": {
"additionalProperties": true,
"title": "get_ticker_infoDictOutput",
"type": "object"
}
},
{
"description": "List indicators, or fetch one indicator's full schema.\n\n Cheap, cacheable per session.\n\n With no arguments: a compact catalog — ``{\"indicators\": [...],\n \"count\": N}`` — where each entry carries id, name, category, kind,\n and value_dtype (no description, to keep the discovery scan small). Use\n it to discover what exists. Pass name='rsi' (id or name,\n case-insensitive) to get that single indicator's complete entry\n including its description and params_schema — do this before adding an\n indicator to a strategy so its parameters are exactly right.\n Pass compact=False for full entries for everything (large; the MCP\n server may cap it and set ``truncated_by_mcp`` — prefer compact or\n name=).\n\n Wire optimization: the compact discovery path asks the engine to omit\n per-entry descriptions (``descriptions=false``) since they are stripped\n locally anyway; the name= and compact=False paths request them. This is\n a pure saving — if the engine ignores the param it returns full entries\n and the local compact strip still yields a lean result.\n ",
"inputSchema": {
"properties": {
"compact": {
"default": true,
"title": "Compact",
"type": "boolean"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Name"
}
},
"title": "list_indicatorsArguments",
"type": "object"
},
"name": "list_indicators",
"outputSchema": null
},
{
"description": "List the available macroeconomic series (the catalog).\n\n Free — no special plan. Returns the set of macro series you can fetch\n with get_macro_series, each with its stable ``id`` (the value\n get_macro_series takes), title, category, native reporting frequency,\n and units, plus the list of categories. Optionally filter to one\n ``category`` (e.g. rates, yield_curve, inflation, employment, recession,\n growth). Call this first to find the ``id`` for the series you want.\n ",
"inputSchema": {
"properties": {
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Category"
}
},
"title": "list_macro_seriesArguments",
"type": "object"
},
"name": "list_macro_series",
"outputSchema": {
"additionalProperties": true,
"title": "list_macro_seriesDictOutput",
"type": "object"
}
},
{
"description": "List predesigned strategy templates, or fetch one in full.\n\n Cheap, cacheable per session. The engine returns the templates\n available to the calling key.\n\n With no arguments: a compact catalog — ``{\"templates\": [...],\n \"count\": N}`` — where each entry carries id, origin, name, and\n description. Use it to discover what exists. Pass name='sma-cross'\n (id or name, case-insensitive) to get that single template's complete\n entry: its strategy logic (``condition_tree`` + ``indicators``, the\n same shape validate_strategy and run_backtest accept) plus parameter\n metadata — ``defaults`` (starting parameter values), ``requires``,\n and ``locked_params`` (parameters that must keep their template\n values). Pass compact=False for complete entries for everything\n (large; the MCP server may cap it and set ``truncated_by_mcp`` —\n prefer compact or name=).\n ",
"inputSchema": {
"properties": {
"compact": {
"default": true,
"title": "Compact",
"type": "boolean"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Name"
}
},
"title": "list_templatesArguments",
"type": "object"
},
"name": "list_templates",
"outputSchema": null
},
{
"description": "List available tickers, optionally filtered by asset class.\n\n The full universe is very large, so the MCP server\n caps the returned list and marks it ``truncated_by_mcp`` — pass\n asset_class to narrow it, or use search_tickers to resolve a specific\n asset by name.\n ",
"inputSchema": {
"properties": {
"asset_class": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Asset Class"
}
},
"title": "list_tickersArguments",
"type": "object"
},
"name": "list_tickers",
"outputSchema": {
"additionalProperties": true,
"title": "list_tickersDictOutput",
"type": "object"
}
},
{
"description": "Run a historical backtest against the engine.\n\n Quota-counted and compute-bound. Validate the\n strategy first (validate_strategy is far cheaper). On a 504 compute\n timeout, do NOT retry the same request — reduce the date range, use a\n coarser frequency, or simplify the strategy. On 429/503, wait for the\n advertised Retry-After before retrying.\n\n Args:\n data_source: Either inline OHLCV ({\"ohlcv\": {dates, open, high,\n low, close, volume?}} as parallel arrays, ISO-8601 dates) or a\n server-side fetch ({\"symbol\", \"start\", \"end\", \"frequency\"} —\n requires a paid plan).\n strategy: Strategy document (indicators[] + condition_tree).\n Mutually exclusive with signals.\n signals: Precomputed signal series ({\"dates\": [...], \"values\":\n [-1|0|1, ...]}). Mutually exclusive with strategy.\n execution: Execution/cost/risk/sizing settings. Use values from\n get_catalog('execution-modes'/'stop-types'/'sizing-methods');\n omit for engine defaults.\n benchmark: Optional benchmark data source (same shape as\n data_source) — when given, the result also carries\n benchmark-relative metrics (beta, alpha, information ratio,\n tracking error, up/down capture) and bar-alignment info.\n data_inputs: Optional custom time-series the strategy references\n (name -> {dates, values}).\n response_detail: 'summary' (default — headline metrics, smallest),\n 'stats' (every metric), 'full' (plus trades and series\n downsampled to a fixed, server-controlled number of points).\n include: Optional add-on blocks at any detail level: 'trades',\n 'equity_curve', 'monthly_returns', 'yearly_returns',\n 'signal_diagnostics' (which per-bar entry/exit conditions\n fired, as capped fire-date lists — {\"available\": false, ...}\n if the run has none, e.g. precomputed signals).\n trades_limit: Max trades returned when trades are included.\n\n Returns:\n The shaped result at the requested detail (including\n ``benchmark_relative``/``alignment`` when a benchmark was given);\n an oversized result is thinned and marked ``truncated_by_mcp``. If\n the engine rejects the request as invalid (400/422), returns\n {\"accepted\": false, \"error\": ...} so you can fix the named\n field(s) and retry. Capacity, timeout, and permission failures\n (e.g. 429/503/504/401/403) raise a tool error carrying explicit\n recovery guidance.\n ",
"inputSchema": {
"properties": {
"benchmark": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Benchmark"
},
"data_inputs": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Data Inputs"
},
"data_source": {
"additionalProperties": true,
"title": "Data Source",
"type": "object"
},
"execution": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Execution"
},
"include": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Include"
},
"response_detail": {
"default": "summary",
"enum": [
"summary",
"stats",
"full"
],
"title": "Response Detail",
"type": "string"
},
"signals": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Signals"
},
"strategy": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Strategy"
},
"trades_limit": {
"default": 50,
"title": "Trades Limit",
"type": "integer"
}
},
"required": [
"data_source"
],
"title": "run_backtestArguments",
"type": "object"
},
"name": "run_backtest",
"outputSchema": {
"additionalProperties": true,
"title": "run_backtestDictOutput",
"type": "object"
}
},
{
"description": "Search available assets by ticker or name (relevance-ranked).\n\n Use to resolve a user's asset mention (\"bitcoin\",\n \"S&P\") to the exact ticker before requesting a server-side data fetch.\n asset_class filters to 'stocks', 'crypto', 'forex', or 'indices'.\n ",
"inputSchema": {
"properties": {
"asset_class": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Asset Class"
},
"limit": {
"default": 20,
"title": "Limit",
"type": "integer"
},
"query": {
"title": "Query",
"type": "string"
}
},
"required": [
"query"
],
"title": "search_tickersArguments",
"type": "object"
},
"name": "search_tickers",
"outputSchema": {
"additionalProperties": true,
"title": "search_tickersDictOutput",
"type": "object"
}
},
{
"description": "Validate a strategy document without running a backtest.\n\n A cheap quota separate from backtest runs,\n so validate freely and ALWAYS before run_backtest.\n\n Args:\n strategy: The strategy document — name, indicators[], and\n condition_tree (see get_strategy_schema for the exact shape).\n injected_indicators: Names of custom time-series columns the\n caller will supply via data_inputs at run time, so conditions\n referencing them validate.\n\n Returns:\n On success: {\"valid\": true, \"warmup_bars\": ..., referenced\n indicators/columns}. On failure: {\"valid\": false, \"errors\": [...]}\n where each error carries a machine code, the location in the\n document, a message, and context (e.g. the list of valid column\n names). A failed validation is a NORMAL result, not an error —\n read the errors, fix the document, and validate again before\n running.\n ",
"inputSchema": {
"properties": {
"injected_indicators": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Injected Indicators"
},
"strategy": {
"additionalProperties": true,
"title": "Strategy",
"type": "object"
}
},
"required": [
"strategy"
],
"title": "validate_strategyArguments",
"type": "object"
},
"name": "validate_strategy",
"outputSchema": {
"additionalProperties": true,
"title": "validate_strategyDictOutput",
"type": "object"
}
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:521aac7d34e7be9c23b742a99a6a3508314761b1edcada668019fe5589937ee2 | sha256sum