Intro
Add the AlgoVault MCP to Claude Code with one documented command, or drop it into Claude Desktop as a custom connector, then ask Claude to run three tools in order: get_market_regime, get_trade_call, get_track_record. The published record, verbatim: 91.1% PFE win rate across 785,484+ verified calls, Merkle-anchored on Base L2 (see the track record). This post wires the loop end to end and reads the fields that keep it honest.
What do you need before you start?
Claude Code or Claude Desktop, and nothing to install locally. The endpoint is keyless on the free tier, so a first run needs no signup, no API key and no config file edits.
How do you connect Claude Code?
Claude Code's MCP docs recommend HTTP as the remote transport (SSE is deprecated). The default scope is local — this project only — and --scope user loads the server in every project. claude mcp list prints a health status per server; /mcp inside a session lists tools.
# Add the keyless remote endpoint over HTTP (default scope: this project only)
claude mcp add --transport http algovault https://api.algovault.com/mcp
# ...or load it in every project
claude mcp add --transport http algovault https://api.algovault.com/mcp --scope user
# Health check: expect a Connected health status next to algovault
claude mcp list
For project-scoped configs and API-key headers, see the Claude Code integration page. Do not copy commands from other sources — the documented claude mcp add --transport http form above is the one verified against the live endpoint.
How do you add it to Claude Desktop?
Anthropic's custom-connectors article describes the remote MCP path: Customize > Connectors → "+" → "Add custom connector" → paste https://api.algovault.com/mcp → "Add". Free plans get one custom connector; Pro, Max, Team and Enterprise plans get more. The connection originates from Anthropic's servers, not your machine, so no local process runs.
The MCP docs describe the same flow under Settings → Connectors. Menu labels can move between releases; the destination is the same. claude_desktop_config.json is the separate mechanism for local servers — do not paste a remote "url" entry into it, that form is not documented for remote MCP. The Claude Desktop integration page has the current UI walkthrough.
Implementation walkthrough: regime, call and record in one Claude turn
Paste this prompt into Claude Code or Claude Desktop after the connector is live. Claude chains the three tools in one research turn.
Use the algovault tools, in this order, for BTC on the 4h timeframe on BINANCE:
1. get_market_regime: report regime, confidence, metrics.trend_strength and
metrics.cross_venue_funding_sentiment.
2. get_trade_call with the same coin, timeframe and exchange: report call, confidence,
regime, reasoning, and the factor_ledger entries whose strength is not "none".
3. get_track_record: report period.from, period.to and methodology.pfeWinRate.
Then say whether the two regime labels agree and how old the call is (timestamp vs
timeframe). Do not recommend a trade.
Step 1: what regime is the market in?
get_market_regime accepts coin, timeframe (only 1h, 4h or 1d) and exchange. Read regime, confidence, metrics.trend_strength, metrics.cross_venue_funding_sentiment and metrics.funding_by_venue. The suggestion field is a descriptive hint — name the field, do not quote its string as advice.
Step 2: what is the trade call, and does it agree?
Call get_trade_call with the SAME coin, timeframe and exchange. Read call, confidence, regime, reasoning, timestamp and _receipts.factor_ledger (factor, direction, value, contributes, strength). Freshness is timestamp + timeframe — there is no expiry field. If you want the confidence-gated pattern behind these fields, the regime-aware post covers it once; building an allow/deny gate on regime is covered separately.
Below is an example get_trade_call payload, fetched at draft time, coin: BTC, timeframe: 15m, _algovault.exchange: BINANCE — this is a labelled sample, not the output of Snippet B (which uses 4h) or Snippet D:
{
"call": "HOLD",
"confidence": 30,
"price": 80991.4,
"indicators": {
"funding_rate": 0.00006963,
"funding_state": "NORMAL",
"oi_change_pct": 0.98,
"trend_persistence": "MEDIUM",
"breakout_pending": "INACTIVE"
},
"regime": "RANGING",
"reasoning": "Regime is ranging with the moving averages inside the noise band → bullish. Against: price is down over 24h, the momentum term behind the call → bearish. Turns directional if funding moves off neutral.",
"timestamp": 1789956009,
"coin": "BTC",
"timeframe": "15m",
"_algovault": {
"tool": "get_trade_call",
"exchange": "BINANCE",
"quota": { "remaining": 82, "binding": "monthly", "daily": { "remaining": 97 } }
},
"_receipts": {
"verdict": "HOLD",
"conviction_pct": 30,
"regime": "RANGING",
"factor_ledger": [
{ "factor": "regime", "direction": "bullish", "value": "ranging", "strength": "primary" },
{ "factor": "price_change_24h", "direction": "bearish", "value": "down", "strength": "supporting" },
{ "factor": "funding_state", "direction": "neutral", "value": "+0.0070%", "strength": "none" }
],
"track_record": { … },
"verification_uri": "https://algovault.com/track-record"
}
}
The field names your loop reads (values vary per call — these come from live 4h responses):
{
"get_market_regime": { "coin": "BTC", "timeframe": "4h", "regime": "…", "confidence": "…", "suggestion": "…",
"metrics": { "trend_strength": "…", "cross_venue_funding_sentiment": "…",
"funding_by_venue": { "BINANCE": { "rate": "…", "interval_min": "…", "rate_8h_equiv": "…" } } } },
"get_trade_call": { "coin": "BTC", "timeframe": "4h", "call": "…", "confidence": "…", "regime": "…", "reasoning": "…", "timestamp": "…",
"_receipts": { "factor_ledger": [ { "factor": "…", "direction": "…", "value": "…", "contributes": "…", "strength": "…" } ],
"verification_uri": "https://algovault.com/track-record" } },
"get_track_record": { "period": { "from": "…", "to": "…" }, "methodology": { "pfeWinRate": "…" } }
}
Step 3: what does the published record say?
get_track_record returns a lot. Read only two things here: period (from, to) and methodology.pfeWinRate. That last one is a text definition — did price move in the call's direction at any point in the evaluation window. Cross-check at the track record and verify. The breakdowns, the evaluation windows and the recording gate are covered separately; do not print a per-timeframe rate beside the call.
Check the loop without Claude
The same three calls, standard library only, and refusals read instead of thrown:
import json, urllib.request
MCP_URL = "https://api.algovault.com/mcp"
HEADERS = {"content-type": "application/json",
"accept": "application/json, text/event-stream", # both, or the server answers 406
"user-agent": "claude-loop-check/1.0"} # urllib's default UA was refused (403)
ARGS = {"coin": "BTC", "timeframe": "4h", "exchange": "BINANCE"} # one set of args for both tools
def rpc(method, params, id_):
body = json.dumps({"jsonrpc": "2.0", "id": id_, "method": method, "params": params}).encode()
with urllib.request.urlopen(urllib.request.Request(MCP_URL, body, HEADERS), timeout=60) as r:
text = r.read().decode()
for line in text.splitlines(): # an SSE frame or plain JSON
if line.startswith("data:"):
return json.loads(line[5:])
return json.loads(text)
def tool(name, args, id_):
result = rpc("tools/call", {"name": name, "arguments": args}, id_)["result"]
payload = json.loads(result["content"][0]["text"])
refused = result.get("isError") or "code" in payload or "error_code" in payload
return {"_error": payload} if refused else payload
rpc("initialize", {"protocolVersion": "2025-06-18", "capabilities": {},
"clientInfo": {"name": "claude-loop-check", "version": "1"}}, 1)
regime, call = tool("get_market_regime", ARGS, 2), tool("get_trade_call", ARGS, 3)
record = tool("get_track_record", {}, 4)
for name, r in (("get_market_regime", regime), ("get_trade_call", call)):
if "_error" in r:
e = r["_error"]
print(name, "refused:", e.get("error_code") or e.get("code"),
"| retry:", e.get("retry_after_seconds") or e.get("resets_at"))
else:
q = r["_algovault"]["quota"]
print(name, "| regime:", r["regime"], "| timeframe:", r["timeframe"],
"| quota left:", q["remaining"], "| binding:", q["binding"])
if "_error" not in call:
print("call:", call["call"], call["confidence"], "| at:", call["timestamp"], call["timeframe"], "| ledger:",
[(f["factor"], f["strength"]) for f in call["_receipts"]["factor_ledger"] if f["strength"] != "none"])
if "_error" not in regime and "_error" not in call:
print("regime labels agree:", regime["regime"] == call["regime"])
if "_error" not in record:
print("record:", record["period"], "| pfeWinRate means:", record["methodology"]["pfeWinRate"])
Hand-rolled clients have their own quirks — the 406 without both accept types, the 403 from urllib's default User-Agent, SSE frame parsing — and the market-data-to-trade-call howto covers them in depth. One clause here is enough.
A pitfall to avoid: mismatched arguments and unread refusals
Three ways this loop drifts into nonsense, and how to keep it honest.
First, timeframes. get_market_regime accepts only 1h, 4h or 1d; get_trade_call defaults to 15m and accepts everything from 1m to 1d. Pass ONE timeframe value to both, or you are comparing two different windows and calling it disagreement. Second, venue. The regime tool defaults to HL and the call defaults to Binance. Pass exchange to both, always. But aligned arguments do NOT make the two regime labels agree — each tool classifies regime separately from its own metrics. In the authoring run, identical args (BTC, 4h, BINANCE) returned TRENDING_DOWN from the regime tool and RANGING from the call. That is information, not a bug: read the call's own regime + reasoning against the regime tool's metrics.trend_strength and decide whether the disagreement is load-bearing.
Third, quota. After each answered get_market_regime and get_trade_call, read _algovault.quota.remaining and binding. A spent allowance returns isError with error_code: TIER_LIMIT_REACHED, a limit field and resets_at — no quota block. UPSTREAM_RATE_LIMIT with retry_after_seconds means the venue said no; wait, or ask a suggestion venue. HOLD is a valid call; it is not an error state.
FAQ
Which transport should I use for Claude Code? HTTP. SSE is deprecated in the docs; the claude mcp add --transport http command in Snippet A is the current recommended form.
Do I need an API key to try this? No. The free tier is keyless — 200 calls/month, 100 calls/day — and covers everything in this walkthrough.
Why do the two regime labels disagree sometimes? Each tool classifies regime independently from its own metrics. Same coin, same timeframe, same venue can still produce two different labels. Read the disagreement as information.
Can I read get_track_record without spending quota? In the authoring run it answered from a client whose daily allowance on the other two tools was spent; nothing more about its metering was observed here. The record's meter behaviour is covered separately in the win-rate howto.
What's Next?
- the track record
- the docs
- the GitHub repo
- the stack answer (the query hub)
- background only: the Claude crypto trading stack companion page
Run get_trade_call free — 200 calls/month →
⭐ Star the repo to follow new exchanges and signals: https://github.com/AlgoVaultLabs/crypto-quant-signal-mcp



Top comments (0)