Closed
Conversation
MCP (Model Context Protocol) server for TastyTrade trading operations. Consumed by DeerFlow AI agent (tasty-autonomus). Features: - OAuth authentication (clientId + clientSecret + refreshToken) - Same SDK v6 generateAccessToken patch as main TastyScanner app - 9 MCP tools: market overview, strategies, positions, execute trade, close position (safe guidance), adjust order (auto-replace), working orders, account info, connection status - Iron Condor strategy builder (server-side port of strategies-builder.ts) - DxLink quote streamer with 5s data wait for strategy calculations - HTTP transport (Streamable HTTP + legacy SSE fallback) - Docker-ready with health checks Architecture: - Independent TastyTrade session (not proxied through UI app) - Runs on internal Docker network only (port 7698) - Designed as sidecar container alongside main TastyScanner UI
- Removed SSEServerTransport (deprecated in MCP SDK, replaced by StreamableHTTPServerTransport) - Removed /sse and /messages endpoints — only /mcp (Streamable HTTP) remains - Added ENABLE_LIVE_TRADING env var (default: false) - Gates execute_trade and adjust_order tools - When disabled, both tools return TRADING_DISABLED error - All read-only tools (market overview, strategies, positions, etc.) work regardless - Startup log now shows trading status
Strategy builder now supports all strategies from main TastyScanner UI: Credit strategies (sell premium, positive theta): - Iron Condor — put spread + call spread, different short strikes - Put Credit Spread — STO put + BTO put below - Call Credit Spread — STO call + BTO call above - Iron Butterfly — like IC but short strikes at same ATM price - Jade Lizard — naked STO put + call spread (zero upside risk) - Twisted Sister — naked STO call + put spread (zero downside risk) Debit strategies (buy premium, negative theta): - Long Straddle — BTO put + BTO call at same strike - Long Strangle — BTO put + BTO call at different OTM strikes - Bull Call Spread — BTO call lower + STO call higher - Bear Put Spread — BTO put higher + STO put lower - Call Butterfly — BTO lower + 2xSTO mid + BTO upper (calls) - Put Butterfly — BTO lower + 2xSTO mid + BTO upper (puts) get_strategies tool: - New strategy_type param: 'all' or any specific type - Separate delta filters for credit vs debit strategies - debit_min_delta/debit_max_delta params (default 0.30-0.50) - Broken wing butterfly detection All 9 tool descriptions rewritten with clear, detailed explanations of what each tool does, when to use it, and what it returns.
getNestedOptionChain() returns an array — each element has .expirations. Previous code did rawChain?.expirations on the array, getting undefined → 0 expirations. Now iterates over the array (same as main app's tasty-market-data-provider.ts) and flattens all expirations. Also parseFloat on strike-price to match main app.
New tools: - get_watchlists — lists personal + TastyTrade platform watchlists - manage_watchlist — create/add/remove/delete personal watchlists get_market_overview enhanced: - watchlist param — scan symbols from a personal watchlist - public_watchlist param — scan from TastyTrade platform watchlists - hide_earnings_within_days filter — avoid IV crush risk - Response now includes source and count metadata tasty-client.ts: added getUserWatchlists, getPublicWatchlists, getWatchlist, createWatchlist, replaceWatchlist, deleteWatchlist DeerFlow workflow: 1. get_watchlists() → see available lists 2. get_market_overview(public_watchlist='High Options Volume') → scan 3. manage_watchlist(action='create', name='My Candidates', symbols=[...]) 4. get_market_overview(watchlist='My Candidates') → monitor your list 5. get_strategies(symbol) → find trades on candidates 6. manage_watchlist(action='remove', ...) → clean stale symbols Total: 11 MCP tools, 2809 lines
get_market_overview now uses a single 'watchlist' param instead of separate watchlist/public_watchlist. Resolution order: 1. Try personal watchlist by name 2. If not found, search TastyTrade platform watchlists (case-insensitive) 3. If neither found, return WATCHLIST_NOT_FOUND with hint to use get_watchlists() This means the agent can just call get_market_overview(watchlist='High IVR') without knowing if it's personal or platform — the tool figures it out. Removed public_watchlist param — no longer needed.
Added auto-reconnect logic for API calls that fail due to expired tokens, preventing concurrent reconnect attempts.
…on IDs Security: - MCP_AUTH_TOKEN env var for Bearer token auth on /mcp endpoints (constant-time comparison via crypto.timingSafeEqual) - CORS middleware (configurable via MCP_CORS_ORIGIN, default localhost:3333) - Rate limiter: 120 req/min per IP on MCP endpoints - Session IDs: crypto.randomUUID() instead of predictable Date.now() - Removed (transport as any).sessionId — use WeakMap tracking - Account numbers masked in logs (last 4 digits only) - Health endpoint shows auth_enabled and live_trading status README: - Removed TASTY_USERNAME/TASTY_PASSWORD (never existed in code) - Added correct OAuth env vars table with MCP_AUTH_TOKEN - Added auth headers to curl examples - Rewrote Security Notes section Docker: - Added MCP_AUTH_TOKEN to docker-compose.yml and combined.yml - Improved .dockerignore (.env.*, .DS_Store, docker-compose files)
Created src/tasty-api-types.ts with comprehensive interfaces: TastyAccountApiResponse, TastyBalanceApiResponse, TastyStreamerMessage, TastyStreamerEvent, TastyHttpClientInternals (SDK patch), TastyOrderApiResponse + Leg + Fill, TastyPositionApiResponse + Leg, TastyChainApiResponse + Expiration + Strike, TastyMetricsApiResponse, TastyEquityInfoApiResponse + TickSize, TastyWatchlistApiResponse + Entry, extractErrorMessage() + extractHttpStatus() helpers tasty-client.ts (26 → 0 any): - All public API methods now return typed responses - catch (err: any) → catch (err: unknown) + extractErrorMessage() - httpClient SDK patch: as any → as unknown as TastyHttpClientInternals - Streamer events: any → TastyStreamerEvent - Account loading: any[] → TastyAccountApiResponse[] mcp-server.ts (32 → 0 any): - All catch blocks: err: any → err: unknown + extractErrorMessage() - Watchlist parsing: any → TastyWatchlistApiResponse - Position parsing: any → TastyPositionApiResponse - Order parsing: any → TastyOrderApiResponse - Removed unsafe (x as any)?.data?.items fallbacks strategy-builder.ts (4 → 0 any): - _parseChain: any → TastyChainApiResponse - Expiration/strike mapping: typed interfaces Remaining 4 any: logger.ts (...args: any[]) — correct type for console.log variadic parameters, cannot be narrowed further.
- Fixed position leg mapping: TastyPositionApiResponse → TastyPositionLegApiResponse with proper fallback cast for single-leg positions - Fixed order property access: removed camelCase aliases (underlyingSymbol, priceEffect, orderType, timeInForce, receivedAt) — use only kebab-case from API - Fixed metrics mapping: parse close-price as string, default symbol to '' - Fixed watchlist entry extraction: always return string, not union type - Fixed publicFormatted type: symbol_count instead of symbols array - Fixed adjust_order: parse price string→number, use TastyOrderLegApiResponse for legs - Fixed strategy-builder: use only kebab-case expiration properties - Added index signatures to TastyPositionApiResponse, TastyPositionLegApiResponse, TastyOrderApiResponse to allow kebab-case property access - Build: npx tsc --noEmit passes with 0 errors
DxLink reconnect spam fix:
- Created market-status.ts (same logic as main app)
- When streamer disconnects and market is closed, logs one clean message
instead of spamming 'Unable to connect' every few seconds
- Polls every 60s, reconnects automatically when trading resumes
- market_status added to ConnectionStatus and health endpoint
Tool descriptions shortened ~60% for small model compatibility:
- get_market_overview: 8 lines → 2
- get_strategies: 15 lines → 4
- get_positions: 6 lines → 1
- execute_trade: 5 lines → 2
- close_position: 4 lines → 1
- adjust_order: 5 lines → 1
- get_account_info: 4 lines → 1
- get_connection_status: 4 lines → 1
- get_watchlists: 8 lines → 1
- manage_watchlist: 8 lines → 1
get_strategies improvements:
- Added max_loss parameter (filter by max loss per contract in $)
- Hard cap max_results at 50 (was unlimited)
- Response now wrapped: {symbol, strategy_type, total_found, returned, strategies}
so AI knows how many were filtered vs returned
- Logs total vs returned count
Bumps and [path-to-regexp](https://github.com/pillarjs/path-to-regexp). These dependencies needed to be updated together. Updates `path-to-regexp` from 8.3.0 to 8.4.0 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](pillarjs/path-to-regexp@v8.3.0...v8.4.0) Updates `path-to-regexp` from 0.1.12 to 0.1.13 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](pillarjs/path-to-regexp@v8.3.0...v8.4.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-version: 8.4.0 dependency-type: indirect - dependency-name: path-to-regexp dependency-version: 0.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]>
…dd8502de9 Bump path-to-regexp
- Add MIT LICENSE - Add CONTRIBUTING.md guidelines - Add CODEOWNERS for auto-review assignment - Add CodeQL security analysis workflow - Add Release workflow with Docker publishing - Update README with badges, sponsors section, and better structure - Configure Dependabot for npm, docker, and actions - Add issue templates (bug report, feature request) - Add PR template - Add GitHub Sponsors funding config
Bumps [zod](https://github.com/colinhacks/zod) from 3.25.76 to 4.3.6. - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](colinhacks/zod@v3.25.76...v4.3.6) --- updated-dependencies: - dependency-name: zod dependency-version: 4.3.6 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]>
auto-merge was automatically disabled
April 10, 2026 09:53
Pull request was closed
Contributor
Author
|
OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting If you change your mind, just re-open this PR and I'll resolve any conflicts on it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps zod from 3.25.76 to 4.3.6.
Release notes
Sourced from zod's releases.
... (truncated)
Commits
ca3c862v4.3.6762e911Generalize numeric key handlingdfbbf1cAvoid re-exported star modules (#5656)cbf77bbAvoid non null assertion (#5638)85db85efix: typo in codec.test.ts file (#5628)edd4132fix: add missing User-agent to robots.txt and allow all (#5646)251d716Clean up workflow_callf4b7baeUpdate pullfrog.yml (#5634)9977fb0Add brand.dev to sponsors0cdc0b84.3.5Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)