Skip to content

Architecture Internals

tradesdontlie edited this page Jul 21, 2026 · 1 revision

Architecture Internals

How the bridge actually talks to TradingView. Useful if you're contributing, debugging, or writing a new tool.

The stack

Claude / MCP client
      │  (MCP over stdio)
      ▼
MCP Server  (Node.js, src/server.js)
      │  (Chrome DevTools Protocol via chrome-remote-interface)
      ▼
CDP endpoint  localhost:9222
      │
      ▼
TradingView Desktop  (Electron / Chromium)
  • Transport to the client: MCP over stdio.
  • Transport to TradingView: CDP on localhost:9222 via chrome-remote-interface. Tools evaluate JavaScript in the page context and read structured results back.
  • No BFS discovery at runtime. The bridge uses direct, known paths into TradingView's internals rather than searching for them each call.

Repository layout

src/
  server.js        # MCP server entry — registers all tool modules
  connection.js    # CDP connection management
  wait.js          # timing / readiness helpers
  core/            # business logic (health, update, chart ops, …)
  tools/           # one file per category; each registers server.tool(...)
    health.js      chart.js     data.js      pine.js
    indicators.js  drawing.js   alerts.js    replay.js
    tab.js         pane.js      ui.js        watchlist.js
    batch.js       capture.js   _format.js   (jsonResult helper)
  cli/             # command-line entry points

Each tool file exports a registerXxxTools(server) function that calls server.tool('name', 'description', schema, handler). Handlers wrap results with jsonResult(...) from _format.js and always return { success: true/false, ... }.

Known API paths into TradingView

The bridge reaches these internal objects directly:

Purpose Path
Active chart widget window.TradingViewApi._activeChartWidgetWV.value()
Bar data ..._chartWidget.model().mainSeries().bars()
Chart widget collection window.TradingViewApi._chartWidgetCollection
Bottom toolbar window.TradingView.bottomWidgetBar
Bar replay window.TradingViewApi._replayApi
Alerts window.TradingViewApi._alertService
WebSocket layer window.ChartApiInstance

Pine graphics path

The custom-indicator reading tools (Reading Custom Pine Output) walk into the study's private graphics collection:

study._graphics._primitivesCollection.dwglines.get('lines').get(false)._primitivesDataById

...with the analogous collections for labels, tables, and boxes. Results are normalized and deduplicated before being returned.

Lazy-opened panels

Some tools need a panel that may not be open yet — the bridge opens it on demand:

  • Pine Editor — auto-opened via bottomWidgetBar; Monaco is lazy-loaded and reached by traversing the React fiber tree.
  • Strategy Tester — auto-opened via bottomWidgetBar when querying results; a hidden strategy is auto-unhidden (TradingView never computes reports for hidden strategies).

Screenshots

capture_screenshot saves PNGs to the screenshots/ directory with timestamps and returns the file path (not the image bytes) — which is why it's so cheap on context. Regions: full, chart, strategy_tester.

Conventions

  • All tools return { success: true/false, ... }.
  • OHLCV capped at 500 bars; trades at 20 per request; Pine labels at 50 per study.
  • API path availability is logged to discovery-log.json.
  • Launch TradingView with scripts\launch_tv_debug.bat (direct EXE with --remote-debugging-port=9222) or the tv_launch tool.

Adding a new tool

  1. Add a server.tool('your_name', 'description', zodSchema, handler) call in the relevant src/tools/*.js file (or a new module registered in server.js).
  2. Put the real logic in src/core/ and keep the tool handler thin.
  3. Return via jsonResult({ success: true, ... }).
  4. Follow the context-size discipline in Context Management — offer a compact mode for anything potentially large.

See CONTRIBUTING for the full contribution flow.

Clone this wiki locally