get_track_record
Fetch a verified trading track record for any Tradallo profile or agent. Returns cryptographically-verified statistics including Sharpe, win rate, max drawdown, PnL, and trade count, with ed25519 signature verification.
Instructions
Fetch a verified trading track record for a Tradallo profile (human) or agent. Returns cryptographically-verified statistics (Sharpe, win rate, max drawdown, PnL, trade count) computed from on-chain or in-house-sim trade history. The signature is ed25519-verified against Tradallo's published pubkey before this tool returns.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| handle | Yes | The Tradallo handle to look up (e.g. 'aaronjordan' for a human, 'alpha-momentum-v3' for an agent). | |
| principal_type | No | Whether the handle is a human profile or an agent. Defaults to 'agent' (the more common reputation-query use case). |
Implementation Reference
- src/index.ts:186-202 (handler)The MCP tool handler for 'get_track_record' — extracts handle and principal_type from arguments, constructs the appropriate API path (agent vs human), fetches the signed envelope via TradalloClient.getSigned, and returns the verified JSON result.
case "get_track_record": { const handle = String((args as { handle?: unknown })?.handle ?? "").trim(); const principal_type = ((args as { principal_type?: unknown })?.principal_type as | "human" | "agent" | undefined) ?? "agent"; if (!handle) { return errorResult("handle is required"); } const path = principal_type === "human" ? `/api/v1/profiles/${encodeURIComponent(handle)}/track-record` : `/api/v1/agents/${encodeURIComponent(handle)}/track-record`; const data = await client.getSigned<unknown>(path); return jsonResult(data); } - src/index.ts:75-103 (registration)Tool registration for 'get_track_record' in the ListToolsRequestSchema handler — defines the tool name, description, input schema (handle as required string, principal_type as optional enum defaulting to 'agent'), and read-only annotations.
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: "get_track_record", description: "Fetch a verified trading track record for a Tradallo profile (human) or agent. Returns cryptographically-verified statistics (Sharpe, Sortino, win rate, max drawdown, PnL, trade count, expectancy, profit factor) across all-time and rolling 30/90/365-day windows. The signature is ed25519-verified against Tradallo's published pubkey before this tool returns.\n\nExamples:\n - get_track_record(\"alpha-momentum-v3\") — agent (default)\n - get_track_record(\"aaronjordan\", \"human\") — human profile", inputSchema: { type: "object", properties: { handle: { type: "string", minLength: 1, maxLength: 40, pattern: "^[a-z0-9_-]+$", description: "The Tradallo handle to look up (e.g. 'aaronjordan' for a human, 'alpha-momentum-v3' for an agent). Lowercase letters, digits, hyphens, underscores.", }, principal_type: { type: "string", enum: ["human", "agent"], default: "agent", description: "Whether the handle is a human profile or an agent. Defaults to 'agent' (the more common reputation-query use case).", }, }, required: ["handle"], }, annotations: READ_ONLY_ANNOTATIONS, }, - src/client.ts:117-130 (helper)TradalloClient.getSigned — the HTTP fetch method used by the handler to retrieve and cryptographically verify signed envelopes from the Tradallo API.
async getSigned<T>(path: string): Promise<T> { const res = await fetch(`${this.baseUrl}${path}`, { headers: { ...this.headers, accept: "application/json" }, }); if (res.status === 404) { throw new Error(`not_found: ${path}`); } if (!res.ok) { throw new Error(`request failed: ${res.status} ${res.statusText} (${path})`); } const envelope = (await res.json()) as SignedEnvelope<T>; await this.verifyEnvelope(envelope); return envelope.data; } - src/client.ts:135-183 (helper)TradalloClient.verifyEnvelope — performs full ed25519 signature verification, JCS canonicalization, schema version check, and replay window check, ensuring the data returned to the handler is trustworthy.
private async verifyEnvelope<T>(envelope: SignedEnvelope<T>): Promise<void> { if (envelope.schema_version !== SUPPORTED_SCHEMA_VERSION) { throw new Error( `unsupported envelope schema_version: ${envelope.schema_version} (expected ${SUPPORTED_SCHEMA_VERSION})`, ); } const servedAtMs = Date.parse(envelope.served_at); if (Number.isNaN(servedAtMs)) { throw new Error("envelope has invalid served_at"); } if (Date.now() > servedAtMs + envelope.max_age_seconds * 1000) { throw new Error("envelope past max_age_seconds (replay window expired)"); } if (envelope.signature.alg !== "ed25519") { throw new Error(`unsupported signature alg: ${envelope.signature.alg}`); } const pubkeys = await this.getPubkeys(); const match = pubkeys.find((k) => k.key_id === envelope.signature.key_id); if (!match) { // One refresh attempt — the key may have been rotated since our cache // was populated. this.pubkeyCache = null; const refreshed = await this.getPubkeys(); const retry = refreshed.find((k) => k.key_id === envelope.signature.key_id); if (!retry) { throw new Error(`unknown signing key_id: ${envelope.signature.key_id}`); } return this.verifyEnvelope(envelope); } const pubkeyRaw = base64ToBytes(match.pubkey); const canonical = canonicalize({ data: envelope.data, schema_version: envelope.schema_version, served_at: envelope.served_at, max_age_seconds: envelope.max_age_seconds, }); if (canonical === undefined) { throw new Error("envelope data not canonicalizable"); } const message = TEXT_ENCODER.encode(canonical); const signature = base64ToBytes(envelope.signature.sig); const ok = await verifyEd25519(message, signature, pubkeyRaw); if (!ok) { throw new Error("ed25519 signature verification failed"); } } - src/index.ts:62-73 (schema)Annotations and READ_ONLY_ANNOTATIONS constant applied to all tools including get_track_record — hints to MCP clients that the tool is read-only, non-destructive, idempotent, and accesses external data.
// ─── Tool catalog ─────────────────────────────────────────────────────── // Annotations applied to every tool: all five are pure reads against the // public Tradallo API, no side effects, idempotent, and reach an external // system (open-world). Modern MCP clients use these to decide whether to // auto-approve a call vs prompt the user. const READ_ONLY_ANNOTATIONS = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, } as const;