EmidLabs Backtest
REMOTE · MCP.BACKTEST.EMIDLABS.COM · SCANNED SEP 20
Run crypto trading strategy backtests through EmidLabs's Backtesting API.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score → Why this is hard to score →
Endpoint Security74
- The endpoint's TLS certificate is valid, in date, and uses a strong key. View diagnostics → Pass
- No authorisation is required to call this server. Every tool declares its destructiveHint and none is destructive, so open access doesn't expose one. See how to fix → View diagnostics → Partial
- HTTPS is enforced; there's no plaintext access path. View diagnostics → Pass
- HSTS check failed: the Strict-Transport-Security header is absent. See how to fix → View diagnostics → Fail
- DNSSEC check failed: this domain isn't protected by DNSSEC. See how to fix → View diagnostics → Fail
Transport & Reachability100
- Verified streamable-http transport via a live MCP handshake. View diagnostics → Pass
Schema Quality & AI Usability77
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 2954 tokens (~295/item across 10 items; 9 tools + 1 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management100
- No destabilizing schema changes in the last 30 days.Pass
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- We read all 9 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
- An AI judge read all 11 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the EmidLabs Backtest MCP server?
EmidLabs Backtest is a hosted endpoint at https://mcp.backtest.emidlabs.com/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
remote · mcp.backtest.emidlabs.com
claude mcp add --transport http emidlabs-backtest-mcp 'https://mcp.backtest.emidlabs.com/mcp'
{
"mcpServers": {
"emidlabs-backtest-mcp": {
"url": "https://mcp.backtest.emidlabs.com/mcp"
}
}
} {
"servers": {
"emidlabs-backtest-mcp": {
"type": "http",
"url": "https://mcp.backtest.emidlabs.com/mcp"
}
}
} [mcp_servers.emidlabs-backtest-mcp] url = "https://mcp.backtest.emidlabs.com/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"emidlabs-backtest-mcp": {
"type": "remote",
"url": "https://mcp.backtest.emidlabs.com/mcp",
"enabled": true
}
}
} openclaw mcp add emidlabs-backtest-mcp --url 'https://mcp.backtest.emidlabs.com/mcp' --transport streamable-http
mcp_servers:
emidlabs-backtest-mcp:
url: "https://mcp.backtest.emidlabs.com/mcp" {
"McpServers": {
"emidlabs-backtest-mcp": {
"Transport": "http",
"Url": "https://mcp.backtest.emidlabs.com/mcp"
}
}
} assistant mcp add emidlabs-backtest-mcp -t streamable-http -u 'https://mcp.backtest.emidlabs.com/mcp'
{
"mcpServers": {
"emidlabs-backtest-mcp": {
"type": "http",
"url": "https://mcp.backtest.emidlabs.com/mcp"
}
}
} The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 10 Sept 26 0
- Stability: 0.97 → pass security
- 9 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 93 to 97. That category is still filling its 30-day observation window: 28 days of observed history at the previous scan, 29 at this one. The score rises as the window fills, whether or not the server changes.
- 8 Sept 26 −1
- Stability: pass → 0.93 functional
- 6 Sept 26 +5
- Stability: fail → pass ▲ security
- 2 Sept 26 0
- Tool “get_confirmation_source_signals” rewrote its description, which is the text the model reads security
- 1 Sept 26 0
- Tool “submit_backtest” rewrote its description, which is the text the model reads security
- Tool “submit_backtest_batch” rewrote its description, which is the text the model reads security
- Schema quality: 241 → 280 ▼ functional
- New tool “get_confirmation_source” functional
- New tool “get_confirmation_source_signals” functional
- New tool “submit_confirmation_source” functional
- “submit_backtest” added an optional parameter “confirmationSources” cosmetic
- “submit_backtest_batch” added an optional parameter “confirmationSources” cosmetic
- 28 Aug 26 +2
No change was recorded against any check on this day. Stability & Change Management went from 46 to 63.
- 26 Aug 26 +1
- We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Probed https://mcp.backtest.emidlabs.com/mcp
TLS valid
Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .
| Subject | Issuer | Valid from | Valid until | Key | Signature | Serial |
|---|---|---|---|---|---|---|
| CN=mcp.backtest.emidlabs.com | CN=YE1,O=Let's Encrypt,C=US | 12 Aug 2026 | 10 Nov 2026 | ECDSA 256 | ECDSA-SHA384 | 5b7741cbeba2022cf27f7b5aaf2f2023e3c |
| SANs: mcp.backtest.emidlabs.com | ||||||
| CN=YE1,O=Let's Encrypt,C=US (CA) | CN=Root YE,O=ISRG,C=US | 3 Sept 2025 | 2 Sept 2028 | ECDSA 384 | ECDSA-SHA384 | 5ddd70dd31f801c85c186a7a04b80afe |
| CN=Root YE,O=ISRG,C=US (CA) | CN=ISRG Root X2,O=Internet Security Research Group,C=US | 13 May 2026 | 2 Sept 2032 | ECDSA 384 | ECDSA-SHA384 | 872165fc34b6e5fba8add5b3705fb53a |
| CN=ISRG Root X2,O=Internet Security Research Group,C=US (CA) | CN=ISRG Root X1,O=Internet Security Research Group,C=US | 13 May 2026 | 2 Sept 2032 | ECDSA 384 | SHA256-RSA | 6c8f1dc727c7117f7baf853ac980f9cd |
Background: What to check on a remote MCP endpoint →
DNSSEC insecure
Validation of mcp.backtest.emidlabs.com. — Not signed
| Zone | DS | Keys | Algorithms | Outcome |
|---|---|---|---|---|
| . | trust_anchor | 20326, 38696 | 8, 8 | Verified |
| com. | present | 19718 | 13 | Verified |
| emidlabs.com. | absent | Unsigned (proven) parent-signed NSEC/NSEC3 proves an unsigned delegation |
Authentication No authorisation required
The endpoint answered without asking for a token. Anyone who knows the URL can reach it.
| Result | No authorisation required |
|---|---|
| HTTP status | 200 |
Background: How OAuth 2.1 works in the 2026 MCP spec →
Transports 2 probes
| Transport | URL | Outcome | Status | Location |
|---|---|---|---|---|
| streamable-http | https://mcp.backtest.emidlabs.com/mcp | Verified | 200 | |
| http (plaintext) | http://mcp.backtest.emidlabs.com/mcp | HTTPS enforced | 308 | https://mcp.backtest.emidlabs.com/mcp |
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
get_backtest_batch_results Get Backtest Batch Results ~339
Fetches every asset's outcome from a submit_backtest_batch call, paginated. By default (waitForCompletion: true) polls internally until every item in the batch is done — a cheap check, not one that pages through everything — so one call returns the finished page. Each item has the same aggregate metrics and recency fields (recentTradeCount/recentAvgPnlR/recentOutcomes) get_backtest_result returns for a single backtest, plus assetPair/status/error, so the single-result and batch-result shapes never drift apart. totalCount/completedCount/failedCount/pendingCount come back on every page, not just the last, so you can tell the batch is done from a single pageSize=1 call.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. |
| batchId | string|null | – | The batchId returned by submit_backtest_batch. |
| page | integer | – | 1-based page number. Default 1. |
| pageSize | integer | – | Items per page, 1-100. Default 20. |
| pollTimeoutMs | integer | – | Defaults to 300000 (5 minutes) — a batch's slowest item determines the total wait, so this is higher than get_backtest_result's default. |
| waitForCompletion | boolean | – | If true (default), polls internally until every item in the batch is done or pollTimeoutMs elapses. |
| Name | Type | Req | Description |
|---|---|---|---|
| batchId | string | – | – |
| completedCount | integer | – | How many items finished successfully. |
| failedCount | integer | – | How many items finished unsuccessfully (Failed, Cancelled, or Expired). |
| items | array | – | – |
| page | integer | – | – |
| pageSize | integer | – | – |
| pendingCount | integer | – | How many items are still Queued or Running. The whole batch is done once this reaches 0 — true on every page, not just the last. |
| totalCount | integer | – | Total items in this batch, across every page — not just this one. |
| totalPages | integer | – | – |
No examples provided.
get_backtest_result Get Backtest Result ~213
Fetches a submitted backtest by id. By default (waitForCompletion: true) polls internally until it finishes, so one call returns one final answer — no need to poll from the caller's side. Only aggregate metrics are returned here, no trade-by-trade detail — call get_backtest_trades for that (paginated, sortable). Fetching many results from the same submit_backtest_batch call? Use get_backtest_batch_results instead.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. |
| id | string|null | – | The id returned by submit_backtest. |
| pollTimeoutMs | integer | – | Defaults to 120000 (2 minutes). |
| waitForCompletion | boolean | – | If true (default), polls internally until the backtest finishes or pollTimeoutMs elapses. |
| Name | Type | Req | Description |
|---|---|---|---|
| candlesProcessed | integer|null | – | Number of candles the analyser processed for this backtest. Null until Status is "Completed". This is raw volume, not the plan's billing unit — see UnitsConsumed for that. |
| errorMessage | string|null | – | – |
| id | string | – | – |
| recentAvgPnlR | number|null | – | Average pnlR of the most recent RecentTradeCount closed trades. This is the recency signal for a rolling ranking — weighted alongside expectancyR, not a replacement for it. |
| recentOutcomes | array|null | – | "Win"/"Loss" per recent trade, chronological — oldest first, so the LAST element is the most recent trade. Lets a caller see whether recent trades were genuinely a streak (e.g. all "Loss") versus alt… |
| recentTradeCount | integer|null | – | Number of trades the recency fields below are based on (up to 5, fewer if the backtest has fewer trades). Null until Status is "Completed". |
| result | object|null | – | – |
| runtimeMs | integer|null | – | How long the analyser actually took to run this backtest, in milliseconds — pure compute time, not counting queue/messaging latency. Null until Status is "Completed". |
| status | string | – | – |
| unitsConsumed | number|null | – | The actual execution-unit cost of this backtest, matching what's debited from the account's plan balance (CandlesProcessed normalized by the account's candles-per-unit rate). Null until Status is "Co… |
No examples provided.
get_backtest_trades Get Backtest Trades ~247
Fetches the closed-trade list for a completed backtest, paginated and sortable — the trade-by-trade detail get_backtest_result deliberately omits. Only closed trades ever appear; a position still open when the backtest's date range ends isn't represented here or anywhere else. Example: sortBy="exitTime", sortDirection="desc", pageSize=5 for the most recently closed trades.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. |
| id | string|null | – | The id returned by submit_backtest. |
| page | integer | – | 1-based page number. Default 1. |
| pageSize | integer | – | Trades per page, 1-100. Default 20. |
| sortBy | string|null | – | One of: number, pnlR, pnlPct, entryTime, exitTime. Defaults to number (closing order). |
| sortDirection | string|null | – | "asc" or "desc". Defaults to asc. |
| Name | Type | Req | Description |
|---|---|---|---|
| items | array | – | The trades on this page, in the requested sort order. |
| page | integer | – | – |
| pageSize | integer | – | – |
| totalCount | integer | – | Total closed trades across the whole backtest, not just this page. |
| totalPages | integer | – | – |
No examples provided.
get_confirmation_source Get Confirmation Source ~213
Fetches a submitted confirmation source by id. By default (waitForCompletion: true) polls internally until it finishes, so one call returns one final answer. No trade-outcome fields here at all (no PnlR/WinRate/...) — a confirmation source never opens a position. Once Completed, its id can be used as a confirmationSources sourceId in submit_backtest; its raw signal timeline is available separately via get_confirmation_source_signals.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. |
| id | string|null | – | The id returned by submit_confirmation_source. |
| pollTimeoutMs | integer | – | Defaults to 120000 (2 minutes). |
| waitForCompletion | boolean | – | If true (default), polls internally until the confirmation source finishes or pollTimeoutMs elapses. |
| Name | Type | Req | Description |
|---|---|---|---|
| assetPair | string | – | – |
| candlesProcessed | integer|null | – | Number of candles the analyser processed. Null until Status is "Completed". This is raw volume, not the plan's billing unit — see UnitsConsumed for that. |
| errorMessage | string|null | – | – |
| id | string | – | – |
| runtimeMs | integer|null | – | How long the analyser actually took to compute this confirmation source's signal timeline, in milliseconds. Null until Status is "Completed". |
| status | string | – | – |
| timeframe | string | – | – |
| unitsConsumed | number|null | – | The actual execution-unit cost, same pool/rate as a regular backtest — computing a confirmation source's signal timeline costs the same per candle as simulating trades, it just skips the trade simula… |
No examples provided.
get_confirmation_source_signals Get Confirmation Source Signals ~335
Fetches a completed confirmation source's raw signal timeline, paginated — the actual data a backtest's confirmationSources requirement is checked against. Can easily run into the thousands for a frequent condition over a long range (every candle-condition match is a row, not just closed trades), which is why this is paginated from the start. Debugging/inspection only — you do NOT need this tool to make confirmationSources work, and should not fetch these rows to reconstruct the gating yourself. To actually gate a backtest by this source, pass its id directly as sourceId in submit_backtest's own confirmationSources array; the backend applies the backward-only state check against this exact timeline automatically, including the higher-timeframe-to-lower-timeframe alignment. Reimplementing that alignment by hand from this raw data is unnecessary and easy to get wrong (e.g. failing to correctly persist a higher-timeframe state across every lower-timeframe candle until the next higher-timeframe close). Use this tool only to sanity-check a source's signal density or diagnose an unexpectedly low ConfirmedSignalsCount after the fact.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. |
| id | string|null | – | The id returned by submit_confirmation_source. |
| page | integer | – | 1-based page number. Default 1. |
| pageSize | integer | – | Signals per page, 1-100. Default 20. |
| Name | Type | Req | Description |
|---|---|---|---|
| items | array | – | The signals on this page, in candle order. |
| page | integer | – | – |
| pageSize | integer | – | – |
| totalCount | integer | – | Total signals across the whole confirmation source, not just this page — can easily be in the thousands for a frequent condition over a long range. |
| totalPages | integer | – | – |
No examples provided.
list_available_assets List Available Assets ~151
Lists every asset pair with real historical data, each with its supported timeframes and the date range actually available. Optional to call — submit_backtest already returns a clear error (with the real available range) when an asset or date range doesn't have data, so this is for up-front exploration or for recovering from an "unknown asset" error, not a required step before every submit_backtest.
| Name | Type | Req | Description |
|---|---|---|---|
| backtestApiKey | string|null | – | Your EmidLabs backtest API key. Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. Override only for self-hosted/staging use. |
| Name | Type | Req | Description |
|---|---|---|---|
| assets | array | – | – |
No examples provided.
submit_backtest Submit Backtest ~527
Submits a strategy for backtesting against historical OHLCV data. Returns immediately with an id and status — call get_backtest_result to fetch the outcome once it finishes. Testing the same strategy against many assets? Use submit_backtest_batch instead — one call per asset here adds up fast. Optionally accepts confirmationSources to only count a candidate Entry/Exit as a real trade once corroborated by a submit_confirmation_source result (multi-timeframe or cross-asset confirmation) — see the confirmationSources argument and submit_confirmation_source's own description.
| Name | Type | Req | Description |
|---|---|---|---|
| assetPair | string|null | – | e.g. "BTC-USDC". |
| backtestApiKey | string|null | – | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. Override only for self-hosted/staging use. |
| confirmationSources | array|null | – | Optional. Each entry names a submit_confirmation_source result (same account only, must already be Completed) that every candidate Entry/Exit must be corroborated by before it's simulated as a trade… |
| finalDate | string|null | – | ISO date string, e.g. "2025-06-01". |
| initialDate | string|null | – | ISO date string, e.g. "2025-01-01". |
| strategySnapshotJson | object|null | – | The Strategy DSL object — every field below documents its own exact shape, this is just the execution model that ties them together. Entry fills at the close of the candle where decision.entry turns… |
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | – | – |
| status | string | – | – |
No examples provided.
submit_backtest_batch Submit Backtest Batch ~492
Submits ONE strategy against MANY asset pairs in a single call — the same backtest you'd get from calling submit_backtest once per asset, without needing dozens of round trips. Returns immediately with a batchId (pass it to get_backtest_batch_results to fetch every asset's outcome, paginated) plus the per-asset id/status assigned right away. Best-effort: one bad asset pair (unknown, or its date range outside coverage) shows up with an error in that item only — every other asset in the batch is unaffected. Optionally accepts confirmationSources, applied identically to every asset in the batch — see submit_backtest's own confirmationSources argument for the full semantics.
| Name | Type | Req | Description |
|---|---|---|---|
| assetPairs | array|null | – | e.g. ["BTC-USDC", "ETH-USDC", "SOL-USDC"]. Every asset gets the exact same strategySnapshotJson and date range. |
| backtestApiKey | string|null | – | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. Override only for self-hosted/staging use. |
| confirmationSources | string|null | – | Optional. A JSON-encoded STRING (not a native array/object — pass it exactly like a quoted string value), containing the same shape as submit_backtest's own confirmationSources: [{"sourceId":"<a subm… |
| finalDate | string|null | – | ISO date string, e.g. "2025-06-01". |
| initialDate | string|null | – | ISO date string, e.g. "2025-01-01". |
| strategySnapshotJson | object|null | – | Same Strategy DSL object submit_backtest takes — see that tool's description for the full shape. |
| Name | Type | Req | Description |
|---|---|---|---|
| batchId | string | – | Pass this to get_backtest_batch_results to fetch every item's status/result, paginated. |
| items | array | – | – |
No examples provided.
submit_confirmation_source Submit Confirmation Source ~335
Runs a strategy against historical data purely to produce a signal timeline used to confirm OTHER backtests — not a backtest itself. Walks the same candles and evaluates the same DSL as submit_backtest, but never simulates a position: no trade, no PnL, no WinRate/drawdown, none of that applies here, because this strategy is never meant to be traded on its own. Returns immediately with an id and status — call get_confirmation_source to check completion, then pass that id as a confirmationSources sourceId in submit_backtest (e.g. only count an XRP entry once a BTC-neutral confirmation source agrees). Costs the same capacity as a regular backtest of the same size — the compute is identical, it just skips trade simulation.
| Name | Type | Req | Description |
|---|---|---|---|
| assetPair | string|null | – | e.g. "BTC-USDC". |
| backtestApiKey | string|null | – | Your EmidLabs backtest API key (created in the Console). Not needed if this connector was added with a static 'x-api-key' header. |
| backtestBaseUrl | string|null | – | Defaults to the public production API. Override only for self-hosted/staging use. |
| finalDate | string|null | – | ISO date string, e.g. "2025-06-01". |
| initialDate | string|null | – | ISO date string, e.g. "2025-01-01". |
| strategySnapshotJson | object|null | – | The Strategy DSL object — identical shape to submit_backtest's own. riskManagement is accepted but never used (no position is ever opened), so it's fine to omit. |
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | – | – |
| status | string | – | – |
No examples provided.
What is the EmidLabs Backtest MCP server?
EmidLabs Backtest is an MCP server listed in the public MCP registry as io.github.emidlabs/backtest-mcp. Run crypto trading strategy backtests through EmidLabs's Backtesting API. This page covers its hosted endpoint (https://mcp.backtest.emidlabs.com/mcp).
Is the EmidLabs Backtest MCP server safe to use?
EmidLabs Backtest scores 85 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the EmidLabs Backtest MCP server expose?
EmidLabs Backtest exposes 9 tools: submit_confirmation_source, list_available_assets, submit_backtest_batch, get_backtest_batch_results, get_backtest_trades, and 4 more. Their descriptions and schemas cost roughly 2,852 tokens of context every time the server is loaded.
Does the EmidLabs Backtest MCP server require authentication?
No. We connected to EmidLabs Backtest without credentials and it answered, so anything it exposes is reachable by anyone who knows the address.
Is the EmidLabs Backtest MCP server still maintained?
EmidLabs Backtest is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.