HT

hplin/tastytrade-research-mcp

Developer tools
0 stars 0 forks Quality 70 Trend 20MIT

Research-focused MCP server for tastytrade historical market data and backtesting, including Backtester API integration and historical candles for XSP/SPX and SPY options regression testing.

Overview

Research-only Model Context Protocol (MCP) server for tastytrade historical options research, bounded live SPX/SPXW option evidence, package-price evidence, and strategy regression testing. The project is intentionally separate from the official tastytrade/tastytrade-mcp: - : general live market data, account workflows, and broker dry-run validation - : historical candles, Backtester access, bounded direct SPX/SPXW Gamma+OI snapshots, package-pricing research, and post-session fill verification - : brokerage order placement, replacement, or cancellation These tools dynamically resolve an explicitly selected Traditional IRA, mask account identifiers, and expose only broker GET requests. They do not use the recent/live order snapshot. See broker history and OO audit for window semantics, privacy, completeness, quote limitations, and a synthetic FinPilot input. Engineering fixtures remain explicitly synthetic, not live acceptance evidence.

README

tastytrade-research-mcp

Research-only Model Context Protocol (MCP) server for tastytrade historical options research, bounded live SPX/SPXW option evidence, package-price evidence, and strategy regression testing.

The project is intentionally separate from the official tastytrade/tastytrade-mcp:

  • official tastytrade MCP: general live market data, account workflows, and broker dry-run validation
  • this project: historical candles, Backtester access, bounded direct SPX/SPXW Gamma+OI snapshots, package-pricing research, and post-session fill verification
  • never exposed here: brokerage order placement, replacement, or cancellation

MCP tools

Provider-native Backtester tools

Tool Upstream endpoint Purpose
tastytrade_get_backtest_available_dates GET /available-dates Discover symbols and historical coverage
tastytrade_list_backtests GET /backtests List submitted research jobs
tastytrade_create_backtest POST /backtests Submit a provider-native historical strategy
tastytrade_get_backtest GET /backtests/{id} Poll status and retrieve results
tastytrade_get_backtest_logs GET /backtests/{id}/logs Retrieve trials and execution logs
tastytrade_cancel_backtest POST /backtests/{id}/cancel Cancel only a Backtester job
tastytrade_simulate_trade POST /simulate-trade Simulate one exact historical trade

Read-only broker history and OO audit

Tool Purpose
tastytrade_get_historical_orders Paginated historical SPX/SPXW orders, all statuses, available lifecycle timestamps and explicit coverage
tastytrade_get_historical_transactions Exact-decimal per-leg historical executions, transaction cash flows, fees and UTC/ET timestamps
tastytrade_audit_oo_broker_orders OO-to-broker ID/leg correlation, attempts, independent call/put cash flows, evidence matrix and Traditional Chinese summary

These tools dynamically resolve an explicitly selected Traditional IRA, mask account identifiers, and expose only broker GET requests. They do not use the recent/live order snapshot. See broker history and OO audit for window semantics, privacy, completeness, quote limitations, and a synthetic FinPilot input. Engineering fixtures remain explicitly synthetic, not live acceptance evidence. Authorized October 12–13 ET broker queries enumerated 59 orders and 76 transactions with complete provider-result pagination, not exhaustive lifecycle-event history. User-provided original OO Activity Log text for both days is now available privately and correlated through source-bound normalization. Its clocks have whole-second precision; ET is attributed to the user context, not embedded offsets. One October 12 exhaustion episode is identified; a second reported episode retains a definite identification-coverage gap, not an invented failure or proof of absence. Issue #102 remains open pending independent acceptance of the actual evidence. Fees and cash flows are reconciled when available; final fee, settlement and campaign incompleteness remains an explicit evidence limitation, with definitive claims suppressed, not a new requirement to acquire unavailable final data.

Research and regression tools

Tool Purpose
tastytrade_get_live_option_snapshot Auto-chunk and merge exact SPX/SPXW DXLink Quote, Greeks, and Summary.openInterest cohorts; preserve native/local timing, evaluate optional 2/3/4-leg exact packages with caller quality policy for FinPilot evidence handoff, and calculate a research-only unsigned Gamma concentration proxy
tastytrade_compute_heuristic_signed_gex Apply an explicit versioned research signing hypothesis to one unified snapshot, with separate current-Gamma signed GEX and optional bounded spot-repriced heuristic gamma flip
tastytrade_price_option_package Price verticals, iron condors, and double diagonals with explicit native/synthetic provenance
tastytrade_discover_historical_spx_candidates Reconstruct timestamp-safe historical SPXW candidates under a versioned resolution profile, with exact-timestamp Backtester fallback
tastytrade_discover_historical_spx_candidates_range Run the same candidate discovery over an explicit trading calendar with bounded concurrency, deadlines, immutable-cache diagnostics, and resumable partial progress
tastytrade_get_historical_spx_candidate_universe Return a bounded multi-strike, multi-expiration SPXW universe and optional versioned RESEARCH_ONLY DD selected-leg/matched-delta IV handoff
tastytrade_get_historical_option_package_at_checkpoint Reconstruct an exact-leg SPX package reference at an RFC3339 or IANA-local checkpoint with explicit age and skew controls
tastytrade_get_historical_option_package_path Return profile-aligned completed-candle package points and explicit gaps without interpolation
tastytrade_get_historical_option_package_horizons Reconstruct a frozen exact-leg candidate inventory at caller-supplied ENTRY/+3/+5 trading sessions, with an opt-in research-only model fallback for candle-missing legs
tastytrade_normalize_historical_execution_evidence Normalize immutable exact-leg quote snapshots/windows into signed, provider-neutral simulated-execution inputs without claiming a fill
tastytrade_normalize_historical_strategy_evidence Normalize V2 frozen strategy identities, exact inventory, historical quote/reference evidence and optional actual entry facts, including staged SIC, without inferring fills or certifying maximum loss
tastytrade_build_historical_event_path Replay caller-frozen exact-leg observations and staged entry/partial close/roll/settlement events with timestamp-safe risk, shared execution/fee models, bounded resume and full metric denominators
tastytrade_simulate_historical_execution Apply one caller-frozen, hashed execution profile to immutable exact-leg evidence and return a separate simulated fill/P&L result
tastytrade_build_historical_replay_report Aggregate frozen baseline/research decisions and immutable execution simulations into deterministic +3/+5-day metrics without changing grading or paper state
tastytrade_prepare_spx_spread Deterministically normalize SPX legs without calling an upstream service
tastytrade_simulate_spx_spread Run exact-leg SPX historical simulation and normalize its result
tastytrade_create_spx_spread_backtest Submit supported SPX structures through relative Backtester selectors
tastytrade_verify_historical_fill Check a frozen paper limit against a caller-supplied historical package path or a forward Backtester path
tastytrade_get_historical_candles Retrieve DXLink LAST/BID/ASK OHLC aggregates without resampling; valuation-only, not executable quotes

Use MCP tools/list for the complete JSON input schemas. The direct live snapshot, bounded DXLink batch provenance, event/cohort freshness contract, OI-based unsigned Gamma concentration methodology, semantic limits, regression handoff, and opt-in live gate are documented in docs/live-option-snapshot.md. The separate Level 3 signing hypothesis, model/result identities, current-Gamma versus spot-repriced evidence, bounded heuristic gamma-flip search, and research-only live gate are documented in docs/heuristic-signed-gex.md. The shared profile contract and the optional seven-date live capability gate are documented in docs/resolution-profiles.md. The separate Double Diagonal IV measurement contract, legacy-preserving migration, and reproducible grading/regression handoff are documented in docs/dd-iv-measurements.md. Private immutable source-cache configuration, exact offline replay, and migration guidance are documented in docs/evidence-cache.md. The external historical-source capability review, explicit no-spend decision, and approval gates are documented in docs/historical-provider-decision.md. The pinned offline March–August 2026 exact-leg inventory, blocked coverage matrix, and reproducible report command are documented in docs/historical-coverage-audit.md. The quote-backed exact-leg handoff, signed inventory convention, and valuation/simulation/broker separation are documented in docs/historical-execution-evidence.md. The additive V2 family shapes, frozen selection/reference costs, actual entry facts, and independently timestamped staged SIC exposure are documented in docs/historical-strategy-evidence.md. The additive variable-checkpoint event-path contract, caller-frozen exit instructions, lifecycle ledger, pagination and reproducible real-evidence NOT_ASSESSABLE audit are documented in docs/historical-event-path.md. Caller-frozen execution profiles, fill statuses, exact P&L arithmetic, and fee semantics are documented in docs/historical-execution-model.md. The replay acceptance matrix, denominator rules, one-week smoke manifest, and runner guidance are documented in docs/historical-replay.md.

Private historical evidence cache

The historical candle, SPX candidate/universe, and exact-package tools accept an opt-in evidence_cache policy. The server exposes 29 tools, including the local-only historical quote normalizer, deterministic execution-model adapter, and historical replay report builder. READ_WRITE stores sanitized source observations and normalized results as separate content-addressed objects; REFRESH creates a new immutable revision and diff; CACHE_ONLY replays only caller-supplied exact manifest IDs and never contacts the provider.

The filesystem backend is disabled until TASTYTRADE_EVIDENCE_CACHE_DIR points to a private volume. It uses atomic writes, read-back checksum verification, bounded provider concurrency, request deduplication, short-lived retryable-failure indexes, and a hard disk quota without evicting immutable evidence. Cache identity includes exact symbols, range/as-of, provider/dataset/license scope, aggregation/session/ alignment/price type, the full resolution profile, resource policy, and normalization/model/source revisions. Retrieval time is frozen in each immutable manifest and never replaces bar availability time. Run npm run report:evidence-cache for a deterministic synthetic cache hit/miss, byte-count, normalized-hash, and provider-call-reduction report.

Approval-gated bounded history

The repository contains a provider-neutral bounded-history contract for a future approved source. It is intentionally dormant: no vendor transport, credential, paid fallback, environment configuration, or MCP tool is enabled. Construction requires an exact approval scope, confirmed field and expired-symbol entitlements, a provider-specific native-field allowlist, a fixed HTTPS host, separate credentials, and explicit cache storage/reuse permission. Synthetic tests validate the contract but do not establish external SPX/SPXW coverage.

Execution evidence contract

Every normalized research result uses execution-evidence contract 1.0.0. The contract distinguishes:

  • NATIVE_PACKAGE
  • SYNTHETIC_NATURAL
  • SYNTHETIC_MID_REFERENCE
  • HISTORICAL_OPTION_PACKAGE_REFERENCE
  • HISTORICAL_PATH
  • BACKTESTER_SIMULATION
  • BROKER_DRY_RUN

The machine-readable schema is docs/execution-evidence.schema.json. Migration guidance for existing paper-simulation logs is in docs/execution-evidence-migration.md.

BROKER_DRY_RUN validates a caller-supplied order; it never implies fillability. Synthetic midpoint evidence is valuation-only.

Package pricing

Package arithmetic uses an in-repository exact decimal implementation rather than binary floating-point arithmetic.

  • NATIVE_PACKAGE is selected only when the caller supplies a valid, non-crossed upstream package market.
  • SYNTHETIC_NATURAL buys each leg at its ask and sells each leg at its bid.
  • SYNTHETIC_MID_REFERENCE uses leg midpoints and always reports guaranteed_executable: false.
  • Native package bid/ask fields are never populated with synthetic arithmetic.
  • Every leg retains its exact symbol, action, quantity, expiration, timestamp, and provider source.
  • as_of, freshness, and temporal alignment are computed from the decision-critical observations.
  • Missing, crossed, stale, future-dated, and materially misaligned quotes are returned as explicit warnings. Unusable evidence is never success-shaped.

Supported families are DEBIT_VERTICAL, CREDIT_VERTICAL, IRON_CONDOR, and multi-expiration DOUBLE_DIAGONAL.

SPX spread adapter

The high-level adapter preserves each exact provider/OCC option symbol in /simulate-trade requests and returns stable 1.0.0 result envelopes. Each result repeats the immutable normalized legs and carries a deterministic SHA-256 request_id, so persisted evidence remains attributable even though the provider response itself contains only prices and timestamps.

Aggregate /backtests requests use relative selectors (delta, percentageOTM, currentPriceOffset, or premium) and therefore cannot preserve an exact historical strike or expiration. The adapter exposes that limitation in its capability flags.

Double diagonals remain exact-simulation only because the aggregate Backtester cannot faithfully preserve their multi-expiration identity. 0DTE legs are rejected unless the caller explicitly sets allow_0dte: true.

This MCP supplies evidence only. It does not assign grades or make production entry decisions.

Historical SPX candidate discovery

tastytrade_discover_historical_spx_candidates is the REGRESSION_RESEARCH bridge between timestamp-safe selector evidence and exact contract identity. tastytrade_discover_historical_spx_candidates_range applies that same single-checkpoint contract to an explicit caller-supplied trading calendar. It preserves chronological output order while using a bounded worker pool, isolates checkpoint failures, retries only transient provider failures, and returns an opaque continuation cursor for unresolved or deferred sessions. Continuation scheduling completes a first pass over never-attempted sessions before retrying failures. Retry-eligible checkpoints run before checkpoints whose provider cooldown is still active, and unresolved retries rotate to the queue tail so rate-limited dates cannot block later checkpoints. All Backtester endpoints in one server process share a request-start gate. It spaces starts by at least 100 ms by default, honors Retry-After before X-RateLimit-Reset, and falls back to bounded jittered 10/30/90-second cooldowns. Override only the pacing interval with TASTYTRADE_BACKTESTER_MIN_REQUEST_INTERVAL_MS; continuation retry timestamps remain provider- or scheduler-derived. Per-checkpoint stage timings identify cache lookup, provider bootstrap, contract-universe construction, candle reconstruction, selector evaluation, and the stage interrupted by a deadline. Operational settings and diagnostic callbacks do not alter the logical batch request ID or candle-cache fingerprints.

The official option-chain and REST quote endpoints do not document an historical as_of parameter. Backtester logs currently expose exact selected strike, expiration, side, and a provider-internal symbol, but those log fields are undocumented. The documented Backtester EntryConditions also has no time-of-day field, and a live request containing undocumented entryTime: "14:30:00Z" was silently ignored: the SPX trial still opened at 19:45:00Z.

For DELTA and PERCENTAGE_OTM, the adapter reconstructs a bounded SPXW universe from generated OCC/streamer symbols and completed DXLink candles. Candidate discovery uses the provider-supported maximum of 100 option symbols per candle batch; the standalone bounded-universe tool retains its existing 20-symbol batch policy. Omitting resolution_profile preserves the 5-minute cohort; strict native-hour RTH research requires explicit HOURLY_VALUATION_RESEARCH. When DXLink labels SPXW hour bars on its provider clock instead of the 09:30 ET session anchor, callers must opt into the separate HOURLY_PROVIDER_ALIGNED_RESEARCH cohort; those bars are never relabeled as session-aligned. It enforces available_at <= as_of, profile age/skew limits, aligned call/put parity for the forward, and contract-candle IV for Black-76-style delta. Selection is deterministic by selector error, observation age, DTE distance, and strike.

Generated contract identity becomes eligible only when DXLink returns historical evidence for that exact symbol. The result preserves checkpoint selection time, observation age, price, contract IV, reconstructed delta, volume/OI when present, OCC identity, and field-level provenance.

Exact-timestamp Backtester selection remains the fallback for unsupported selectors or insufficient reconstruction evidence. It never sends or trusts entryTime, and it accepts only a trial and opening order exactly at as_of. Stale and future trials remain fail-closed.

The capability returns HISTORICAL_SELECTOR_CANDIDATE_SET, never a full-chain snapshot. Historical bid/ask, ATM IV surface, skew, and term structure remain unavailable. Exact symbols are /simulate-trade compatible, but the capability separately reports whether an exact simulation snapshot exists at the arbitrary checkpoint.

The live 2026-08-25 07:30 PT smoke test returns four timestamp-safe CALL/PUT Delta-20 and 1%-OTM candidates without creating Backtester jobs.

The full provider findings, contract, anti-lookahead rules, and limitations are documented in docs/historical-spx-candidates.md.

Historical SPX candidate universe

tastytrade_get_historical_spx_candidate_universe expands checkpoint-safe evidence from selector winners into a caller-bounded strike grid. By default it covers the nearest min/mid/max DTE SPXW expirations, both option sides, and a 25-point strike step.

Generated OCC identity is returned only after DXLink supplies a completed historical candle for that exact symbol. Contracts without timestamp-safe evidence are omitted and counted as coverage gaps. The endpoint preserves price, reconstructed delta, contract IV, OI, volume, observation age, and field-level provenance when available; it never selects the final spread. Delta reconstruction prefers a timestamp-aligned put/call parity forward. When parity is unavailable but historical IV exists, the universe endpoint uses the completed checkpoint SPX price as an explicitly warned zero-carry forward approximation. Missing IV remains null, and this fallback does not change the stricter selector-discovery path.

The default freshness maximum is 60 minutes. A caller may explicitly extend it to 24 hours; older pre-checkpoint observations are then retained only as STALE/LOW evidence. Coverage gaps, provider batch errors, and per-field availability counts remain machine-readable, and aggregate field capability flags are true only when every returned contract supports the field.

Both historical SPX tools accept either RFC3339 as_of or an unambiguous IANA local_checkpoint. They preserve bar_start, bar_end, available_at, and retrieved_at, and return the normalized resolution profile with deterministic requested/effective cohort IDs. An opaque versioned candidate_construction_profile is returned unchanged; this MCP does not duplicate grading, DD-bucket, or final-leg-selection rules.

An optional dd_iv_measurement request freezes an exact four-leg Double Diagonal candidate and returns distinct SELECTED_LEG_IV_DIFFERENCE and MATCHED_DELTA / MATCHED_FORWARD_MONEYNESS cohorts. The handoff is always RESEARCH_ONLY, preserves provider/derived models, timestamp lineage, and optional immutable evidence-manifest IDs, and explicitly does not replace legacy production term_structure.

See docs/historical-spx-universe.md for the input contract, reconstruction rules, and live checkpoint findings.

Historical exact-leg package reconstruction

tastytrade_get_historical_option_package_at_checkpoint selects only completed option candles available by the requested checkpoint and preserves each leg’s exact OCC identity, derived streamer symbol, historical close, IV, bar-start timestamp, availability timestamp, age, and provenance. Explicit age and temporal-skew limits fail closed. Candle-derived values are always VALUATION_ONLY; historical bid/ask is not fabricated.

The checkpoint and path results include deterministic request IDs plus requested/native/effective aggregation, session, alignment, age/skew, fallback, and cohort metadata. The default checkpoint behavior remains the existing 5-minute compatibility path. Native-hour New York RTH valuation is explicit opt-in and does not silently fall into the 5-minute cohort. Checkpoint legs also return a structured reconstruction status and failure reason. Their provenance carries the requested lifecycle, resolution profile, provider failure reasons, source revision, and exact cache manifest/content IDs when available.

tastytrade_get_historical_option_package_horizons accepts a bounded frozen candidate inventory and a caller-supplied ordered trading-session calendar. It resolves ENTRY, OUTCOME_3_TRADING_DAYS, and OUTCOME_5_TRADING_DAYS by session index rather than assuming weekdays are trading days. Every horizon reuses the same OCC symbols, actions, quantities, roles, strategy family, and resolution profile. The result keeps candle references labeled VALUATION_ONLY / CANDLE_REFERENCE and reports complete package counts, missing legs by role, missing-reason counts, and coverage by strategy, expiration, entry DTE, and resolution profile. Exact 21/35-DTE Double Diagonals are supported without changing grading or leg selection.

An optional valuation_fallback can supply checkpoint-frozen SPX levels, per-exact-leg IV or surface inputs, rates, dividends, immutable source IDs, and an IV-shift uncertainty assumption. The strict candle status, package, legs, and failure taxonomy remain unchanged. A separate valuation object classifies each result as EXACT_PACKAGE_REFERENCE, MIXED_OBSERVED_MODELED, or MODEL_SURFACE; observed leg values are copied unchanged and only unavailable exact legs are modeled. Cache/provider errors, stale observations, and alignment failures remain non-modelable.

Any package containing a modeled leg is MODEL_REFERENCE / VALUATION_ONLY, carries guaranteed_executable: false, and is explicitly not bid/ask, NBBO, midpoint, touch, or fill evidence. Its execution_evidence_input can be passed to tastytrade_normalize_historical_execution_evidence and then evaluated only through a separately frozen REFERENCE_COST execution profile. Coverage keeps strict package counts separate from valued exact, mixed, and fully modeled cohorts.

tastytrade_get_historical_option_package_path emits a point only when every leg has an exact timestamp-aligned completed bar. It never interpolates or forward-fills missing legs. If a bounded old 1-minute DXLink replay exhausts a configured local resource budget or the provider returns a clipped snapshot, the result records the failed attempt and explicitly selects the finest retrievable coarser resolution. A local budget result is not described as a provider limit.

The returned fill_verification_path can be passed directly to tastytrade_verify_historical_fill. Full rules and the 2026-08-27 07:30 PT acceptance finding are documented in docs/historical-option-package.md.

Historical fill verification

tastytrade_verify_historical_fill:

  • evaluates only [submitted_at, valid_until];
  • accepts either caller-supplied historical package points or the existing exact-leg Backtester mode;
  • supports both ENTRY and EXIT;
  • preserves paper_order_id, checkpoint_id, and position_id references;
  • returns legacy status values TOUCHED, NOT_TOUCHED, or NOT_VERIFIABLE, plus assessment_status: NOT_ASSESSABLE for an insufficient path;
  • distinguishes LIMIT_TOUCH from CONSERVATIVE_CROSS;
  • reports an exact observed touch timestamp when defensible, otherwise a bounded interval for a sparse path;
  • records disagreement with a live paper assumption without mutating the original paper event.

All verification is marked POST_SESSION_REGRESSION and includes HISTORICAL_EVIDENCE_ONLY_DO_NOT_REWRITE_LIVE_EVENT.

tastytrade_get_historical_candles obtains an API quote token from GET /api-quote-tokens, connects only to a wss:// host under dxfeed.com, completes the DXLink handshake, and waits for the indexed-event snapshot boundary.

Optional price_type: LAST | BID | ASK selects separate provider-native price aggregates. LAST remains the default; BID/ASK are not synchronized NBBO and have no quote sizes or executable-package guarantee. Each price type has a distinct cache identity. Recent SPXW BID/ASK aggregates were retrieved, but July 2 minute history remains unavailable; dxFeed documents approximately 14 calendar days of BID/ASK candle retention. See docs/historical-candles.md for the measured coverage, request example, and completed-bar timing requirements.

The normalized output includes:

  • deterministic request and cohort identity;
  • dxlink_auth recovery provenance and a sanitized provider_error when authentication required recovery;
  • requested and actual UTC ranges;
  • source_time, bar_start, bar_end, available_at, and retrieved_at per bar;
  • explicit instrument type and interval;
  • ALL, US REGULAR, or caller-defined CUSTOM session filtering with an IANA timezone;
  • OHLC, volume, VWAP, bid/ask volume, implied volatility, and open interest when supplied;
  • missing-bar, empty-result, and snapshot-truncation warnings;
  • resampled: false.

REGULAR requests use provider-native a=s,tho=true candle attributes, so bars are aligned to and built only from the instrument’s regular trading session. CUSTOM windows filter complete provider bars by their source timestamp; they are never reaggregated and include an explicit warning about that limitation.

One-unit periods use DXLink’s native normalized spelling (m, h, d, or w). In particular, public interval 1h subscribes to native HOUR {=h}; 60m remains {=60m} and is not treated as equivalent. Request/response matching accepts only provider-defined canonical aliases such as omitted defaults and attribute ordering differences.

The server sends fromTime as epoch milliseconds, matching the current production DXLink service. The published AsyncAPI description currently says seconds, but seconds cause the service to replay the full available history. Production currently appears to ignore toTime. The client reports a continuous-calendar replay estimate for planning, but that estimate is explicitly advisory: it does not account for sessions, closures, sparse options, or expiration, and never blocks a request before connecting.

Streaming state is indexed and deduplicated per symbol, retains only rows in the requested range and session, serializes message processing, and does not infer completion from timestamp order. Completion still requires DXLink snapshot protocol evidence. Each result includes:

  • status, snapshot_complete, snapshot_truncated, and provider_snapshot_complete;
  • machine-readable failure_reasons;
  • per-symbol and aggregate request counters for received events, valid events, unique observations, retained rows/bytes, and returned rows;
  • configured limits and the advisory calendar-slot estimates.

snapshot_complete means a provider END marker was observed without local or provider truncation. It does not assert that every interval traded; status and failure_reasons separately report missing or uncovered evidence.

The independent client controls are:

Input Scope Default Maximum
max_output_candles retained/returned rows per symbol 10,000 250,000
max_received_events aggregate Candle protocol rows per request 10,000 1,000,000
max_buffer_bytes aggregate queued wire data plus accounted retained state 16 MiB 128 MiB
deadline_ms complete DXLink snapshot lifecycle 15,000 ms 60,000 ms

Received-event counts include marker, remove, invalid, duplicate, and unmatched Candle rows. Unique observations count distinct in-window indexed events admitted to bounded state; retained rows reflect removals, and returned rows reflect the final normalized output. Retained-byte accounting uses serialized field sizes plus conservative per-object/index overhead rather than claiming exact V8 heap usage.

max_candles remains as a deprecated compatibility shorthand, capped at 20,000, that applies the same value to per-symbol output and aggregate receive budgets. It cannot be combined with either explicit field. timeout_ms is a deprecated alias for deadline_ms and cannot be combined with it.

LOCAL_RECEIVE_BUDGET_EXCEEDED, LOCAL_BUFFER_BUDGET_EXCEEDED, and LOCAL_OUTPUT_BUDGET_EXCEEDED are client facts. PROVIDER_SNAPSHOT_SNIPPED is provider protocol evidence. REQUESTED_WINDOW_NOT_COVERED, SNAPSHOT_TIMEOUT, and MISSING_CONTRACT_EVIDENCE describe observed availability; none is automatically classified as an entitlement failure. Completed symbols remain usable when another batch symbol fails locally or is snipped.

Canonical identity, snapshot transaction rules, the sanitized timeout root cause, and live native-hour findings are documented in docs/historical-candles.md.

Rate limits and retries

  • API quote tokens use the provider’s expires-at timestamp with a one-minute safety margin. The previous 23-hour bound remains only as a fallback when the provider omits expiry metadata.
  • Historical candles and live option snapshots share one quote-token lifecycle in the production service. A post-AUTH UNAUTHORIZED invalidates both the cached quote token and cached OAuth access token, reacquires credentials, rebuilds the WebSocket connection, and retries exactly once.
  • Successful recovery returns dxlink_auth.status = REFRESHED with retry_count = 1. A second rejection returns explicit AUTH_FAILED diagnostics; a timeout before AUTH_STATE/AUTHORIZED is NOT_CONFIRMED. Tokens are never included.
  • The quote-token REST request retries network errors, 429, and 5xx up to three attempts with capped exponential backoff and jitter.
  • A candle snapshot has a configurable deadline_ms (maximum 60 seconds).
  • Non-authentication WebSocket failures are returned explicitly and are not silently retried or merged.
  • Received events, returned rows, and memory are bounded independently as documented above.
  • DXLink permits at most 5 concurrent sessions and 100 Candle subscriptions per session. Callers should batch work rather than fan out unbounded calls.

Security model

OAuth client credentials and refresh tokens are sent only to api.tastyworks.com. The short-lived OAuth token is sent to the fixed Backtester host and to the tastytrade quote-token endpoint. The resulting quote token is sent only over wss:// to a host under dxfeed.com.

Do not commit credentials. If using Node’s --env-file, unset inherited TASTYTRADE_* variables first because inherited values override the file. All API timestamps must be RFC3339 values containing Z or an explicit UTC offset; timezone-less timestamps are rejected.

The remote HTTP entrypoint supports two authentication modes:

  • api-key for local development and emergency rollback, using a constant-time comparison against MCP_API_KEY;
  • oauth for production, validating Entra JWT signature, issuer, audience, expiration, and mcp.read scope through cached JWKS.

OAuth mode publishes RFC 9728 protected-resource metadata at both supported well-known paths and includes that URL and the required scope in every 401 challenge. MCP is accepted only at POST /mcp, request bodies are limited to 1 MiB, and GET /healthz remains unauthenticated with health metadata only.

Requirements and setup

  • Node.js 22+
  • tastytrade OAuth API grant:
    • TASTYTRADE_CLIENT_ID
    • TASTYTRADE_CLIENT_SECRET
    • TASTYTRADE_REFRESH_TOKEN
  • A fully onboarded tastytrade customer for DXLink quote tokens
npm ci
npm run build

export TASTYTRADE_CLIENT_ID="..."
export TASTYTRADE_CLIENT_SECRET="..."
export TASTYTRADE_REFRESH_TOKEN="..."

npm start

For remote Streamable HTTP:

export MCP_API_KEY="$(openssl rand -hex 32)"
export MCP_HTTP_HOST=127.0.0.1
export MCP_HTTP_PORT=8000

npm run start:http

Connect to http://127.0.0.1:8000/mcp with Authorization: Bearer . Azure Container Apps deployment and Key Vault guidance are documented in docs/azure-deployment.md.

Production OAuth configuration additionally requires MCP_PUBLIC_URL, OAUTH_ISSUER, OAUTH_JWKS_URL, OAUTH_AUDIENCE, OAUTH_REQUIRED_SCOPE, and OAUTH_TOKEN_SCOPE. ChatGPT discovers the Entra authorization server from /.well-known/oauth-protected-resource, then sends its access token in the standard Authorization header.

For an MCP client:

{
  "mcpServers": {
    "tastytrade-research": {
      "command": "node",
      "args": ["/absolute/path/to/tastytrade-research-mcp/dist/index.js"],
      "env": {
        "TASTYTRADE_CLIENT_ID": "...",
        "TASTYTRADE_CLIENT_SECRET": "...",
        "TASTYTRADE_REFRESH_TOKEN": "..."
      }
    }
  }
}

Development

npm ci
npm run typecheck
npm test

The regression suite covers clean and degraded package markets, all supported spread families, regular and custom candle sessions, both fill models, ambiguous paths, Backtester normalization, and MCP tool dispatch.

Upstream documentation

Disclaimer

This is an independent research project and is not an official tastytrade product. Historical simulations can differ materially from live execution because of fills, liquidity, spreads, slippage, data availability, and model assumptions.

MIT License.

View this README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide

Configuration

{ "mcpServers": { "tastytrade-research": { "command": "node", "args": ["/absolute/path/to/tastytrade-research-mcp/dist/index.js"], "env": { "TASTYTRADE_CLIENT_ID": "...", "TASTYTRADE_CLIENT_SECRET": "...", "TASTYTRADE_REFRESH_TOKEN": "..." } } } }