@dwlf/mcp-server 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/client.d.ts +10 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +87 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +45 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/resources/symbols.d.ts +4 -0
  12. package/dist/resources/symbols.d.ts.map +1 -0
  13. package/dist/resources/symbols.js +15 -0
  14. package/dist/resources/symbols.js.map +1 -0
  15. package/dist/tools/academy.d.ts +3 -0
  16. package/dist/tools/academy.d.ts.map +1 -0
  17. package/dist/tools/academy.js +130 -0
  18. package/dist/tools/academy.js.map +1 -0
  19. package/dist/tools/ai-summary.d.ts +4 -0
  20. package/dist/tools/ai-summary.d.ts.map +1 -0
  21. package/dist/tools/ai-summary.js +53 -0
  22. package/dist/tools/ai-summary.js.map +1 -0
  23. package/dist/tools/backtests.d.ts +4 -0
  24. package/dist/tools/backtests.d.ts.map +1 -0
  25. package/dist/tools/backtests.js +84 -0
  26. package/dist/tools/backtests.js.map +1 -0
  27. package/dist/tools/custom-events.d.ts +4 -0
  28. package/dist/tools/custom-events.d.ts.map +1 -0
  29. package/dist/tools/custom-events.js +72 -0
  30. package/dist/tools/custom-events.js.map +1 -0
  31. package/dist/tools/indicators.d.ts +4 -0
  32. package/dist/tools/indicators.d.ts.map +1 -0
  33. package/dist/tools/indicators.js +61 -0
  34. package/dist/tools/indicators.js.map +1 -0
  35. package/dist/tools/market-data.d.ts +4 -0
  36. package/dist/tools/market-data.d.ts.map +1 -0
  37. package/dist/tools/market-data.js +120 -0
  38. package/dist/tools/market-data.js.map +1 -0
  39. package/dist/tools/portfolio.d.ts +4 -0
  40. package/dist/tools/portfolio.d.ts.map +1 -0
  41. package/dist/tools/portfolio.js +70 -0
  42. package/dist/tools/portfolio.js.map +1 -0
  43. package/dist/tools/signals.d.ts +4 -0
  44. package/dist/tools/signals.d.ts.map +1 -0
  45. package/dist/tools/signals.js +69 -0
  46. package/dist/tools/signals.js.map +1 -0
  47. package/dist/tools/strategies.d.ts +4 -0
  48. package/dist/tools/strategies.d.ts.map +1 -0
  49. package/dist/tools/strategies.js +118 -0
  50. package/dist/tools/strategies.js.map +1 -0
  51. package/dist/tools/symbol-activations.d.ts +4 -0
  52. package/dist/tools/symbol-activations.d.ts.map +1 -0
  53. package/dist/tools/symbol-activations.js +191 -0
  54. package/dist/tools/symbol-activations.js.map +1 -0
  55. package/dist/tools/trades.d.ts +4 -0
  56. package/dist/tools/trades.d.ts.map +1 -0
  57. package/dist/tools/trades.js +180 -0
  58. package/dist/tools/trades.js.map +1 -0
  59. package/dist/tools/watchlist.d.ts +4 -0
  60. package/dist/tools/watchlist.d.ts.map +1 -0
  61. package/dist/tools/watchlist.js +50 -0
  62. package/dist/tools/watchlist.js.map +1 -0
  63. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DWLF / Andy Williams
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @dwlf/mcp-server
2
+
3
+ MCP server for the [DWLF](https://www.dwlf.co.uk) market analysis platform. 45+ tools that turn market noise into semantic data AI agents can reason about — candles, indicators, support/resistance, events, strategies, backtests, portfolios, trade journals, symbol activations, and more.
4
+
5
+ Works with Claude Desktop, Cursor, VS Code, and any MCP-compatible client.
6
+
7
+ ## Quick Start
8
+
9
+ The fastest way to get running — no cloning needed:
10
+
11
+ ```bash
12
+ npx -y @dwlf/mcp-server
13
+ ```
14
+
15
+ Or install globally:
16
+
17
+ ```bash
18
+ npm install -g @dwlf/mcp-server
19
+ dwlf-mcp-server
20
+ ```
21
+
22
+ You'll need a `DWLF_API_KEY` environment variable. See [Getting an API Key](#getting-an-api-key) below.
23
+
24
+ ## Claude Desktop
25
+
26
+ Add to your `claude_desktop_config.json`:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "dwlf": {
32
+ "command": "npx",
33
+ "args": ["-y", "@dwlf/mcp-server"],
34
+ "env": {
35
+ "DWLF_API_KEY": "dwlf_sk_your_key_here"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Cursor
43
+
44
+ Add to `.cursor/mcp.json`:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "dwlf": {
50
+ "command": "npx",
51
+ "args": ["-y", "@dwlf/mcp-server"],
52
+ "env": {
53
+ "DWLF_API_KEY": "dwlf_sk_your_key_here"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## VS Code
61
+
62
+ Add to `.vscode/mcp.json`:
63
+
64
+ ```json
65
+ {
66
+ "mcp": {
67
+ "servers": {
68
+ "dwlf": {
69
+ "command": "npx",
70
+ "args": ["-y", "@dwlf/mcp-server"],
71
+ "env": {
72
+ "DWLF_API_KEY": "dwlf_sk_your_key_here"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ ## Getting an API Key
81
+
82
+ 1. Sign up at [dwlf.co.uk](https://www.dwlf.co.uk)
83
+ 2. Go to **Settings → API Keys**
84
+ 3. Create a new key — it starts with `dwlf_sk_`
85
+ 4. Set it as `DWLF_API_KEY` in your MCP client config
86
+
87
+ ## Configuration
88
+
89
+ | Variable | Required | Default | Description |
90
+ |----------|----------|---------|-------------|
91
+ | `DWLF_API_KEY` | Yes | — | Your DWLF API key (`dwlf_sk_...`) |
92
+ | `DWLF_API_URL` | No | `https://api.dwlf.co.uk` | API base URL |
93
+
94
+ ## Tools
95
+
96
+ ### Market Data
97
+ Get OHLCV candles, list symbols, support/resistance levels, and indicator events (crossovers, breakouts, divergences, candlestick patterns).
98
+
99
+ ### Technical Indicators
100
+ RSI, MACD, EMA, Bollinger Bands, DSS, Ichimoku, trendlines, and more.
101
+
102
+ ### Trade Signals
103
+ Active signals, signal history with P&L, and performance stats (win rate, avg return).
104
+
105
+ ### Strategies
106
+ Create, update, compile, and browse visual trading strategies. List public community strategies.
107
+
108
+ ### Backtesting
109
+ Run backtests (async), get results with Sharpe ratios, and aggregate performance summaries.
110
+
111
+ ### Portfolio & Trade Journal
112
+ Portfolio holdings with P&L, historical snapshots, trade logging, notes, and plan templates.
113
+
114
+ ### Symbol Activations
115
+ Activate symbols for event detection and strategy signal generation. Manage which symbols are actively monitored.
116
+
117
+ ### Custom Events
118
+ Create custom indicator-based triggers (e.g. "DSS exits oversold with bullish cross").
119
+
120
+ ### AI Summaries
121
+ Full account dashboard, single-symbol briefs, and strategy performance overviews — pre-aggregated for AI consumption.
122
+
123
+ ### Academy
124
+ Browse educational tracks, read lessons, and search academy content.
125
+
126
+ ## Example Prompts
127
+
128
+ ```
129
+ "How's BTC looking right now?"
130
+ "Show me RSI and MACD for AAPL on the 4h chart"
131
+ "What active trade signals do we have?"
132
+ "Create a Golden Cross strategy using EMA 50/200"
133
+ "Backtest my strategy on NVDA over the last year"
134
+ "Log a long on ETH at 3,200 with stop at 3,050"
135
+ "Activate TSLA for my momentum strategy"
136
+ ```
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ git clone https://github.com/andywilliams/dwlf-mcp-server.git
142
+ cd dwlf-mcp-server
143
+ npm install
144
+ npm run build
145
+ DWLF_API_KEY=dwlf_sk_your_key npm run start
146
+ ```
147
+
148
+ For hot reload during development:
149
+
150
+ ```bash
151
+ DWLF_API_KEY=dwlf_sk_your_key npm run dev
152
+ ```
153
+
154
+ ## Cookbook
155
+
156
+ For multi-step workflows, see [docs/cookbook.md](https://github.com/andywilliams/dwlf-mcp-server/blob/master/docs/cookbook.md).
157
+
158
+ ## License
159
+
160
+ [MIT](LICENSE) — DWLF / Andy Williams
@@ -0,0 +1,10 @@
1
+ export declare function normalizeSymbol(input: string): string;
2
+ export declare class DWLFClient {
3
+ private http;
4
+ constructor();
5
+ get<T = unknown>(path: string, params?: Record<string, unknown>): Promise<T>;
6
+ post<T = unknown>(path: string, data?: Record<string, unknown>): Promise<T>;
7
+ put<T = unknown>(path: string, data?: Record<string, unknown>): Promise<T>;
8
+ delete<T = unknown>(path: string): Promise<T>;
9
+ }
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAqBA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwBrD;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAgB;;IAsBtB,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IAmBP,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC;IAKP,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC;IAKP,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAIpD"}
package/dist/client.js ADDED
@@ -0,0 +1,87 @@
1
+ import axios from 'axios';
2
+ /**
3
+ * Normalize symbol input to DWLF's expected format (e.g. BTC-USD).
4
+ *
5
+ * Accepts:
6
+ * BTC, BTC/USD, BTC-USD, btc, btc/usd, BTCUSD
7
+ * Returns:
8
+ * BTC-USD (crypto) or AAPL (stocks — no suffix needed)
9
+ *
10
+ * Crypto assets get "-USD" appended when no quote currency is present.
11
+ * Known stock/ETF tickers pass through unchanged.
12
+ */
13
+ const KNOWN_STOCKS = new Set([
14
+ 'NVDA', 'TSLA', 'META', 'AAPL', 'AMZN', 'GOOG', 'GOOGL', 'MSFT', 'AMD',
15
+ 'SLV', 'GDXJ', 'SILJ', 'AGQ', 'GLD', 'GDX', 'GOLD', // ETFs/metals
16
+ 'MARA', 'RIOT', 'BTBT', 'CIFR', 'IREN', 'CLSK', // crypto miners
17
+ 'COIN', 'MSTR', 'HUT', 'HIVE', 'BITF', 'WULF', // crypto-adjacent
18
+ 'LSPD', 'SOFI', // fintech
19
+ ]);
20
+ export function normalizeSymbol(input) {
21
+ let s = input.trim().toUpperCase();
22
+ // Already has separator: BTC/USD → BTC-USD, BTC-USD stays
23
+ if (s.includes('/')) {
24
+ return s.replace('/', '-');
25
+ }
26
+ if (s.includes('-')) {
27
+ return s;
28
+ }
29
+ // Known stock ticker — pass through as-is
30
+ if (KNOWN_STOCKS.has(s)) {
31
+ return s;
32
+ }
33
+ // Detect concatenated pair: BTCUSD, ETHUSD, SOLUSD etc.
34
+ const pairMatch = s.match(/^([A-Z]{2,5})(USD|USDT|EUR|GBP|BTC|ETH)$/);
35
+ if (pairMatch) {
36
+ return `${pairMatch[1]}-${pairMatch[2]}`;
37
+ }
38
+ // Bare crypto symbol: BTC → BTC-USD
39
+ return `${s}-USD`;
40
+ }
41
+ export class DWLFClient {
42
+ http;
43
+ constructor() {
44
+ const baseURL = process.env.DWLF_API_URL || 'https://api.dwlf.co.uk';
45
+ const apiKey = process.env.DWLF_API_KEY;
46
+ if (!apiKey) {
47
+ console.error('Warning: DWLF_API_KEY not set. Authenticated endpoints will fail.');
48
+ }
49
+ this.http = axios.create({
50
+ baseURL: `${baseURL}/v2`,
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ ...(apiKey ? { Authorization: `ApiKey ${apiKey}` } : {}),
54
+ },
55
+ timeout: 30000,
56
+ });
57
+ }
58
+ async get(path, params) {
59
+ // Filter out undefined params
60
+ const cleanParams = {};
61
+ if (params) {
62
+ for (const [key, value] of Object.entries(params)) {
63
+ if (value !== undefined) {
64
+ cleanParams[key] = value;
65
+ }
66
+ }
67
+ }
68
+ const config = {
69
+ params: Object.keys(cleanParams).length > 0 ? cleanParams : undefined,
70
+ };
71
+ const response = await this.http.get(path, config);
72
+ return response.data;
73
+ }
74
+ async post(path, data) {
75
+ const response = await this.http.post(path, data);
76
+ return response.data;
77
+ }
78
+ async put(path, data) {
79
+ const response = await this.http.put(path, data);
80
+ return response.data;
81
+ }
82
+ async delete(path) {
83
+ const response = await this.http.delete(path);
84
+ return response.data;
85
+ }
86
+ }
87
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { DWLFClient } from './client.js';
5
+ import { registerMarketDataTools } from './tools/market-data.js';
6
+ import { registerIndicatorTools } from './tools/indicators.js';
7
+ import { registerSignalTools } from './tools/signals.js';
8
+ import { registerWatchlistTools } from './tools/watchlist.js';
9
+ import { registerStrategyTools } from './tools/strategies.js';
10
+ import { registerBacktestTools } from './tools/backtests.js';
11
+ import { registerPortfolioTools } from './tools/portfolio.js';
12
+ import { registerTradeTools } from './tools/trades.js';
13
+ import { registerCustomEventTools } from './tools/custom-events.js';
14
+ import { registerAISummaryTools } from './tools/ai-summary.js';
15
+ import { registerAcademyTools } from './tools/academy.js';
16
+ import { registerSymbolActivationTools } from './tools/symbol-activations.js';
17
+ import { registerSymbolsResource } from './resources/symbols.js';
18
+ const server = new McpServer({
19
+ name: 'dwlf',
20
+ version: '0.3.0',
21
+ });
22
+ const client = new DWLFClient();
23
+ // Register all tools — Phase 1 (read)
24
+ registerMarketDataTools(server, client);
25
+ registerIndicatorTools(server, client);
26
+ registerSignalTools(server, client);
27
+ registerWatchlistTools(server, client);
28
+ // Register all tools — Phase 2 (read + write)
29
+ registerStrategyTools(server, client);
30
+ registerBacktestTools(server, client);
31
+ registerPortfolioTools(server, client);
32
+ registerTradeTools(server, client);
33
+ registerCustomEventTools(server, client);
34
+ // Register all tools — Phase 2b (symbol activation for events & strategies)
35
+ registerSymbolActivationTools(server, client);
36
+ // Register all tools — Phase 3 (AI summary endpoints)
37
+ registerAISummaryTools(server, client);
38
+ // Register all tools — Phase 4 (Academy — public CDN, no auth)
39
+ registerAcademyTools(server);
40
+ // Register resources
41
+ registerSymbolsResource(server, client);
42
+ // Start server with stdio transport
43
+ const transport = new StdioServerTransport();
44
+ await server.connect(transport);
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;AAEhC,sCAAsC;AACtC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,8CAA8C;AAC9C,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzC,4EAA4E;AAC5E,6BAA6B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,sDAAsD;AACtD,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,+DAA+D;AAC/D,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,qBAAqB;AACrB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAExC,oCAAoC;AACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { DWLFClient } from '../client.js';
3
+ export declare function registerSymbolsResource(server: McpServer, client: DWLFClient): void;
4
+ //# sourceMappingURL=symbols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../../src/resources/symbols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,QAkBnB"}
@@ -0,0 +1,15 @@
1
+ export function registerSymbolsResource(server, client) {
2
+ server.resource('symbols', 'dwlf://symbols', async (uri) => {
3
+ const symbols = await client.get('/market-data/symbols');
4
+ return {
5
+ contents: [
6
+ {
7
+ uri: uri.href,
8
+ mimeType: 'application/json',
9
+ text: JSON.stringify(symbols, null, 2),
10
+ },
11
+ ],
12
+ };
13
+ });
14
+ }
15
+ //# sourceMappingURL=symbols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../../src/resources/symbols.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAAkB;IAElB,MAAM,CAAC,QAAQ,CACb,SAAS,EACT,gBAAgB,EAChB,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACzD,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;iBACvC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerAcademyTools(server: McpServer): void;
3
+ //# sourceMappingURL=academy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"academy.d.ts","sourceRoot":"","sources":["../../src/tools/academy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2DpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,QAuIrD"}
@@ -0,0 +1,130 @@
1
+ import { z } from 'zod';
2
+ import axios from 'axios';
3
+ const ACADEMY_BASE = 'https://academy.dwlf.co.uk/live';
4
+ const MANIFEST_TTL_MS = 15 * 60 * 1000; // 15 minutes
5
+ // ── Cached manifest ───────────────────────────────────────────────
6
+ let cachedManifest = null;
7
+ let cacheTimestamp = 0;
8
+ async function getManifest() {
9
+ const now = Date.now();
10
+ if (cachedManifest && now - cacheTimestamp < MANIFEST_TTL_MS) {
11
+ return cachedManifest;
12
+ }
13
+ const { data } = await axios.get(`${ACADEMY_BASE}/manifest.json`, { timeout: 15000 });
14
+ cachedManifest = data;
15
+ cacheTimestamp = now;
16
+ return data;
17
+ }
18
+ // ── Image URL rewriter ────────────────────────────────────────────
19
+ function rewriteImageUrls(markdown) {
20
+ // Convert relative image paths to absolute CDN URLs
21
+ // Handles: ![alt](assets/img/foo.svg) and ![alt](./assets/img/foo.svg)
22
+ return markdown.replace(/!\[([^\]]*)\]\((?:\.\/)?assets\//g, `![$1](${ACADEMY_BASE}/assets/`);
23
+ }
24
+ // ── Tool registration ─────────────────────────────────────────────
25
+ export function registerAcademyTools(server) {
26
+ // 1. List all tracks and lessons
27
+ server.tool('dwlf_list_academy_tracks', 'List all DWLF Academy tracks and lessons. Use this to discover educational content about DWLF concepts — indicators, events, strategies, charting, and more.', {}, async () => {
28
+ try {
29
+ const manifest = await getManifest();
30
+ return {
31
+ content: [
32
+ { type: 'text', text: JSON.stringify(manifest, null, 2) },
33
+ ],
34
+ };
35
+ }
36
+ catch (error) {
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: `Error fetching academy manifest: ${error instanceof Error ? error.message : String(error)}`,
42
+ },
43
+ ],
44
+ isError: true,
45
+ };
46
+ }
47
+ });
48
+ // 2. Get a single lesson by slug
49
+ server.tool('dwlf_get_academy_lesson', 'Get the full content of a DWLF Academy lesson by slug. Returns markdown. Use dwlf_list_academy_tracks first to find available lessons.', {
50
+ slug: z
51
+ .string()
52
+ .describe('Lesson slug from the academy manifest (e.g. "intro-to-indicators")'),
53
+ }, async ({ slug }) => {
54
+ try {
55
+ const { data } = await axios.get(`${ACADEMY_BASE}/lessons/${slug}.md`, { timeout: 15000, responseType: 'text' });
56
+ const content = rewriteImageUrls(data);
57
+ return {
58
+ content: [{ type: 'text', text: content }],
59
+ };
60
+ }
61
+ catch (error) {
62
+ const msg = axios.isAxiosError(error) && error.response?.status === 404
63
+ ? `Lesson "${slug}" not found. Use dwlf_list_academy_tracks to see available lessons.`
64
+ : `Error fetching lesson "${slug}": ${error instanceof Error ? error.message : String(error)}`;
65
+ return {
66
+ content: [{ type: 'text', text: msg }],
67
+ isError: true,
68
+ };
69
+ }
70
+ });
71
+ // 3. Search academy content by keyword
72
+ server.tool('dwlf_search_academy', 'Search DWLF Academy content by keyword. Searches track and lesson titles. Returns matching lessons with their track context.', {
73
+ query: z
74
+ .string()
75
+ .describe('Search term to match against track/lesson titles and descriptions'),
76
+ }, async ({ query }) => {
77
+ try {
78
+ const manifest = await getManifest();
79
+ const q = query.toLowerCase();
80
+ const results = [];
81
+ for (const track of manifest.tracks) {
82
+ const trackMatch = track.title.toLowerCase().includes(q) ||
83
+ track.description.toLowerCase().includes(q);
84
+ const matchedLessons = track.lessons.filter((l) => l.title.toLowerCase().includes(q));
85
+ if (trackMatch || matchedLessons.length > 0) {
86
+ results.push({
87
+ track: {
88
+ id: track.id,
89
+ title: track.title,
90
+ description: track.description,
91
+ },
92
+ matchedLessons: matchedLessons.length > 0
93
+ ? matchedLessons
94
+ : trackMatch
95
+ ? track.lessons
96
+ : [],
97
+ trackMatch,
98
+ });
99
+ }
100
+ }
101
+ if (results.length === 0) {
102
+ return {
103
+ content: [
104
+ {
105
+ type: 'text',
106
+ text: `No academy content found for "${query}". Use dwlf_list_academy_tracks to browse all content.`,
107
+ },
108
+ ],
109
+ };
110
+ }
111
+ return {
112
+ content: [
113
+ { type: 'text', text: JSON.stringify(results, null, 2) },
114
+ ],
115
+ };
116
+ }
117
+ catch (error) {
118
+ return {
119
+ content: [
120
+ {
121
+ type: 'text',
122
+ text: `Error searching academy: ${error instanceof Error ? error.message : String(error)}`,
123
+ },
124
+ ],
125
+ isError: true,
126
+ };
127
+ }
128
+ });
129
+ }
130
+ //# sourceMappingURL=academy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"academy.js","sourceRoot":"","sources":["../../src/tools/academy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { DWLFClient } from '../client.js';
3
+ export declare function registerAISummaryTools(server: McpServer, client: DWLFClient): void;
4
+ //# sourceMappingURL=ai-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-summary.d.ts","sourceRoot":"","sources":["../../src/tools/ai-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAmB,MAAM,cAAc,CAAC;AAE3D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,QAgEnB"}
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ import { normalizeSymbol } from '../client.js';
3
+ export function registerAISummaryTools(server, client) {
4
+ // 1. AI Dashboard
5
+ server.tool('dwlf_ai_dashboard', 'Get a complete account overview in a single call: watchlist with prices, active signals, open trades, portfolios, strategies, and recent events. Ideal for "what\'s going on?" queries. Requires markets:read permission; other sections degrade gracefully based on permissions.', {}, async () => {
6
+ try {
7
+ const data = await client.get('/ai/dashboard');
8
+ return {
9
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
10
+ };
11
+ }
12
+ catch (error) {
13
+ return {
14
+ content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
15
+ isError: true,
16
+ };
17
+ }
18
+ });
19
+ // 2. AI Symbol Brief
20
+ server.tool('dwlf_ai_symbol_brief', 'Get a condensed single-symbol view: latest price with change, recent candles, key indicators, S/R levels, recent events, and active signals. Perfect for "how\'s BTC doing?" queries.', {
21
+ symbol: z.string().describe('Symbol to get brief for (e.g. BTC, TSLA, NVDA)'),
22
+ }, async ({ symbol }) => {
23
+ try {
24
+ const normalized = normalizeSymbol(symbol);
25
+ const data = await client.get(`/ai/symbol-brief/${normalized}`);
26
+ return {
27
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
28
+ };
29
+ }
30
+ catch (error) {
31
+ return {
32
+ content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
33
+ isError: true,
34
+ };
35
+ }
36
+ });
37
+ // 3. AI Strategy Performance
38
+ server.tool('dwlf_ai_strategy_performance', 'Get all strategies with signal stats and performance metrics in a single call: total signals, active signals, win rate, avg R/R, total P&L, and per-strategy breakdowns.', {}, async () => {
39
+ try {
40
+ const data = await client.get('/ai/strategy-performance');
41
+ return {
42
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
43
+ };
44
+ }
45
+ catch (error) {
46
+ return {
47
+ content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
48
+ isError: true,
49
+ };
50
+ }
51
+ });
52
+ }
53
+ //# sourceMappingURL=ai-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-summary.js","sourceRoot":"","sources":["../../src/tools/ai-summary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAc,eAAe,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAkB;IAElB,kBAAkB;IAClB,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,mRAAmR,EACnR,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC/C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACjE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACrG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,qBAAqB;IACrB,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,uLAAuL,EACvL;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,oBAAoB,UAAU,EAAE,CAAC,CAAC;YAChE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACjE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACrG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,6BAA6B;IAC7B,MAAM,CAAC,IAAI,CACT,8BAA8B,EAC9B,0KAA0K,EAC1K,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAC1D,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACjE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACrG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { DWLFClient } from '../client.js';
3
+ export declare function registerBacktestTools(server: McpServer, client: DWLFClient): void;
4
+ //# sourceMappingURL=backtests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backtests.d.ts","sourceRoot":"","sources":["../../src/tools/backtests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAmB,MAAM,cAAc,CAAC;AAE3D,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,QAkGnB"}