@aetherwealth/mcp 0.1.18-beta.4 → 0.1.18
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.
- package/README.md +124 -121
- package/dist/index.js +2 -2
- package/package.json +23 -3
package/README.md
CHANGED
|
@@ -1,146 +1,149 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Aether Wealth MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Official Model Context Protocol (MCP) server for Aether Wealth. Connect any
|
|
4
|
+
stdio-compatible MCP client to your Aether Wealth trading journal, accounts,
|
|
5
|
+
alerts, market context, macro calendar, and technical indicators.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
The package runs locally with `npx`, authenticates with browser-based OAuth, and
|
|
8
|
+
uses your Aether Wealth account permissions for every data tool. It is built for
|
|
9
|
+
traders who want an AI assistant to inspect their journal, summarize performance,
|
|
10
|
+
create alerts, and fetch market context without copying API keys into their MCP
|
|
11
|
+
client.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
> exposed — trades are permanent records; delete them in the web app. Market-data
|
|
13
|
-
> tools are public (work without sign-in); everything else needs `login`.
|
|
13
|
+
## Install
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
**Auth**
|
|
18
|
-
|
|
19
|
-
| Tool | Purpose |
|
|
20
|
-
|------|---------|
|
|
21
|
-
| `login` | Sign in. Opens the browser; after you approve, the MCP stores a per-user token. |
|
|
22
|
-
| `logout` | Sign out on this device (clears the stored token). |
|
|
23
|
-
|
|
24
|
-
**Trades** (require sign-in)
|
|
25
|
-
|
|
26
|
-
| Tool | Purpose |
|
|
27
|
-
|------|---------|
|
|
28
|
-
| `list_trades` | List trades; filter by account, status, pair, or date range. |
|
|
29
|
-
| `get_trade` | Get a single trade by id. |
|
|
30
|
-
| `list_accounts` | List trading accounts (for `create_trade`'s `accountId`). |
|
|
31
|
-
| `trade_stats` | Performance statistics (win rate, PnL, …). |
|
|
32
|
-
| `create_trade` | Record a new trade. |
|
|
33
|
-
| `update_trade` | Update fields on a trade. |
|
|
34
|
-
| `close_trade` | Close an open trade with an exit price + time. |
|
|
35
|
-
|
|
36
|
-
**Alerts** (require sign-in)
|
|
37
|
-
|
|
38
|
-
| Tool | Purpose |
|
|
39
|
-
|------|---------|
|
|
40
|
-
| `list_alerts` / `list_indicator_alerts` | List price+trendline / indicator alerts. |
|
|
41
|
-
| `create_price_alert` | Price-level alert (above/below/crosses). |
|
|
42
|
-
| `create_trendline_alert` | Trendline alert from two points. |
|
|
43
|
-
| `create_indicator_alert` | Indicator-output alert (e.g. RSI crosses 70). |
|
|
44
|
-
| `update_alert` / `delete_alert` | Update / delete a price/trendline alert. |
|
|
45
|
-
| `update_indicator_alert` / `delete_indicator_alert` | Update / delete an indicator alert. |
|
|
15
|
+
Use the package in any MCP client that can launch a local stdio server.
|
|
46
16
|
|
|
47
|
-
|
|
17
|
+
```bash
|
|
18
|
+
npx -y @aetherwealth/mcp
|
|
19
|
+
```
|
|
48
20
|
|
|
49
|
-
|
|
50
|
-
|------|---------|
|
|
51
|
-
| `get_candles` | Recent OHLC candles (up to 500) for a pair + timeframe, read from Redis. |
|
|
52
|
-
| `list_economic_calendar` | Economic calendar events; filter by currency, date, impact. |
|
|
53
|
-
| `get_macro_series` | Macro indicator time series (e.g. USD cpi). |
|
|
54
|
-
| `get_market_config` | Catalog of supported instruments + timeframes. |
|
|
21
|
+
Most MCP clients use a JSON config like this:
|
|
55
22
|
|
|
56
|
-
|
|
57
|
-
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"aether-wealth": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["-y", "@aetherwealth/mcp"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
58
33
|
|
|
59
|
-
|
|
34
|
+
Restart your MCP client after adding the server. Then ask it to run the
|
|
35
|
+
`login` tool once.
|
|
60
36
|
|
|
61
|
-
|
|
37
|
+
## What It Does
|
|
62
38
|
|
|
63
|
-
|
|
64
|
-
2. Start a loopback listener on `127.0.0.1` (a fixed port from a small set).
|
|
65
|
-
3. Open the browser to the authorize URL. If you're already signed in to the
|
|
66
|
-
Aether Wealth web app it completes immediately; otherwise you sign in there.
|
|
67
|
-
4. The redirect lands on the loopback listener with an authorization code, which
|
|
68
|
-
is exchanged (with the PKCE verifier) for an access token.
|
|
69
|
-
5. The token is stored in the **OS keychain** (macOS Keychain / Windows
|
|
70
|
-
Credential Manager / Linux libsecret), with a `0600`-file fallback, keyed by
|
|
71
|
-
backend host so prod and beta tokens coexist.
|
|
39
|
+
Aether Wealth MCP gives AI assistants a safe tool layer over Aether Wealth:
|
|
72
40
|
|
|
73
|
-
|
|
74
|
-
|
|
41
|
+
- Read and summarize your trading journal
|
|
42
|
+
- List accounts and performance stats
|
|
43
|
+
- Create, update, and close trade records
|
|
44
|
+
- Create and manage price, trendline, and indicator alerts
|
|
45
|
+
- Fetch candles, economic calendar events, macro series, and market config
|
|
46
|
+
- Compute technical indicators such as RSI, MACD, EMA, Bollinger Bands, ATR,
|
|
47
|
+
ADX, Supertrend, and more
|
|
75
48
|
|
|
76
|
-
|
|
49
|
+
Aether Wealth is trading analysis and journaling software. This MCP server does
|
|
50
|
+
not place broker orders or execute trades.
|
|
77
51
|
|
|
78
|
-
|
|
52
|
+
## Authentication
|
|
79
53
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| `AETHER_MCP_CREDENTIALS_FILE` | no | Set to force the `0600`-file credential store instead of the OS keychain. |
|
|
84
|
-
| `MCP_TRANSPORT` | no | `stdio` (default) or `http`. |
|
|
85
|
-
| `MCP_HTTP_PORT` / `MCP_HTTP_HOST` / `MCP_HTTP_PATH` / `MCP_HTTP_BEARER` | no | HTTP transport only. |
|
|
54
|
+
The `login` tool opens the Aether Wealth OAuth flow in your browser. After you
|
|
55
|
+
approve access, the MCP stores a local token in the operating-system keychain
|
|
56
|
+
where available, with a protected file fallback.
|
|
86
57
|
|
|
87
|
-
|
|
58
|
+
No shared API key is configured in your MCP client. All data tools require
|
|
59
|
+
OAuth sign-in, including market-data tools. `logout` clears the local
|
|
60
|
+
credential for this device.
|
|
88
61
|
|
|
89
|
-
|
|
90
|
-
# From the repo root
|
|
91
|
-
bun run --filter=@aetherwealth/mcp start
|
|
92
|
-
# Or directly
|
|
93
|
-
cd apps/aether-wealth-mcp && bun run src/index.ts
|
|
94
|
-
```
|
|
62
|
+
## Tools
|
|
95
63
|
|
|
96
|
-
###
|
|
64
|
+
### Auth
|
|
97
65
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"command": "bun",
|
|
103
|
-
"args": ["run", "/abs/path/to/apps/aether-wealth-mcp/src/index.ts"],
|
|
104
|
-
"env": { "AETHER_BASE_URL": "https://api.aetherwealth.ai" }
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
```
|
|
66
|
+
| Tool | Purpose |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `login` | Sign in with Aether Wealth OAuth. |
|
|
69
|
+
| `logout` | Clear the local OAuth credential on this device. |
|
|
109
70
|
|
|
110
|
-
|
|
111
|
-
sign-in, and your trades become available.
|
|
71
|
+
### Trades, Accounts, And Stats
|
|
112
72
|
|
|
113
|
-
|
|
73
|
+
| Tool | Purpose |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `list_trades` | List trades by account, status, pair, or date range. |
|
|
76
|
+
| `get_trade` | Fetch one trade by ID. |
|
|
77
|
+
| `list_accounts` | List your trading accounts. |
|
|
78
|
+
| `trade_stats` | Summarize performance, win rate, PnL, and related stats. |
|
|
79
|
+
| `create_trade` | Record a new trade. |
|
|
80
|
+
| `update_trade` | Update fields on an existing trade. |
|
|
81
|
+
| `close_trade` | Close an open trade with exit price and time. |
|
|
114
82
|
|
|
115
|
-
|
|
116
|
-
bun run --filter=@aetherwealth/mcp test # vitest
|
|
117
|
-
bun run --filter=@aetherwealth/mcp typecheck # tsc --noEmit
|
|
118
|
-
bun run --filter=@aetherwealth/mcp lint # biome
|
|
119
|
-
bun run --filter=@aetherwealth/mcp build # bun bundle → dist/
|
|
120
|
-
```
|
|
83
|
+
### Alerts
|
|
121
84
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
85
|
+
| Tool | Purpose |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `list_alerts` | List price and trendline alerts. |
|
|
88
|
+
| `create_price_alert` | Create a price-level alert. |
|
|
89
|
+
| `create_trendline_alert` | Create a trendline alert from two chart points. |
|
|
90
|
+
| `update_alert` | Update or archive a price or trendline alert. |
|
|
91
|
+
| `delete_alert` | Delete a price or trendline alert. |
|
|
92
|
+
| `list_indicator_alerts` | List indicator-based alerts. |
|
|
93
|
+
| `create_indicator_alert` | Create an alert on an indicator output condition. |
|
|
94
|
+
| `update_indicator_alert` | Update an indicator alert. |
|
|
95
|
+
| `delete_indicator_alert` | Delete an indicator alert. |
|
|
96
|
+
|
|
97
|
+
### Market Context
|
|
126
98
|
|
|
127
|
-
|
|
99
|
+
| Tool | Purpose |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `get_candles` | Fetch recent OHLC candles for a pair and timeframe. |
|
|
102
|
+
| `list_economic_calendar` | List economic calendar events by currency, release, date, or impact. |
|
|
103
|
+
| `get_macro_series` | Fetch macro indicator time series such as CPI or interest-rate data. |
|
|
104
|
+
| `get_market_config` | Fetch supported instruments and timeframes. |
|
|
128
105
|
|
|
129
|
-
|
|
130
|
-
index.ts entry: config → credential store → OAuth session → tRPC client → transport
|
|
131
|
-
config.ts env → { baseUrl, trpcUrl, host } (OAuth-only)
|
|
132
|
-
trpc-client.ts typed tRPC client (AppRouter); attaches Bearer token per request
|
|
133
|
-
tool-registry.ts login / logout / list_trades; McpToolContext = { session, trpc }
|
|
134
|
-
server.ts registry → @modelcontextprotocol/sdk request-handler bridge
|
|
135
|
-
oauth/
|
|
136
|
-
contract.ts client id / redirect ports / scopes (mirrors aether-backend constants)
|
|
137
|
-
pkce.ts PKCE verifier + S256 challenge, state
|
|
138
|
-
discovery.ts fetch the AS openid-configuration
|
|
139
|
-
loopback.ts loopback redirect listener (captures code/state)
|
|
140
|
-
browser.ts open the system browser
|
|
141
|
-
login.ts runLogin: PKCE → loopback → browser → token exchange
|
|
142
|
-
credential-store.ts OS keychain + 0600-file fallback, keyed by host
|
|
143
|
-
session.ts OAuthSession: getAccessToken / login / logout
|
|
144
|
-
```
|
|
106
|
+
### Technical Indicators
|
|
145
107
|
|
|
146
|
-
|
|
108
|
+
| Tool | Purpose |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `get_indicators` | Compute up to 8 technical indicators for a pair and interval. |
|
|
111
|
+
|
|
112
|
+
## Example Prompts
|
|
113
|
+
|
|
114
|
+
- "List my open trades and group them by pair. Flag anything without a stop
|
|
115
|
+
loss."
|
|
116
|
+
- "Summarize my last 20 closed trades. What setup is leaking the most R?"
|
|
117
|
+
- "What high-impact USD events are left this week, and which open trades overlap
|
|
118
|
+
them?"
|
|
119
|
+
- "Fetch EUR/USD 1h RSI and MACD, then create an alert if RSI crosses below 40."
|
|
120
|
+
- "Create a price alert if XAU/USD crosses yesterday's high before New York
|
|
121
|
+
open."
|
|
122
|
+
|
|
123
|
+
## Safety And Limits
|
|
124
|
+
|
|
125
|
+
- OAuth is per user. Your MCP client does not store a shared service secret.
|
|
126
|
+
- Tokens are stored locally and can be cleared with `logout`.
|
|
127
|
+
- Backend rate limits protect market-data reads, MCP Bearer traffic, and
|
|
128
|
+
cost-sensitive indicator calls.
|
|
129
|
+
- Technical indicators include request, active-pair, cache, and upstream credit
|
|
130
|
+
gates.
|
|
131
|
+
- Destructive trade and account deletion tools are intentionally not exposed.
|
|
132
|
+
- The MCP does not execute trades or route broker orders.
|
|
133
|
+
|
|
134
|
+
## Updating
|
|
135
|
+
|
|
136
|
+
If your MCP client launches the server with `npx -y @aetherwealth/mcp`, restart
|
|
137
|
+
the client to pick up the current published package.
|
|
138
|
+
|
|
139
|
+
The backend can also advertise a minimum supported MCP version. If your local
|
|
140
|
+
server is too old, tool calls return an update-required message instead of
|
|
141
|
+
failing silently.
|
|
142
|
+
|
|
143
|
+
## Links
|
|
144
|
+
|
|
145
|
+
- Aether Wealth: https://aetherwealth.ai
|
|
146
|
+
- Trading app: https://app.aetherwealth.ai
|
|
147
|
+
- MCP page: https://aetherwealth.ai/mcp
|
|
148
|
+
- Tool reference: https://aetherwealth.ai/mcp-tools.json
|
|
149
|
+
- npm package: https://www.npmjs.com/package/@aetherwealth/mcp
|
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ data:
|
|
|
82
82
|
`;return G+=`data: ${JSON.stringify(Y)}
|
|
83
83
|
|
|
84
84
|
`,Q.enqueue(X.encode(G)),!0}catch(G){return this.onerror?.(G),!1}}handleUnsupportedRequest(){return this.onerror?.(Error("Method not allowed.")),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32000,message:"Method not allowed."},id:null}),{status:405,headers:{Allow:"GET, POST, DELETE","Content-Type":"application/json"}})}async handlePostRequest(Q,X){try{let Y=Q.headers.get("accept");if(!Y?.includes("application/json")||!Y.includes("text/event-stream"))return this.onerror?.(Error("Not Acceptable: Client must accept both application/json and text/event-stream")),this.createJsonErrorResponse(406,-32000,"Not Acceptable: Client must accept both application/json and text/event-stream");let W=Q.headers.get("content-type");if(!W||!W.includes("application/json"))return this.onerror?.(Error("Unsupported Media Type: Content-Type must be application/json")),this.createJsonErrorResponse(415,-32000,"Unsupported Media Type: Content-Type must be application/json");let G={headers:Object.fromEntries(Q.headers.entries()),url:new URL(Q.url)},J;if(X?.parsedBody!==void 0)J=X.parsedBody;else try{J=await Q.json()}catch{return this.onerror?.(Error("Parse error: Invalid JSON")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON")}let B;try{if(Array.isArray(J))B=J.map((M)=>q9.parse(M));else B=[q9.parse(J)]}catch{return this.onerror?.(Error("Parse error: Invalid JSON-RPC message")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON-RPC message")}let H=B.some(uX);if(H){if(this._initialized&&this.sessionId!==void 0)return this.onerror?.(Error("Invalid Request: Server already initialized")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Server already initialized");if(B.length>1)return this.onerror?.(Error("Invalid Request: Only one initialization request is allowed")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Only one initialization request is allowed");if(this.sessionId=this.sessionIdGenerator?.(),this._initialized=!0,this.sessionId&&this._onsessioninitialized)await Promise.resolve(this._onsessioninitialized(this.sessionId))}if(!H){let M=this.validateSession(Q);if(M)return M;let q=this.validateProtocolVersion(Q);if(q)return q}if(!B.some(G1)){for(let M of B)this.onmessage?.(M,{authInfo:X?.authInfo,requestInfo:G});return new Response(null,{status:202})}let z=crypto.randomUUID(),A=B.find((M)=>uX(M)),Z=A?A.params.protocolVersion:Q.headers.get("mcp-protocol-version")??_G;if(this._enableJsonResponse)return new Promise((M)=>{this._streamMapping.set(z,{resolveJson:M,cleanup:()=>{this._streamMapping.delete(z)}});for(let q of B)if(G1(q))this._requestToStreamMapping.set(q.id,z);for(let q of B)this.onmessage?.(q,{authInfo:X?.authInfo,requestInfo:G})});let D=new TextEncoder,F,V=new ReadableStream({start:(M)=>{F=M},cancel:()=>{this._streamMapping.delete(z)}}),L={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};if(this.sessionId!==void 0)L["mcp-session-id"]=this.sessionId;for(let M of B)if(G1(M))this._streamMapping.set(z,{controller:F,encoder:D,cleanup:()=>{this._streamMapping.delete(z);try{F.close()}catch{}}}),this._requestToStreamMapping.set(M.id,z);await this.writePrimingEvent(F,D,z,Z);for(let M of B){let q,O;if(G1(M)&&this._eventStore&&Z>="2025-11-25")q=()=>{this.closeSSEStream(M.id)},O=()=>{this.closeStandaloneSSEStream()};this.onmessage?.(M,{authInfo:X?.authInfo,requestInfo:G,closeSSEStream:q,closeStandaloneSSEStream:O})}return new Response(V,{status:200,headers:L})}catch(Y){return this.onerror?.(Y),this.createJsonErrorResponse(400,-32700,"Parse error",{data:String(Y)})}}async handleDeleteRequest(Q){let X=this.validateSession(Q);if(X)return X;let Y=this.validateProtocolVersion(Q);if(Y)return Y;return await Promise.resolve(this._onsessionclosed?.(this.sessionId)),await this.close(),new Response(null,{status:200})}validateSession(Q){if(this.sessionIdGenerator===void 0)return;if(!this._initialized)return this.onerror?.(Error("Bad Request: Server not initialized")),this.createJsonErrorResponse(400,-32000,"Bad Request: Server not initialized");let X=Q.headers.get("mcp-session-id");if(!X)return this.onerror?.(Error("Bad Request: Mcp-Session-Id header is required")),this.createJsonErrorResponse(400,-32000,"Bad Request: Mcp-Session-Id header is required");if(X!==this.sessionId)return this.onerror?.(Error("Session not found")),this.createJsonErrorResponse(404,-32001,"Session not found");return}validateProtocolVersion(Q){let X=Q.headers.get("mcp-protocol-version");if(X!==null&&!v1.includes(X))return this.onerror?.(Error(`Bad Request: Unsupported protocol version: ${X} (supported versions: ${v1.join(", ")})`)),this.createJsonErrorResponse(400,-32000,`Bad Request: Unsupported protocol version: ${X} (supported versions: ${v1.join(", ")})`);return}async close(){this._streamMapping.forEach(({cleanup:Q})=>{Q()}),this._streamMapping.clear(),this._requestResponseMap.clear(),this.onclose?.()}closeSSEStream(Q){let X=this._requestToStreamMapping.get(Q);if(!X)return;let Y=this._streamMapping.get(X);if(Y)Y.cleanup()}closeStandaloneSSEStream(){let Q=this._streamMapping.get(this._standaloneSseStreamId);if(Q)Q.cleanup()}async send(Q,X){let Y=X?.relatedRequestId;if(i0(Q)||x1(Q))Y=Q.id;if(Y===void 0){if(i0(Q)||x1(Q))throw Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");let J;if(this._eventStore)J=await this._eventStore.storeEvent(this._standaloneSseStreamId,Q);let B=this._streamMapping.get(this._standaloneSseStreamId);if(B===void 0)return;if(B.controller&&B.encoder)this.writeSSEEvent(B.controller,B.encoder,Q,J);return}let W=this._requestToStreamMapping.get(Y);if(!W)throw Error(`No connection established for request ID: ${String(Y)}`);let G=this._streamMapping.get(W);if(!this._enableJsonResponse&&G?.controller&&G?.encoder){let J;if(this._eventStore)J=await this._eventStore.storeEvent(W,Q);this.writeSSEEvent(G.controller,G.encoder,Q,J)}if(i0(Q)||x1(Q)){this._requestResponseMap.set(Y,Q);let J=Array.from(this._requestToStreamMapping.entries()).filter(([H,K])=>K===W).map(([H])=>H);if(J.every((H)=>this._requestResponseMap.has(H))){if(!G)throw Error(`No connection established for request ID: ${String(Y)}`);if(this._enableJsonResponse&&G.resolveJson){let H={"Content-Type":"application/json"};if(this.sessionId!==void 0)H["mcp-session-id"]=this.sessionId;let K=J.map((z)=>this._requestResponseMap.get(z));if(K.length===1)G.resolveJson(new Response(JSON.stringify(K[0]),{status:200,headers:H}));else G.resolveJson(new Response(JSON.stringify(K),{status:200,headers:H}))}else G.cleanup();for(let H of J)this._requestResponseMap.delete(H),this._requestToStreamMapping.delete(H)}}}}function h1(Q){return!!Q._zod}function J1(Q,X){if(h1(Q))return z9(Q,X);return Q.safeParse(X)}function d8(Q){if(!Q)return;let X;if(h1(Q))X=Q._zod?.def?.shape;else X=Q.shape;if(!X)return;if(typeof X==="function")try{return X()}catch{return}return X}function tG(Q){if(h1(Q)){let J=Q._zod?.def;if(J){if(J.value!==void 0)return J.value;if(Array.isArray(J.values)&&J.values.length>0)return J.values[0]}}let Y=Q._def;if(Y){if(Y.value!==void 0)return Y.value;if(Array.isArray(Y.values)&&Y.values.length>0)return Y.values[0]}let W=Q.value;if(W!==void 0)return W;return}function B1(Q){return Q==="completed"||Q==="failed"||Q==="cancelled"}var $F=Symbol("Let zodToJsonSchema decide on which parser to use");var DT=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function sX(Q){let Y=d8(Q)?.method;if(!Y)throw Error("Schema is missing a method literal");let W=tG(Y);if(typeof W!=="string")throw Error("Schema method literal must be a string");return W}function eX(Q,X){let Y=J1(Q,X);if(!Y.success)throw Y.error;return Y.data}var jF=60000;class Q6{constructor(Q){if(this._options=Q,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this._taskProgressTokens=new Map,this._requestResolvers=new Map,this.setNotificationHandler(x8,(X)=>{this._oncancel(X)}),this.setNotificationHandler(g8,(X)=>{this._onprogress(X)}),this.setRequestHandler(y8,(X)=>({})),this._taskStore=Q?.taskStore,this._taskMessageQueue=Q?.taskMessageQueue,this._taskStore)this.setRequestHandler(h8,async(X,Y)=>{let W=await this._taskStore.getTask(X.params.taskId,Y.sessionId);if(!W)throw new T(C.InvalidParams,"Failed to retrieve task: Task not found");return{...W}}),this.setRequestHandler(u8,async(X,Y)=>{let W=async()=>{let G=X.params.taskId;if(this._taskMessageQueue){let B;while(B=await this._taskMessageQueue.dequeue(G,Y.sessionId)){if(B.type==="response"||B.type==="error"){let H=B.message,K=H.id,z=this._requestResolvers.get(K);if(z)if(this._requestResolvers.delete(K),B.type==="response")z(H);else{let A=H,Z=new T(A.error.code,A.error.message,A.error.data);z(Z)}else{let A=B.type==="response"?"Response":"Error";this._onerror(Error(`${A} handler missing for request ${K}`))}continue}await this._transport?.send(B.message,{relatedRequestId:Y.requestId})}}let J=await this._taskStore.getTask(G,Y.sessionId);if(!J)throw new T(C.InvalidParams,`Task not found: ${G}`);if(!B1(J.status))return await this._waitForTaskUpdate(G,Y.signal),await W();if(B1(J.status)){let B=await this._taskStore.getTaskResult(G,Y.sessionId);return this._clearTaskQueue(G),{...B,_meta:{...B._meta,[W1]:{taskId:G}}}}return await W()};return await W()}),this.setRequestHandler(l8,async(X,Y)=>{try{let{tasks:W,nextCursor:G}=await this._taskStore.listTasks(X.params?.cursor,Y.sessionId);return{tasks:W,nextCursor:G,_meta:{}}}catch(W){throw new T(C.InvalidParams,`Failed to list tasks: ${W instanceof Error?W.message:String(W)}`)}}),this.setRequestHandler(c8,async(X,Y)=>{try{let W=await this._taskStore.getTask(X.params.taskId,Y.sessionId);if(!W)throw new T(C.InvalidParams,`Task not found: ${X.params.taskId}`);if(B1(W.status))throw new T(C.InvalidParams,`Cannot cancel task in terminal status: ${W.status}`);await this._taskStore.updateTaskStatus(X.params.taskId,"cancelled","Client cancelled task execution.",Y.sessionId),this._clearTaskQueue(X.params.taskId);let G=await this._taskStore.getTask(X.params.taskId,Y.sessionId);if(!G)throw new T(C.InvalidParams,`Task not found after cancellation: ${X.params.taskId}`);return{_meta:{},...G}}catch(W){if(W instanceof T)throw W;throw new T(C.InvalidRequest,`Failed to cancel task: ${W instanceof Error?W.message:String(W)}`)}})}async _oncancel(Q){if(!Q.params.requestId)return;this._requestHandlerAbortControllers.get(Q.params.requestId)?.abort(Q.params.reason)}_setupTimeout(Q,X,Y,W,G=!1){this._timeoutInfo.set(Q,{timeoutId:setTimeout(W,X),startTime:Date.now(),timeout:X,maxTotalTimeout:Y,resetTimeoutOnProgress:G,onTimeout:W})}_resetTimeout(Q){let X=this._timeoutInfo.get(Q);if(!X)return!1;let Y=Date.now()-X.startTime;if(X.maxTotalTimeout&&Y>=X.maxTotalTimeout)throw this._timeoutInfo.delete(Q),T.fromError(C.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:X.maxTotalTimeout,totalElapsed:Y});return clearTimeout(X.timeoutId),X.timeoutId=setTimeout(X.onTimeout,X.timeout),!0}_cleanupTimeout(Q){let X=this._timeoutInfo.get(Q);if(X)clearTimeout(X.timeoutId),this._timeoutInfo.delete(Q)}async connect(Q){if(this._transport)throw Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");this._transport=Q;let X=this.transport?.onclose;this._transport.onclose=()=>{X?.(),this._onclose()};let Y=this.transport?.onerror;this._transport.onerror=(G)=>{Y?.(G),this._onerror(G)};let W=this._transport?.onmessage;this._transport.onmessage=(G,J)=>{if(W?.(G,J),i0(G)||x1(G))this._onresponse(G);else if(G1(G))this._onrequest(G,J);else if(lG(G))this._onnotification(G);else this._onerror(Error(`Unknown message type: ${JSON.stringify(G)}`))},await this._transport.start()}_onclose(){let Q=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._taskProgressTokens.clear(),this._pendingDebouncedNotifications.clear();for(let Y of this._timeoutInfo.values())clearTimeout(Y.timeoutId);this._timeoutInfo.clear();for(let Y of this._requestHandlerAbortControllers.values())Y.abort();this._requestHandlerAbortControllers.clear();let X=T.fromError(C.ConnectionClosed,"Connection closed");this._transport=void 0,this.onclose?.();for(let Y of Q.values())Y(X)}_onerror(Q){this.onerror?.(Q)}_onnotification(Q){let X=this._notificationHandlers.get(Q.method)??this.fallbackNotificationHandler;if(X===void 0)return;Promise.resolve().then(()=>X(Q)).catch((Y)=>this._onerror(Error(`Uncaught error in notification handler: ${Y}`)))}_onrequest(Q,X){let Y=this._requestHandlers.get(Q.method)??this.fallbackRequestHandler,W=this._transport,G=Q.params?._meta?.[W1]?.taskId;if(Y===void 0){let z={jsonrpc:"2.0",id:Q.id,error:{code:C.MethodNotFound,message:"Method not found"}};if(G&&this._taskMessageQueue)this._enqueueTaskMessage(G,{type:"error",message:z,timestamp:Date.now()},W?.sessionId).catch((A)=>this._onerror(Error(`Failed to enqueue error response: ${A}`)));else W?.send(z).catch((A)=>this._onerror(Error(`Failed to send an error response: ${A}`)));return}let J=new AbortController;this._requestHandlerAbortControllers.set(Q.id,J);let B=hG(Q.params)?Q.params.task:void 0,H=this._taskStore?this.requestTaskStore(Q,W?.sessionId):void 0,K={signal:J.signal,sessionId:W?.sessionId,_meta:Q.params?._meta,sendNotification:async(z)=>{if(J.signal.aborted)return;let A={relatedRequestId:Q.id};if(G)A.relatedTask={taskId:G};await this.notification(z,A)},sendRequest:async(z,A,Z)=>{if(J.signal.aborted)throw new T(C.ConnectionClosed,"Request was cancelled");let D={...Z,relatedRequestId:Q.id};if(G&&!D.relatedTask)D.relatedTask={taskId:G};let F=D.relatedTask?.taskId??G;if(F&&H)await H.updateTaskStatus(F,"input_required");return await this.request(z,A,D)},authInfo:X?.authInfo,requestId:Q.id,requestInfo:X?.requestInfo,taskId:G,taskStore:H,taskRequestedTtl:B?.ttl,closeSSEStream:X?.closeSSEStream,closeStandaloneSSEStream:X?.closeStandaloneSSEStream};Promise.resolve().then(()=>{if(B)this.assertTaskHandlerCapability(Q.method)}).then(()=>Y(Q,K)).then(async(z)=>{if(J.signal.aborted)return;let A={result:z,jsonrpc:"2.0",id:Q.id};if(G&&this._taskMessageQueue)await this._enqueueTaskMessage(G,{type:"response",message:A,timestamp:Date.now()},W?.sessionId);else await W?.send(A)},async(z)=>{if(J.signal.aborted)return;let A={jsonrpc:"2.0",id:Q.id,error:{code:Number.isSafeInteger(z.code)?z.code:C.InternalError,message:z.message??"Internal error",...z.data!==void 0&&{data:z.data}}};if(G&&this._taskMessageQueue)await this._enqueueTaskMessage(G,{type:"error",message:A,timestamp:Date.now()},W?.sessionId);else await W?.send(A)}).catch((z)=>this._onerror(Error(`Failed to send response: ${z}`))).finally(()=>{if(this._requestHandlerAbortControllers.get(Q.id)===J)this._requestHandlerAbortControllers.delete(Q.id)})}_onprogress(Q){let{progressToken:X,...Y}=Q.params,W=Number(X),G=this._progressHandlers.get(W);if(!G){this._onerror(Error(`Received a progress notification for an unknown token: ${JSON.stringify(Q)}`));return}let J=this._responseHandlers.get(W),B=this._timeoutInfo.get(W);if(B&&J&&B.resetTimeoutOnProgress)try{this._resetTimeout(W)}catch(H){this._responseHandlers.delete(W),this._progressHandlers.delete(W),this._cleanupTimeout(W),J(H);return}G(Y)}_onresponse(Q){let X=Number(Q.id),Y=this._requestResolvers.get(X);if(Y){if(this._requestResolvers.delete(X),i0(Q))Y(Q);else{let J=new T(Q.error.code,Q.error.message,Q.error.data);Y(J)}return}let W=this._responseHandlers.get(X);if(W===void 0){this._onerror(Error(`Received a response for an unknown message ID: ${JSON.stringify(Q)}`));return}this._responseHandlers.delete(X),this._cleanupTimeout(X);let G=!1;if(i0(Q)&&Q.result&&typeof Q.result==="object"){let J=Q.result;if(J.task&&typeof J.task==="object"){let B=J.task;if(typeof B.taskId==="string")G=!0,this._taskProgressTokens.set(B.taskId,X)}}if(!G)this._progressHandlers.delete(X);if(i0(Q))W(Q);else{let J=T.fromError(Q.error.code,Q.error.message,Q.error.data);W(J)}}get transport(){return this._transport}async close(){await this._transport?.close()}async*requestStream(Q,X,Y){let{task:W}=Y??{};if(!W){try{yield{type:"result",result:await this.request(Q,X,Y)}}catch(J){yield{type:"error",error:J instanceof T?J:new T(C.InternalError,String(J))}}return}let G;try{let J=await this.request(Q,_1,Y);if(J.task)G=J.task.taskId,yield{type:"taskCreated",task:J.task};else throw new T(C.InternalError,"Task creation did not return a task");while(!0){let B=await this.getTask({taskId:G},Y);if(yield{type:"taskStatus",task:B},B1(B.status)){if(B.status==="completed")yield{type:"result",result:await this.getTaskResult({taskId:G},X,Y)};else if(B.status==="failed")yield{type:"error",error:new T(C.InternalError,`Task ${G} failed`)};else if(B.status==="cancelled")yield{type:"error",error:new T(C.InternalError,`Task ${G} was cancelled`)};return}if(B.status==="input_required"){yield{type:"result",result:await this.getTaskResult({taskId:G},X,Y)};return}let H=B.pollInterval??this._options?.defaultTaskPollInterval??1000;await new Promise((K)=>setTimeout(K,H)),Y?.signal?.throwIfAborted()}}catch(J){yield{type:"error",error:J instanceof T?J:new T(C.InternalError,String(J))}}}request(Q,X,Y){let{relatedRequestId:W,resumptionToken:G,onresumptiontoken:J,task:B,relatedTask:H}=Y??{};return new Promise((K,z)=>{let A=(q)=>{z(q)};if(!this._transport){A(Error("Not connected"));return}if(this._options?.enforceStrictCapabilities===!0)try{if(this.assertCapabilityForMethod(Q.method),B)this.assertTaskCapability(Q.method)}catch(q){A(q);return}Y?.signal?.throwIfAborted();let Z=this._requestMessageId++,D={...Q,jsonrpc:"2.0",id:Z};if(Y?.onprogress)this._progressHandlers.set(Z,Y.onprogress),D.params={...Q.params,_meta:{...Q.params?._meta||{},progressToken:Z}};if(B)D.params={...D.params,task:B};if(H)D.params={...D.params,_meta:{...D.params?._meta||{},[W1]:H}};let F=(q)=>{this._responseHandlers.delete(Z),this._progressHandlers.delete(Z),this._cleanupTimeout(Z),this._transport?.send({jsonrpc:"2.0",method:"notifications/cancelled",params:{requestId:Z,reason:String(q)}},{relatedRequestId:W,resumptionToken:G,onresumptiontoken:J}).catch((j)=>this._onerror(Error(`Failed to send cancellation: ${j}`)));let O=q instanceof T?q:new T(C.RequestTimeout,String(q));z(O)};this._responseHandlers.set(Z,(q)=>{if(Y?.signal?.aborted)return;if(q instanceof Error)return z(q);try{let O=J1(X,q.result);if(!O.success)z(O.error);else K(O.data)}catch(O){z(O)}}),Y?.signal?.addEventListener("abort",()=>{F(Y?.signal?.reason)});let V=Y?.timeout??jF,L=()=>F(T.fromError(C.RequestTimeout,"Request timed out",{timeout:V}));this._setupTimeout(Z,V,Y?.maxTotalTimeout,L,Y?.resetTimeoutOnProgress??!1);let M=H?.taskId;if(M){let q=(O)=>{let j=this._responseHandlers.get(Z);if(j)j(O);else this._onerror(Error(`Response handler missing for side-channeled request ${Z}`))};this._requestResolvers.set(Z,q),this._enqueueTaskMessage(M,{type:"request",message:D,timestamp:Date.now()}).catch((O)=>{this._cleanupTimeout(Z),z(O)})}else this._transport.send(D,{relatedRequestId:W,resumptionToken:G,onresumptiontoken:J}).catch((q)=>{this._cleanupTimeout(Z),z(q)})})}async getTask(Q,X){return this.request({method:"tasks/get",params:Q},f8,X)}async getTaskResult(Q,X,Y){return this.request({method:"tasks/result",params:Q},X,Y)}async listTasks(Q,X){return this.request({method:"tasks/list",params:Q},m8,X)}async cancelTask(Q,X){return this.request({method:"tasks/cancel",params:Q},cG,X)}async notification(Q,X){if(!this._transport)throw Error("Not connected");this.assertNotificationCapability(Q.method);let Y=X?.relatedTask?.taskId;if(Y){let B={...Q,jsonrpc:"2.0",params:{...Q.params,_meta:{...Q.params?._meta||{},[W1]:X.relatedTask}}};await this._enqueueTaskMessage(Y,{type:"notification",message:B,timestamp:Date.now()});return}if((this._options?.debouncedNotificationMethods??[]).includes(Q.method)&&!Q.params&&!X?.relatedRequestId&&!X?.relatedTask){if(this._pendingDebouncedNotifications.has(Q.method))return;this._pendingDebouncedNotifications.add(Q.method),Promise.resolve().then(()=>{if(this._pendingDebouncedNotifications.delete(Q.method),!this._transport)return;let B={...Q,jsonrpc:"2.0"};if(X?.relatedTask)B={...B,params:{...B.params,_meta:{...B.params?._meta||{},[W1]:X.relatedTask}}};this._transport?.send(B,X).catch((H)=>this._onerror(H))});return}let J={...Q,jsonrpc:"2.0"};if(X?.relatedTask)J={...J,params:{...J.params,_meta:{...J.params?._meta||{},[W1]:X.relatedTask}}};await this._transport.send(J,X)}setRequestHandler(Q,X){let Y=sX(Q);this.assertRequestHandlerCapability(Y),this._requestHandlers.set(Y,(W,G)=>{let J=eX(Q,W);return Promise.resolve(X(J,G))})}removeRequestHandler(Q){this._requestHandlers.delete(Q)}assertCanSetRequestHandler(Q){if(this._requestHandlers.has(Q))throw Error(`A request handler for ${Q} already exists, which would be overridden`)}setNotificationHandler(Q,X){let Y=sX(Q);this._notificationHandlers.set(Y,(W)=>{let G=eX(Q,W);return Promise.resolve(X(G))})}removeNotificationHandler(Q){this._notificationHandlers.delete(Q)}_cleanupTaskProgressHandler(Q){let X=this._taskProgressTokens.get(Q);if(X!==void 0)this._progressHandlers.delete(X),this._taskProgressTokens.delete(Q)}async _enqueueTaskMessage(Q,X,Y){if(!this._taskStore||!this._taskMessageQueue)throw Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");let W=this._options?.maxTaskQueueSize;await this._taskMessageQueue.enqueue(Q,X,Y,W)}async _clearTaskQueue(Q,X){if(this._taskMessageQueue){let Y=await this._taskMessageQueue.dequeueAll(Q,X);for(let W of Y)if(W.type==="request"&&G1(W.message)){let G=W.message.id,J=this._requestResolvers.get(G);if(J)J(new T(C.InternalError,"Task cancelled or completed")),this._requestResolvers.delete(G);else this._onerror(Error(`Resolver missing for request ${G} during task ${Q} cleanup`))}}}async _waitForTaskUpdate(Q,X){let Y=this._options?.defaultTaskPollInterval??1000;try{let W=await this._taskStore?.getTask(Q);if(W?.pollInterval)Y=W.pollInterval}catch{}return new Promise((W,G)=>{if(X.aborted){G(new T(C.InvalidRequest,"Request cancelled"));return}let J=setTimeout(W,Y);X.addEventListener("abort",()=>{clearTimeout(J),G(new T(C.InvalidRequest,"Request cancelled"))},{once:!0})})}requestTaskStore(Q,X){let Y=this._taskStore;if(!Y)throw Error("No task store configured");return{createTask:async(W)=>{if(!Q)throw Error("No request provided");return await Y.createTask(W,Q.id,{method:Q.method,params:Q.params},X)},getTask:async(W)=>{let G=await Y.getTask(W,X);if(!G)throw new T(C.InvalidParams,"Failed to retrieve task: Task not found");return G},storeTaskResult:async(W,G,J)=>{await Y.storeTaskResult(W,G,J,X);let B=await Y.getTask(W,X);if(B){let H=P9.parse({method:"notifications/tasks/status",params:B});if(await this.notification(H),B1(B.status))this._cleanupTaskProgressHandler(W)}},getTaskResult:(W)=>{return Y.getTaskResult(W,X)},updateTaskStatus:async(W,G,J)=>{let B=await Y.getTask(W,X);if(!B)throw new T(C.InvalidParams,`Task "${W}" not found - it may have been cleaned up`);if(B1(B.status))throw new T(C.InvalidParams,`Cannot update task "${W}" from terminal status "${B.status}" to "${G}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);await Y.updateTaskStatus(W,G,J,X);let H=await Y.getTask(W,X);if(H){let K=P9.parse({method:"notifications/tasks/status",params:H});if(await this.notification(K),B1(H.status))this._cleanupTaskProgressHandler(W)}},listTasks:(W)=>{return Y.listTasks(W,X)}}}}function aG(Q){return Q!==null&&typeof Q==="object"&&!Array.isArray(Q)}function sG(Q,X){let Y={...Q};for(let W in X){let G=W,J=X[G];if(J===void 0)continue;let B=Y[G];if(aG(B)&&aG(J))Y[G]={...B,...J};else Y[G]=J}return Y}var xK=x4(r6(),1),_K=x4(vK(),1);function rw(){let Q=new xK.default({strict:!1,validateFormats:!0,validateSchema:!1,allErrors:!0});return _K.default(Q),Q}class J4{constructor(Q){this._ajv=Q??rw()}getValidator(Q){let X="$id"in Q&&typeof Q.$id==="string"?this._ajv.getSchema(Q.$id)??this._ajv.compile(Q):this._ajv.compile(Q);return(Y)=>{if(X(Y))return{valid:!0,data:Y,errorMessage:void 0};else return{valid:!1,data:void 0,errorMessage:this._ajv.errorsText(X.errors)}}}}class B4{constructor(Q){this._server=Q}requestStream(Q,X,Y){return this._server.requestStream(Q,X,Y)}createMessageStream(Q,X){let Y=this._server.getClientCapabilities();if((Q.tools||Q.toolChoice)&&!Y?.sampling?.tools)throw Error("Client does not support sampling tools capability.");if(Q.messages.length>0){let W=Q.messages[Q.messages.length-1],G=Array.isArray(W.content)?W.content:[W.content],J=G.some((z)=>z.type==="tool_result"),B=Q.messages.length>1?Q.messages[Q.messages.length-2]:void 0,H=B?Array.isArray(B.content)?B.content:[B.content]:[],K=H.some((z)=>z.type==="tool_use");if(J){if(G.some((z)=>z.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!K)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(K){let z=new Set(H.filter((Z)=>Z.type==="tool_use").map((Z)=>Z.id)),A=new Set(G.filter((Z)=>Z.type==="tool_result").map((Z)=>Z.toolUseId));if(z.size!==A.size||![...z].every((Z)=>A.has(Z)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}return this.requestStream({method:"sampling/createMessage",params:Q},k9,X)}elicitInputStream(Q,X){let Y=this._server.getClientCapabilities(),W=Q.mode??"form";switch(W){case"url":{if(!Y?.elicitation?.url)throw Error("Client does not support url elicitation.");break}case"form":{if(!Y?.elicitation?.form)throw Error("Client does not support form elicitation.");break}}let G=W==="form"&&Q.mode===void 0?{...Q,mode:"form"}:Q;return this.requestStream({method:"elicitation/create",params:G},g1,X)}async getTask(Q,X){return this._server.getTask({taskId:Q},X)}async getTaskResult(Q,X,Y){return this._server.getTaskResult({taskId:Q},X,Y)}async listTasks(Q,X){return this._server.listTasks(Q?{cursor:Q}:void 0,X)}async cancelTask(Q,X){return this._server.cancelTask({taskId:Q},X)}}function yK(Q,X,Y){if(!Q)throw Error(`${Y} does not support task creation (required for ${X})`);switch(X){case"tools/call":if(!Q.tools?.call)throw Error(`${Y} does not support task creation for tools/call (required for ${X})`);break;default:break}}function gK(Q,X,Y){if(!Q)throw Error(`${Y} does not support task creation (required for ${X})`);switch(X){case"sampling/createMessage":if(!Q.sampling?.createMessage)throw Error(`${Y} does not support task creation for sampling/createMessage (required for ${X})`);break;case"elicitation/create":if(!Q.elicitation?.create)throw Error(`${Y} does not support task creation for elicitation/create (required for ${X})`);break;default:break}}class W8 extends Q6{constructor(Q,X){super(X);if(this._serverInfo=Q,this._loggingLevels=new Map,this.LOG_LEVEL_SEVERITY=new Map(b9.options.map((Y,W)=>[Y,W])),this.isMessageIgnored=(Y,W)=>{let G=this._loggingLevels.get(W);return G?this.LOG_LEVEL_SEVERITY.get(Y)<this.LOG_LEVEL_SEVERITY.get(G):!1},this._capabilities=X?.capabilities??{},this._instructions=X?.instructions,this._jsonSchemaValidator=X?.jsonSchemaValidator??new J4,this.setRequestHandler(_8,(Y)=>this._oninitialize(Y)),this.setNotificationHandler(lX,()=>this.oninitialized?.()),this._capabilities.logging)this.setRequestHandler(oX,async(Y,W)=>{let G=W.sessionId||W.requestInfo?.headers["mcp-session-id"]||void 0,{level:J}=Y.params,B=b9.safeParse(J);if(B.success)this._loggingLevels.set(G,B.data);return{}})}get experimental(){if(!this._experimental)this._experimental={tasks:new B4(this)};return this._experimental}registerCapabilities(Q){if(this.transport)throw Error("Cannot register capabilities after connecting to transport");this._capabilities=sG(this._capabilities,Q)}setRequestHandler(Q,X){let W=d8(Q)?.method;if(!W)throw Error("Schema is missing a method literal");let G;if(h1(W)){let B=W;G=B._zod?.def?.value??B.value}else{let B=W;G=B._def?.value??B.value}if(typeof G!=="string")throw Error("Schema method literal must be a string");if(G==="tools/call"){let B=async(H,K)=>{let z=J1(q1,H);if(!z.success){let F=z.error instanceof Error?z.error.message:String(z.error);throw new T(C.InvalidParams,`Invalid tools/call request: ${F}`)}let{params:A}=z.data,Z=await Promise.resolve(X(H,K));if(A.task){let F=J1(_1,Z);if(!F.success){let V=F.error instanceof Error?F.error.message:String(F.error);throw new T(C.InvalidParams,`Invalid task creation result: ${V}`)}return F.data}let D=J1(p8,Z);if(!D.success){let F=D.error instanceof Error?D.error.message:String(D.error);throw new T(C.InvalidParams,`Invalid tools/call result: ${F}`)}return D.data};return super.setRequestHandler(Q,B)}return super.setRequestHandler(Q,X)}assertCapabilityForMethod(Q){switch(Q){case"sampling/createMessage":if(!this._clientCapabilities?.sampling)throw Error(`Client does not support sampling (required for ${Q})`);break;case"elicitation/create":if(!this._clientCapabilities?.elicitation)throw Error(`Client does not support elicitation (required for ${Q})`);break;case"roots/list":if(!this._clientCapabilities?.roots)throw Error(`Client does not support listing roots (required for ${Q})`);break;case"ping":break}}assertNotificationCapability(Q){switch(Q){case"notifications/message":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${Q})`);break;case"notifications/resources/updated":case"notifications/resources/list_changed":if(!this._capabilities.resources)throw Error(`Server does not support notifying about resources (required for ${Q})`);break;case"notifications/tools/list_changed":if(!this._capabilities.tools)throw Error(`Server does not support notifying of tool list changes (required for ${Q})`);break;case"notifications/prompts/list_changed":if(!this._capabilities.prompts)throw Error(`Server does not support notifying of prompt list changes (required for ${Q})`);break;case"notifications/elicitation/complete":if(!this._clientCapabilities?.elicitation?.url)throw Error(`Client does not support URL elicitation (required for ${Q})`);break;case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability(Q){if(!this._capabilities)return;switch(Q){case"completion/complete":if(!this._capabilities.completions)throw Error(`Server does not support completions (required for ${Q})`);break;case"logging/setLevel":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${Q})`);break;case"prompts/get":case"prompts/list":if(!this._capabilities.prompts)throw Error(`Server does not support prompts (required for ${Q})`);break;case"resources/list":case"resources/templates/list":case"resources/read":if(!this._capabilities.resources)throw Error(`Server does not support resources (required for ${Q})`);break;case"tools/call":case"tools/list":if(!this._capabilities.tools)throw Error(`Server does not support tools (required for ${Q})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw Error(`Server does not support tasks capability (required for ${Q})`);break;case"ping":case"initialize":break}}assertTaskCapability(Q){gK(this._clientCapabilities?.tasks?.requests,Q,"Client")}assertTaskHandlerCapability(Q){if(!this._capabilities)return;yK(this._capabilities.tasks?.requests,Q,"Server")}async _oninitialize(Q){let X=Q.params.protocolVersion;return this._clientCapabilities=Q.params.capabilities,this._clientVersion=Q.params.clientInfo,{protocolVersion:v1.includes(X)?X:yX,capabilities:this.getCapabilities(),serverInfo:this._serverInfo,...this._instructions&&{instructions:this._instructions}}}getClientCapabilities(){return this._clientCapabilities}getClientVersion(){return this._clientVersion}getCapabilities(){return this._capabilities}async ping(){return this.request({method:"ping"},v8)}async createMessage(Q,X){if(Q.tools||Q.toolChoice){if(!this._clientCapabilities?.sampling?.tools)throw Error("Client does not support sampling tools capability.")}if(Q.messages.length>0){let Y=Q.messages[Q.messages.length-1],W=Array.isArray(Y.content)?Y.content:[Y.content],G=W.some((K)=>K.type==="tool_result"),J=Q.messages.length>1?Q.messages[Q.messages.length-2]:void 0,B=J?Array.isArray(J.content)?J.content:[J.content]:[],H=B.some((K)=>K.type==="tool_use");if(G){if(W.some((K)=>K.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!H)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(H){let K=new Set(B.filter((A)=>A.type==="tool_use").map((A)=>A.id)),z=new Set(W.filter((A)=>A.type==="tool_result").map((A)=>A.toolUseId));if(K.size!==z.size||![...K].every((A)=>z.has(A)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}if(Q.tools)return this.request({method:"sampling/createMessage",params:Q},rX,X);return this.request({method:"sampling/createMessage",params:Q},k9,X)}async elicitInput(Q,X){switch(Q.mode??"form"){case"url":{if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support url elicitation.");let W=Q;return this.request({method:"elicitation/create",params:W},g1,X)}case"form":{if(!this._clientCapabilities?.elicitation?.form)throw Error("Client does not support form elicitation.");let W=Q.mode==="form"?Q:{...Q,mode:"form"},G=await this.request({method:"elicitation/create",params:W},g1,X);if(G.action==="accept"&&G.content&&W.requestedSchema)try{let B=this._jsonSchemaValidator.getValidator(W.requestedSchema)(G.content);if(!B.valid)throw new T(C.InvalidParams,`Elicitation response content does not match requested schema: ${B.errorMessage}`)}catch(J){if(J instanceof T)throw J;throw new T(C.InternalError,`Error validating elicitation response: ${J instanceof Error?J.message:String(J)}`)}return G}}}createElicitationCompletionNotifier(Q,X){if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");return()=>this.notification({method:"notifications/elicitation/complete",params:{elicitationId:Q}},X)}async listRoots(Q,X){return this.request({method:"roots/list",params:Q},tX,X)}async sendLoggingMessage(Q,X){if(this._capabilities.logging){if(!this.isMessageIgnored(Q.level,X))return this.notification({method:"notifications/message",params:Q})}}async sendResourceUpdated(Q){return this.notification({method:"notifications/resources/updated",params:Q})}async sendResourceListChanged(){return this.notification({method:"notifications/resources/list_changed"})}async sendToolListChanged(){return this.notification({method:"notifications/tools/list_changed"})}async sendPromptListChanged(){return this.notification({method:"notifications/prompts/list_changed"})}}function H4(){return[{name:"getting_started",description:"Brief the LLM on what the Aether Wealth MCP exposes and the sign-in-first flow.",handler:()=>[{role:"user",content:{type:"text",text:["You are connected to the Aether Wealth MCP, which reads the user's trading journal over an authenticated connection.","","Auth tools:"," • login — sign in. Opens the browser; the user authenticates and approves access. Call this first if a data tool reports the user is not signed in."," • logout — sign out on this device.","","Data tools:"," • list_trades — list the user's trades, filtered by account, status, pair, or date range.","","Recommended flow:"," 1. Try the data tool the user asked for (e.g. list_trades).",' 2. If it reports "not signed in", call login, wait for the user to finish in the browser, then retry.',"","More read and write tools are being added; for now the journal is read-only over this connection."].join(`
|
|
85
|
-
`)}}]}]}function K4(){return[]}function l(Q){return Q}var tw='Not signed in to Aether Wealth. Call the "login" tool to authenticate, then retry.';async function r(Q){if(!await Q.session.getAccessToken())throw Error(tw)}var hK={type:"integer",minimum:1,maximum:200,description:"Max rows to return"},fK={type:"integer",minimum:1,description:"Page number (1-indexed)"};function SQ(Q,X){if(X===null||X===void 0){if(Q.required&&Q.required.length>0)return{ok:!1,reason:`missing required: ${Q.required.join(", ")}`};return{ok:!0,args:{}}}if(typeof X!=="object"||Array.isArray(X))return{ok:!1,reason:"args must be an object"};let Y=X,W=aw(Q,Y)??sw(Q,Y);return W?{ok:!1,reason:W}:{ok:!0,args:Y}}function aw(Q,X){for(let Y of Q.required??[])if(!(Y in X)||X[Y]===void 0||X[Y]===null)return`missing required: ${Y}`;return null}function sw(Q,X){if(Q.additionalProperties!==!1)return null;for(let Y of Object.keys(X))if(!(Y in Q.properties))return`unknown property: ${Y}`;return null}function z4(Q){return{triggerType:Q.triggerType??"close",isPersistent:Q.isPersistent??!1,notifyEmail:Q.notifyEmail??!0,notifyPush:Q.notifyPush??!0,...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}function uK(Q){return{...Q.includeArchived===void 0?{}:{includeArchived:Q.includeArchived},...Q.pair===void 0?{}:{pair:Q.pair}}}function ew(Q){return{id:Q.id,...Q.price===void 0?{}:{price:Q.price},...Q.price1===void 0?{}:{price1:Q.price1},...Q.price2===void 0?{}:{price2:Q.price2},...Q.time1===void 0?{}:{time1:Q.time1},...Q.time2===void 0?{}:{time2:Q.time2},...Q.condition===void 0?{}:{condition:Q.condition},...Q.triggerType===void 0?{}:{triggerType:Q.triggerType},...Q.timeframe===void 0?{}:{timeframe:Q.timeframe},...Q.isActive===void 0?{}:{isActive:Q.isActive},...Q.isArchived===void 0?{}:{isArchived:Q.isArchived},...Q.isPersistent===void 0?{}:{isPersistent:Q.isPersistent},...Q.notifyEmail===void 0?{}:{notifyEmail:Q.notifyEmail},...Q.notifyPush===void 0?{}:{notifyPush:Q.notifyPush},...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}function Q$(Q){return{id:Q.id,...Q.condition===void 0?{}:{condition:Q.condition},...Q.dedupMode===void 0?{}:{dedupMode:Q.dedupMode},...Q.triggerType===void 0?{}:{triggerType:Q.triggerType},...Q.isActive===void 0?{}:{isActive:Q.isActive},...Q.isArchived===void 0?{}:{isArchived:Q.isArchived},...Q.isPersistent===void 0?{}:{isPersistent:Q.isPersistent},...Q.notifyEmail===void 0?{}:{notifyEmail:Q.notifyEmail},...Q.notifyPush===void 0?{}:{notifyPush:Q.notifyPush},...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}var A4={type:"string",enum:["above","below","crosses"]},G8={triggerType:{type:"string",enum:["close","wick"],description:"default: close"},isPersistent:{type:"boolean",description:"Re-arm after firing. default: false"},notifyEmail:{type:"boolean",description:"default: true"},notifyPush:{type:"boolean",description:"default: true"},message:{type:"string"},expiresAt:{type:"string",description:"ISO 8601 datetime"}},lK=[l({name:"list_alerts",description:"List your price + trendline alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.list.query(uK(Q))}}),l({name:"create_price_alert",description:"Create a price-level alert (fires when price is above/below/crosses a level). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},price:{type:"number"},condition:A4,...G8},required:["pair","timeframe","price","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,price:Q.price,condition:Q.condition,...z4(Q)};return X.trpc.alerts.createPrice.mutate(Y)}}),l({name:"create_trendline_alert",description:"Create a trendline alert (fires when price crosses a line defined by two points). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},price1:{type:"number"},time1:{type:"string",description:"ISO 8601 datetime of point 1"},price2:{type:"number"},time2:{type:"string",description:"ISO 8601 datetime of point 2"},condition:A4,...G8},required:["pair","timeframe","price1","time1","price2","time2","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,price1:Q.price1,time1:Q.time1,price2:Q.price2,time2:Q.time2,condition:Q.condition,...z4(Q)};return X.trpc.alerts.createTrendline.mutate(Y)}}),l({name:"update_alert",description:"Update a price/trendline alert (e.g. change level, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},price:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"string"},time2:{type:"string"},condition:A4,timeframe:{type:"string"},isActive:{type:"boolean"},isArchived:{type:"boolean"},...G8},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.update.mutate(ew(Q))}}),l({name:"delete_alert",description:"Delete a price/trendline alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.delete.mutate({id:Q.id})}}),l({name:"list_indicator_alerts",description:"List your indicator-based alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y=uK(Q);return X.trpc.alerts.indicator.list.query(Y)}}),l({name:"create_indicator_alert",description:"Create an indicator alert (fires on an indicator output condition, e.g. RSI crosses 70). `condition` is { op, threshold } or { op, other }. Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},indicatorType:{type:"string",description:"e.g. rsi, ema, macd"},indicatorParams:{type:"object",description:"Indicator settings, e.g. { length: 14 }"},outputSeries:{type:"string",description:"Which output series to watch"},condition:{type:"object",description:"{ op: gt|gte|lt|lte|eq|crosses_above|crosses_below, threshold } or { op: *_series, other }"},dedupMode:{type:"string",enum:["edge","continuous"],description:"default: edge"},...G8},required:["pair","timeframe","indicatorType","indicatorParams","outputSeries","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,indicatorType:Q.indicatorType,indicatorParams:Q.indicatorParams,outputSeries:Q.outputSeries,condition:Q.condition,dedupMode:Q.dedupMode??"edge",...z4(Q)};return X.trpc.alerts.indicator.create.mutate(Y)}}),l({name:"update_indicator_alert",description:"Update an indicator alert (condition, dedup, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},condition:{type:"object"},dedupMode:{type:"string",enum:["edge","continuous"]},isActive:{type:"boolean"},isArchived:{type:"boolean"},...G8},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.indicator.update.mutate(Q$(Q))}}),l({name:"delete_indicator_alert",description:"Delete an indicator alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.indicator.delete.mutate({id:Q.id})}})];var mK=[l({name:"login",description:"Sign in to Aether Wealth. Opens your browser to authenticate; once you approve, the MCP stores a per-user token and the data tools become available.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await X.session.login(),{status:"signed_in",message:"Signed in to Aether Wealth."}}}),l({name:"logout",description:"Sign out of Aether Wealth on this device. Clears the stored access token.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await X.session.logout(),{status:"signed_out",message:"Signed out on this device."}}})];var X$="momentum: rsi, macd, stoch, stochf, stochrsi, cci, cmo, mom, roc, rocr, willr, mfi, ultosc, ppo, apo, bop, aroon, aroonosc; trend: adx, adxr, dx, plus_di, minus_di, plus_dm, minus_dm, sar, supertrend; moving averages: sma, ema, wma, dema, tema, trima, kama, t3ma, mama, vwap, midpoint, midprice; bands: bbands, keltner, percent_b; volatility: atr, natr, trange; volume: obv, ad, adosc; stats: linearreg, linearregslope, linearregangle, linearregintercept, stddev, var, tsf";function Y$(Q){return{pair:Q.pair,interval:Q.interval,indicators:Q.indicators.map((X)=>({name:X.name,...X.params===void 0?{}:{params:X.params}})),...Q.outputsize===void 0?{}:{outputsize:Q.outputsize}}}var cK=[l({name:"get_indicators",description:"Compute Twelve Data technical indicators for a pair + timeframe (requires sign-in). "+`Pass up to 8 indicators by name; params are optional and default sensibly. Names — ${X$}. Bad names/params return an error listing valid options. At most 2 distinct pairs per user at a time.`,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical id, e.g. EURUSD, XAUUSD, BTCUSD (case-insensitive)"},interval:{type:"string",description:"One of 1m, 5m, 15m, 30m, 45m, 1h, 2h, 4h, 1d"},indicators:{type:"array",minItems:1,maxItems:8,description:"Up to 8 indicators to compute on the pair",items:{type:"object",properties:{name:{type:"string",description:"Indicator name, e.g. rsi, macd, ema, bbands, atr, adx"},params:{type:"object",description:'Optional params, e.g. {"time_period": 14} or MACD {"fast_period":12,"slow_period":26}. Defaults applied when omitted.'}},required:["name"],additionalProperties:!1}},outputsize:{type:"integer",minimum:1,maximum:500,description:"Bars to return per indicator (default 30)"}},required:["pair","interval","indicators"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.technicalIndicators.get.query(Y$(Q))}})];function W$(Q){return{...Q.currency===void 0?{}:{currency:Q.currency},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.indicator===void 0?{}:{indicator:Q.indicator},...Q.impactMin===void 0?{}:{impactMin:Q.impactMin},...Q.view===void 0?{}:{view:Q.view}}}function G$(Q){return{currency:Q.currency,indicator:Q.indicator,...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.limit===void 0?{}:{limit:Q.limit}}}var pK=[l({name:"get_candles",description:"Get the most recent OHLC candles (up to 500) for a pair + timeframe. Timeframe may be a base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or any integer multiple of one (e.g. 2h, 3h, 12h, 90m), aggregated server-side; invalid or unsupported timeframes return an error, not an empty list.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD (canonical id; case-insensitive)"},timeframe:{type:"string",description:"A base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or an integer multiple of one (e.g. 2h, 3h, 12h, 90m). No fractional (2.5h) or sub-minute values."}},required:["pair","timeframe"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe};return X.trpc.marketData.candles.query(Y)}}),l({name:"list_economic_calendar",description:'List economic calendar events. Filter by currency, date range, release, or minimum impact (1-5). Currency and indicator/release are validated against the catalog: unknown values return an error listing valid options, so an empty result always means "no events" rather than "bad input".',inputSchema:{type:"object",properties:{currency:{type:"array",items:{type:"string"},description:'ISO currency codes, e.g. ["USD","EUR"]'},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},indicator:{type:"string",description:"release slug, e.g. cpi"},impactMin:{type:"integer",minimum:1,maximum:5},view:{type:"string",enum:["minimal","rich"]}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.listCalendar.query(W$(Q))}}),l({name:"get_macro_series",description:"Get a macro indicator time series (e.g. USD cpi). Currency and indicator are validated against the catalog: unknown values return an error listing valid options (case-insensitive).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"release slug, e.g. cpi"},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},limit:{type:"integer",minimum:1,maximum:1000}},required:["currency","indicator"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.listIndicatorSeries.query(G$(Q))}}),l({name:"get_market_config",description:"Get the catalog of supported instruments + timeframes (useful before calling other tools).",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.getConfig.query()}})];function J$(Q){return{...Q.accountId===void 0?{}:{accountId:Q.accountId},...Q.status===void 0||Q.status==="ALL"?{}:{status:Q.status},...Q.pair===void 0?{}:{pair:Q.pair},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.page===void 0?{}:{page:Q.page},...Q.limit===void 0?{}:{limit:Q.limit}}}function iK(Q){return{...Q.stopLoss===void 0?{}:{stopLoss:Q.stopLoss},...Q.takeProfit===void 0?{}:{takeProfit:Q.takeProfit},...Q.lotSize===void 0?{}:{lotSize:Q.lotSize},...Q.notes===void 0?{}:{notes:Q.notes},...Q.timeframe===void 0?{}:{timeframe:Q.timeframe},...Q.riskPercent===void 0?{}:{riskPercent:Q.riskPercent},...Q.tags===void 0?{}:{tags:Q.tags}}}function B$(Q){return{accountId:Q.accountId,pair:Q.pair,direction:Q.direction,entryPrice:Q.entryPrice,entryTime:Q.entryTime,...iK(Q)}}function H$(Q){return{id:Q.id,...Q.pair===void 0?{}:{pair:Q.pair},...Q.direction===void 0?{}:{direction:Q.direction},...Q.entryPrice===void 0?{}:{entryPrice:Q.entryPrice},...Q.entryTime===void 0?{}:{entryTime:Q.entryTime},...iK(Q)}}function K$(Q){return{id:Q.id,exitPrice:Q.exitPrice,exitTime:Q.exitTime,...Q.fees===void 0?{}:{fees:Q.fees},...Q.swap===void 0?{}:{swap:Q.swap},...Q.notes===void 0?{}:{notes:Q.notes}}}function z$(Q){return{...Q.accountId===void 0?{}:{accountId:Q.accountId},...Q.pair===void 0?{}:{pair:Q.pair},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to}}}var dK={stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},riskPercent:{type:"number"},tags:{type:"array",items:{type:"string"}}},nK=[l({name:"list_trades",description:"List the authenticated user's trades. Filter by account, status, pair, or date range (ISO 8601). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},from:{type:"string",description:"ISO 8601 datetime (inclusive lower bound)"},to:{type:"string",description:"ISO 8601 datetime (inclusive upper bound)"},page:fK,limit:hK},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.list.query(J$(Q))}}),l({name:"get_trade",description:"Get a single trade by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.get.query({id:Q.id})}}),l({name:"list_accounts",description:"List the user's trading accounts (use an account's id when creating a trade). Requires sign-in.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.accounts.list.query()}}),l({name:"trade_stats",description:"Trading performance statistics (win rate, PnL, etc.). Filter by account, pair, or date range. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},pair:{type:"string"},from:{type:"string",description:"ISO 8601 datetime"},to:{type:"string",description:"ISO 8601 datetime"}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.analytics.stats.query(z$(Q))}}),l({name:"create_trade",description:"Record a new trade. Requires sign-in. Use list_accounts to find the accountId.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id (see list_accounts)"},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...dK},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.create.mutate(B$(Q))}}),l({name:"update_trade",description:"Update fields on an existing trade. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},pair:{type:"string"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...dK},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.update.mutate(H$(Q))}}),l({name:"close_trade",description:"Close an open trade with an exit price + time. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},exitPrice:{type:"number"},exitTime:{type:"string",description:"ISO 8601 datetime"},fees:{type:"number"},swap:{type:"number"},notes:{type:"string"}},required:["id","exitPrice","exitTime"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.close.mutate(K$(Q))}})];function Z4(){return[...mK,...nK,...lK,...pK,...cK]}var A$="aether-wealth-mcp",Z$="0.1.18-beta.4";function oK(Q){let X=new W8({name:A$,version:Z$},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return F$(X,Q),X}function F$(Q,X){let Y=!1,W=(G)=>{let J=X.clientGate?.nudge;if(J&&!Y)return Y=!0,`${J}
|
|
85
|
+
`)}}]}]}function K4(){return[]}function l(Q){return Q}var tw='Not signed in to Aether Wealth. Call the "login" tool to authenticate, then retry.';async function r(Q){if(!await Q.session.getAccessToken())throw Error(tw)}var hK={type:"integer",minimum:1,maximum:200,description:"Max rows to return"},fK={type:"integer",minimum:1,description:"Page number (1-indexed)"};function SQ(Q,X){if(X===null||X===void 0){if(Q.required&&Q.required.length>0)return{ok:!1,reason:`missing required: ${Q.required.join(", ")}`};return{ok:!0,args:{}}}if(typeof X!=="object"||Array.isArray(X))return{ok:!1,reason:"args must be an object"};let Y=X,W=aw(Q,Y)??sw(Q,Y);return W?{ok:!1,reason:W}:{ok:!0,args:Y}}function aw(Q,X){for(let Y of Q.required??[])if(!(Y in X)||X[Y]===void 0||X[Y]===null)return`missing required: ${Y}`;return null}function sw(Q,X){if(Q.additionalProperties!==!1)return null;for(let Y of Object.keys(X))if(!(Y in Q.properties))return`unknown property: ${Y}`;return null}function z4(Q){return{triggerType:Q.triggerType??"close",isPersistent:Q.isPersistent??!1,notifyEmail:Q.notifyEmail??!0,notifyPush:Q.notifyPush??!0,...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}function uK(Q){return{...Q.includeArchived===void 0?{}:{includeArchived:Q.includeArchived},...Q.pair===void 0?{}:{pair:Q.pair}}}function ew(Q){return{id:Q.id,...Q.price===void 0?{}:{price:Q.price},...Q.price1===void 0?{}:{price1:Q.price1},...Q.price2===void 0?{}:{price2:Q.price2},...Q.time1===void 0?{}:{time1:Q.time1},...Q.time2===void 0?{}:{time2:Q.time2},...Q.condition===void 0?{}:{condition:Q.condition},...Q.triggerType===void 0?{}:{triggerType:Q.triggerType},...Q.timeframe===void 0?{}:{timeframe:Q.timeframe},...Q.isActive===void 0?{}:{isActive:Q.isActive},...Q.isArchived===void 0?{}:{isArchived:Q.isArchived},...Q.isPersistent===void 0?{}:{isPersistent:Q.isPersistent},...Q.notifyEmail===void 0?{}:{notifyEmail:Q.notifyEmail},...Q.notifyPush===void 0?{}:{notifyPush:Q.notifyPush},...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}function Q$(Q){return{id:Q.id,...Q.condition===void 0?{}:{condition:Q.condition},...Q.dedupMode===void 0?{}:{dedupMode:Q.dedupMode},...Q.triggerType===void 0?{}:{triggerType:Q.triggerType},...Q.isActive===void 0?{}:{isActive:Q.isActive},...Q.isArchived===void 0?{}:{isArchived:Q.isArchived},...Q.isPersistent===void 0?{}:{isPersistent:Q.isPersistent},...Q.notifyEmail===void 0?{}:{notifyEmail:Q.notifyEmail},...Q.notifyPush===void 0?{}:{notifyPush:Q.notifyPush},...Q.message===void 0?{}:{message:Q.message},...Q.expiresAt===void 0?{}:{expiresAt:Q.expiresAt}}}var A4={type:"string",enum:["above","below","crosses"]},G8={triggerType:{type:"string",enum:["close","wick"],description:"default: close"},isPersistent:{type:"boolean",description:"Re-arm after firing. default: false"},notifyEmail:{type:"boolean",description:"default: true"},notifyPush:{type:"boolean",description:"default: true"},message:{type:"string"},expiresAt:{type:"string",description:"ISO 8601 datetime"}},lK=[l({name:"list_alerts",description:"List your price + trendline alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.list.query(uK(Q))}}),l({name:"create_price_alert",description:"Create a price-level alert (fires when price is above/below/crosses a level). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},price:{type:"number"},condition:A4,...G8},required:["pair","timeframe","price","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,price:Q.price,condition:Q.condition,...z4(Q)};return X.trpc.alerts.createPrice.mutate(Y)}}),l({name:"create_trendline_alert",description:"Create a trendline alert (fires when price crosses a line defined by two points). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},price1:{type:"number"},time1:{type:"string",description:"ISO 8601 datetime of point 1"},price2:{type:"number"},time2:{type:"string",description:"ISO 8601 datetime of point 2"},condition:A4,...G8},required:["pair","timeframe","price1","time1","price2","time2","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,price1:Q.price1,time1:Q.time1,price2:Q.price2,time2:Q.time2,condition:Q.condition,...z4(Q)};return X.trpc.alerts.createTrendline.mutate(Y)}}),l({name:"update_alert",description:"Update a price/trendline alert (e.g. change level, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},price:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"string"},time2:{type:"string"},condition:A4,timeframe:{type:"string"},isActive:{type:"boolean"},isArchived:{type:"boolean"},...G8},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.update.mutate(ew(Q))}}),l({name:"delete_alert",description:"Delete a price/trendline alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.delete.mutate({id:Q.id})}}),l({name:"list_indicator_alerts",description:"List your indicator-based alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y=uK(Q);return X.trpc.alerts.indicator.list.query(Y)}}),l({name:"create_indicator_alert",description:"Create an indicator alert (fires on an indicator output condition, e.g. RSI crosses 70). `condition` is { op, threshold } or { op, other }. Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},indicatorType:{type:"string",description:"e.g. rsi, ema, macd"},indicatorParams:{type:"object",description:"Indicator settings, e.g. { length: 14 }"},outputSeries:{type:"string",description:"Which output series to watch"},condition:{type:"object",description:"{ op: gt|gte|lt|lte|eq|crosses_above|crosses_below, threshold } or { op: *_series, other }"},dedupMode:{type:"string",enum:["edge","continuous"],description:"default: edge"},...G8},required:["pair","timeframe","indicatorType","indicatorParams","outputSeries","condition"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe,indicatorType:Q.indicatorType,indicatorParams:Q.indicatorParams,outputSeries:Q.outputSeries,condition:Q.condition,dedupMode:Q.dedupMode??"edge",...z4(Q)};return X.trpc.alerts.indicator.create.mutate(Y)}}),l({name:"update_indicator_alert",description:"Update an indicator alert (condition, dedup, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},condition:{type:"object"},dedupMode:{type:"string",enum:["edge","continuous"]},isActive:{type:"boolean"},isArchived:{type:"boolean"},...G8},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.indicator.update.mutate(Q$(Q))}}),l({name:"delete_indicator_alert",description:"Delete an indicator alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.alerts.indicator.delete.mutate({id:Q.id})}})];var mK=[l({name:"login",description:"Sign in to Aether Wealth. Opens your browser to authenticate; once you approve, the MCP stores a per-user token and the data tools become available.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await X.session.login(),{status:"signed_in",message:"Signed in to Aether Wealth."}}}),l({name:"logout",description:"Sign out of Aether Wealth on this device. Clears the stored access token.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await X.session.logout(),{status:"signed_out",message:"Signed out on this device."}}})];var X$="momentum: rsi, macd, stoch, stochf, stochrsi, cci, cmo, mom, roc, rocr, willr, mfi, ultosc, ppo, apo, bop, aroon, aroonosc; trend: adx, adxr, dx, plus_di, minus_di, plus_dm, minus_dm, sar, supertrend; moving averages: sma, ema, wma, dema, tema, trima, kama, t3ma, mama, vwap, midpoint, midprice; bands: bbands, keltner, percent_b; volatility: atr, natr, trange; volume: obv, ad, adosc; stats: linearreg, linearregslope, linearregangle, linearregintercept, stddev, var, tsf";function Y$(Q){return{pair:Q.pair,interval:Q.interval,indicators:Q.indicators.map((X)=>({name:X.name,...X.params===void 0?{}:{params:X.params}})),...Q.outputsize===void 0?{}:{outputsize:Q.outputsize}}}var cK=[l({name:"get_indicators",description:"Compute Twelve Data technical indicators for a pair + timeframe (requires sign-in). "+`Pass up to 8 indicators by name; params are optional and default sensibly. Names — ${X$}. Bad names/params return an error listing valid options. At most 2 distinct pairs per user at a time.`,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical id, e.g. EURUSD, XAUUSD, BTCUSD (case-insensitive)"},interval:{type:"string",description:"One of 1m, 5m, 15m, 30m, 45m, 1h, 2h, 4h, 1d"},indicators:{type:"array",minItems:1,maxItems:8,description:"Up to 8 indicators to compute on the pair",items:{type:"object",properties:{name:{type:"string",description:"Indicator name, e.g. rsi, macd, ema, bbands, atr, adx"},params:{type:"object",description:'Optional params, e.g. {"time_period": 14} or MACD {"fast_period":12,"slow_period":26}. Defaults applied when omitted.'}},required:["name"],additionalProperties:!1}},outputsize:{type:"integer",minimum:1,maximum:500,description:"Bars to return per indicator (default 30)"}},required:["pair","interval","indicators"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.technicalIndicators.get.query(Y$(Q))}})];function W$(Q){return{...Q.currency===void 0?{}:{currency:Q.currency},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.indicator===void 0?{}:{indicator:Q.indicator},...Q.impactMin===void 0?{}:{impactMin:Q.impactMin},...Q.view===void 0?{}:{view:Q.view}}}function G$(Q){return{currency:Q.currency,indicator:Q.indicator,...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.limit===void 0?{}:{limit:Q.limit}}}var pK=[l({name:"get_candles",description:"Get the most recent OHLC candles (up to 500) for a pair + timeframe. Timeframe may be a base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or any integer multiple of one (e.g. 2h, 3h, 12h, 90m), aggregated server-side; invalid or unsupported timeframes return an error, not an empty list.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD (canonical id; case-insensitive)"},timeframe:{type:"string",description:"A base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or an integer multiple of one (e.g. 2h, 3h, 12h, 90m). No fractional (2.5h) or sub-minute values."}},required:["pair","timeframe"],additionalProperties:!1},handler:async(Q,X)=>{await r(X);let Y={pair:Q.pair,timeframe:Q.timeframe};return X.trpc.marketData.candles.query(Y)}}),l({name:"list_economic_calendar",description:'List economic calendar events. Filter by currency, date range, release, or minimum impact (1-5). Currency and indicator/release are validated against the catalog: unknown values return an error listing valid options, so an empty result always means "no events" rather than "bad input".',inputSchema:{type:"object",properties:{currency:{type:"array",items:{type:"string"},description:'ISO currency codes, e.g. ["USD","EUR"]'},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},indicator:{type:"string",description:"release slug, e.g. cpi"},impactMin:{type:"integer",minimum:1,maximum:5},view:{type:"string",enum:["minimal","rich"]}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.listCalendar.query(W$(Q))}}),l({name:"get_macro_series",description:"Get a macro indicator time series (e.g. USD cpi). Currency and indicator are validated against the catalog: unknown values return an error listing valid options (case-insensitive).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"release slug, e.g. cpi"},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},limit:{type:"integer",minimum:1,maximum:1000}},required:["currency","indicator"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.listIndicatorSeries.query(G$(Q))}}),l({name:"get_market_config",description:"Get the catalog of supported instruments + timeframes (useful before calling other tools).",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.marketData.getConfig.query()}})];function J$(Q){return{...Q.accountId===void 0?{}:{accountId:Q.accountId},...Q.status===void 0||Q.status==="ALL"?{}:{status:Q.status},...Q.pair===void 0?{}:{pair:Q.pair},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to},...Q.page===void 0?{}:{page:Q.page},...Q.limit===void 0?{}:{limit:Q.limit}}}function iK(Q){return{...Q.stopLoss===void 0?{}:{stopLoss:Q.stopLoss},...Q.takeProfit===void 0?{}:{takeProfit:Q.takeProfit},...Q.lotSize===void 0?{}:{lotSize:Q.lotSize},...Q.notes===void 0?{}:{notes:Q.notes},...Q.timeframe===void 0?{}:{timeframe:Q.timeframe},...Q.riskPercent===void 0?{}:{riskPercent:Q.riskPercent},...Q.tags===void 0?{}:{tags:Q.tags}}}function B$(Q){return{accountId:Q.accountId,pair:Q.pair,direction:Q.direction,entryPrice:Q.entryPrice,entryTime:Q.entryTime,...iK(Q)}}function H$(Q){return{id:Q.id,...Q.pair===void 0?{}:{pair:Q.pair},...Q.direction===void 0?{}:{direction:Q.direction},...Q.entryPrice===void 0?{}:{entryPrice:Q.entryPrice},...Q.entryTime===void 0?{}:{entryTime:Q.entryTime},...iK(Q)}}function K$(Q){return{id:Q.id,exitPrice:Q.exitPrice,exitTime:Q.exitTime,...Q.fees===void 0?{}:{fees:Q.fees},...Q.swap===void 0?{}:{swap:Q.swap},...Q.notes===void 0?{}:{notes:Q.notes}}}function z$(Q){return{...Q.accountId===void 0?{}:{accountId:Q.accountId},...Q.pair===void 0?{}:{pair:Q.pair},...Q.from===void 0?{}:{from:Q.from},...Q.to===void 0?{}:{to:Q.to}}}var dK={stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},riskPercent:{type:"number"},tags:{type:"array",items:{type:"string"}}},nK=[l({name:"list_trades",description:"List the authenticated user's trades. Filter by account, status, pair, or date range (ISO 8601). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},from:{type:"string",description:"ISO 8601 datetime (inclusive lower bound)"},to:{type:"string",description:"ISO 8601 datetime (inclusive upper bound)"},page:fK,limit:hK},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.list.query(J$(Q))}}),l({name:"get_trade",description:"Get a single trade by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.get.query({id:Q.id})}}),l({name:"list_accounts",description:"List the user's trading accounts (use an account's id when creating a trade). Requires sign-in.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.accounts.list.query()}}),l({name:"trade_stats",description:"Trading performance statistics (win rate, PnL, etc.). Filter by account, pair, or date range. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},pair:{type:"string"},from:{type:"string",description:"ISO 8601 datetime"},to:{type:"string",description:"ISO 8601 datetime"}},additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.analytics.stats.query(z$(Q))}}),l({name:"create_trade",description:"Record a new trade. Requires sign-in. Use list_accounts to find the accountId.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id (see list_accounts)"},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...dK},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.create.mutate(B$(Q))}}),l({name:"update_trade",description:"Update fields on an existing trade. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},pair:{type:"string"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...dK},required:["id"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.update.mutate(H$(Q))}}),l({name:"close_trade",description:"Close an open trade with an exit price + time. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},exitPrice:{type:"number"},exitTime:{type:"string",description:"ISO 8601 datetime"},fees:{type:"number"},swap:{type:"number"},notes:{type:"string"}},required:["id","exitPrice","exitTime"],additionalProperties:!1},handler:async(Q,X)=>{return await r(X),X.trpc.trading.trades.close.mutate(K$(Q))}})];function Z4(){return[...mK,...nK,...lK,...pK,...cK]}var A$="aether-wealth-mcp",Z$="0.1.18";function oK(Q){let X=new W8({name:A$,version:Z$},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return F$(X,Q),X}function F$(Q,X){let Y=!1,W=(G)=>{let J=X.clientGate?.nudge;if(J&&!Y)return Y=!0,`${J}
|
|
86
86
|
|
|
87
87
|
${G}`;return G};Q.setRequestHandler(C9,async()=>({tools:Array.from(X.tools.values()).map((G)=>({name:G.name,description:G.description,inputSchema:G.inputSchema}))})),Q.setRequestHandler(q1,async(G)=>{if(X.clientGate?.blocked)return{content:[{type:"text",text:X.clientGate.blockedMessage??"Update required."}],isError:!0};let{name:J,arguments:B}=G.params,H=X.tools.get(J);if(!H)throw new T(C.MethodNotFound,`tool not found: ${J}`);let K=SQ(H.inputSchema,B);if(!K.ok)throw new T(C.InvalidParams,`invalid arguments for ${J}: ${K.reason}`);try{let z=await H.handler(K.args,X.toolContext);return{content:[{type:"text",text:W(D$(z))}],isError:!1}}catch(z){return{content:[{type:"text",text:V$(z)}],isError:!0}}}),Q.setRequestHandler(T9,async()=>({resources:Array.from(X.resources.values()).map((G)=>({uri:G.uri,name:G.name,description:G.description,mimeType:G.mimeType}))})),Q.setRequestHandler(j9,async(G)=>{let{uri:J}=G.params,B=X.resources.get(J);if(!B)throw new T(C.MethodNotFound,`resource not found: ${J}`);let H=await B.handler(X.toolContext);return{contents:[{uri:J,mimeType:B.mimeType,text:H.text}]}}),Q.setRequestHandler(S9,async()=>({prompts:Array.from(X.prompts.values()).map((G)=>({name:G.name,description:G.description,...G.arguments?{arguments:G.arguments}:{}}))})),Q.setRequestHandler(R9,async(G)=>{let{name:J,arguments:B}=G.params,H=X.prompts.get(J);if(!H)throw new T(C.MethodNotFound,`prompt not found: ${J}`);let K={};for(let[A,Z]of Object.entries(B??{}))if(typeof Z==="string")K[A]=Z;for(let A of H.arguments??[])if(A.required&&!(A.name in K))throw new T(C.InvalidParams,`prompts/get: missing required argument: ${A.name}`);let z=H.handler(K);return{description:H.description,messages:z}})}function D$(Q){if(typeof Q==="string")return Q;return JSON.stringify(Q,null,2)}function V$(Q){if(!(Q instanceof Error))return String(Q);let X=Q,Y=[`${X.name??"Error"}: ${X.message}`];if(typeof X.status==="number")Y.push(`status=${X.status}`);if(X.code)Y.push(`code=${X.code}`);if(X.method&&X.path)Y.push(`request=${X.method} ${X.path}`);return Y.join(" | ")}var U$="/mcp";async function aK(Q,X){let Y=X.path??U$,W=X.hostname??U1,G=X.log??((K)=>{process.stderr.write(K)});if(!X.bearerToken)G(`[http] WARNING: no bearer token configured; binding to ${W}:${X.port}${Y} unauthenticated
|
|
88
88
|
`);let J=Q.getRegistryBundle(),B=async(K)=>{if(new URL(K.url).pathname!==Y)return new Response("not found",{status:404});if(K.method==="GET")return new Response(JSON.stringify({ok:!0,transport:"streamable-http"}),{status:200,headers:{"content-type":"application/json"}});if(X.bearerToken&&!E$(K,X.bearerToken))return new Response("unauthorized",{status:401});let A=oK(J),Z=new aX({enableJsonResponse:!0});try{return await A.connect(Z),await Z.handleRequest(K)}catch(D){return G(`[http] dispatch error: ${sK(D)}
|
|
@@ -102,7 +102,7 @@ p{margin:0;color:hsl(var(--muted));font-size:.95rem}
|
|
|
102
102
|
<body><main class="card"><div class="badge">${Y}</div><h1>${Q.heading}</h1><p>${Q.detail}</p><div class="brand">Aether Wealth</div></main></body></html>`}var f$=Zz({title:"Signed in · Aether Wealth",heading:"Signed in to Aether Wealth",detail:"You can close this tab and return to your assistant.",ok:!0}),Az=Zz({title:"Sign-in failed · Aether Wealth",heading:"Sign-in failed",detail:"You can close this tab and try again from your assistant.",ok:!1});function u$(Q,X){return new Promise((Y)=>{let W=(G)=>{Q.removeListener("error",W),Y({ok:!1,...G.code==="EADDRINUSE"?{}:{error:G}})};Q.once("error",W),Q.listen(X,U1,()=>{Q.removeListener("error",W),Y({ok:!0})})})}async function l$(Q,X){let Y;for(let G of X){let J=await u$(Q,G);if(J.ok)return G;if(J.error)Y=J.error}let W=Y?`: ${Y.message}`:"";throw Error(`could not bind any loopback port (${X.join(", ")}) for OAuth redirect${W}`)}async function Fz(Q,X){let Y=null,W=null,G=null,J=(K)=>{if(Y)return;if(Y=K,K?.ok)W?.(K.value);else if(K)G?.(K.error)},B=h$((K,z)=>{let A=new URL(K.url??"/",`http://${U1}`);if(A.pathname!==X){z.writeHead(404).end("not found");return}let Z=A.searchParams.get("error"),D=A.searchParams.get("code"),F=A.searchParams.get("state");if(Z){z.writeHead(400,{"content-type":"text/html"}).end(Az),J({ok:!1,error:Error(`authorization denied: ${Z}`)});return}if(!D||!F){z.writeHead(400,{"content-type":"text/html"}).end(Az),J({ok:!1,error:Error("callback missing code or state")});return}z.writeHead(200,{"content-type":"text/html"}).end(f$),J({ok:!0,value:{code:D,state:F}})}),H=await l$(B,Q);return{redirectUri:Hz(H),waitForCode(K){return new Promise((z,A)=>{let Z=setTimeout(()=>A(Error("timed out waiting for the browser sign-in to complete")),K);if(Z.unref(),W=(D)=>{clearTimeout(Z),z(D)},G=(D)=>{clearTimeout(Z),A(D)},Y?.ok)W(Y.value);else if(Y)G(Y.error)})},close(){return new Promise((K)=>B.close(()=>K()))}}}import{createHash as m$,randomBytes as Dz}from"node:crypto";function U4(Q){return Q.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Vz(Q={}){let X=U4((Q.randomBytesImpl??Dz)(32)),Y=Q.hashImpl?Q.hashImpl(X):m$("sha256").update(X).digest();return{verifier:X,challenge:U4(Y),method:"S256"}}function Lz(Q=Dz){return U4(Q(16))}var c$=300000;async function Uz(Q){let X=Q.fetchImpl??fetch,Y=Q.log??(()=>{}),W=Q.now??Date.now,G=await zz(Q.authBaseUrl,X),J=Vz(),B=Lz(),H=await Fz(Jz,L4);try{let K=d$(Q.authBaseUrl),z=p$(G.authorizationEndpoint,{clientId:V4,redirectUri:H.redirectUri,scope:Bz.join(" "),state:B,codeChallenge:J.challenge,...K?{prompt:"consent"}:{}});if(Y(`Opening your browser to sign in. If it doesn't open, visit:
|
|
103
103
|
${z}
|
|
104
104
|
`),!await(Q.openBrowserImpl??Gz)(z))Y(`Could not open a browser automatically — open the URL above manually.
|
|
105
|
-
`);let{code:Z,state:D}=await H.waitForCode(c$);if(D!==B)throw Error("OAuth state mismatch — aborting login (possible CSRF).");return await i$(G.tokenEndpoint,{code:Z,codeVerifier:J.verifier,redirectUri:H.redirectUri,clientId:V4},X,W)}finally{await H.close()}}function p$(Q,X){let Y=new URL(Q);if(Y.searchParams.set("response_type","code"),Y.searchParams.set("client_id",X.clientId),Y.searchParams.set("redirect_uri",X.redirectUri),Y.searchParams.set("scope",X.scope),Y.searchParams.set("state",X.state),Y.searchParams.set("code_challenge",X.codeChallenge),Y.searchParams.set("code_challenge_method","S256"),X.prompt)Y.searchParams.set("prompt",X.prompt);return Y.toString()}function d$(Q){try{return Wz(new URL(Q).hostname)}catch{return!1}}async function i$(Q,X,Y=fetch,W=Date.now){let G=new URLSearchParams({grant_type:"authorization_code",code:X.code,redirect_uri:X.redirectUri,client_id:X.clientId,code_verifier:X.codeVerifier}),J=await Y(Q,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:G.toString()}),B=await RQ(J),H=B.access_token,K=B.expires_in;if(!J.ok||typeof H!=="string")throw Error(`OAuth token exchange failed: ${n$(B,J.status)}`);if(typeof K!=="number"||K<=0)throw Error("OAuth token exchange returned no valid expires_in");return{accessToken:H,expiresAt:W()+K*1000}}function n$(Q,X){if(typeof Q.error_description==="string")return Q.error_description;if(typeof Q.error==="string")return Q.error;return`HTTP ${X}`}class N4{config;store;deps;constructor(Q,X,Y={}){this.config=Q;this.store=X;this.deps=Y}async getAccessToken(){let Q=await this.store.get(this.config.host);if(!Q)return null;let X=(this.deps.now??Date.now)();if(Q.expiresAt<=X)return await this.store.clear(this.config.host),null;return Q.accessToken}async login(){let Q=await(this.deps.runLoginImpl??Uz)({authBaseUrl:this.config.baseUrl,...this.deps.log?{log:this.deps.log}:{},...this.deps.now?{now:this.deps.now}:{}});await this.store.set(this.config.host,{accessToken:Q.accessToken,expiresAt:Q.expiresAt})}async logout(){await this.store.clear(this.config.host)}}var Nz="aether-wealth-mcp",M4="0.1.18
|
|
105
|
+
`);let{code:Z,state:D}=await H.waitForCode(c$);if(D!==B)throw Error("OAuth state mismatch — aborting login (possible CSRF).");return await i$(G.tokenEndpoint,{code:Z,codeVerifier:J.verifier,redirectUri:H.redirectUri,clientId:V4},X,W)}finally{await H.close()}}function p$(Q,X){let Y=new URL(Q);if(Y.searchParams.set("response_type","code"),Y.searchParams.set("client_id",X.clientId),Y.searchParams.set("redirect_uri",X.redirectUri),Y.searchParams.set("scope",X.scope),Y.searchParams.set("state",X.state),Y.searchParams.set("code_challenge",X.codeChallenge),Y.searchParams.set("code_challenge_method","S256"),X.prompt)Y.searchParams.set("prompt",X.prompt);return Y.toString()}function d$(Q){try{return Wz(new URL(Q).hostname)}catch{return!1}}async function i$(Q,X,Y=fetch,W=Date.now){let G=new URLSearchParams({grant_type:"authorization_code",code:X.code,redirect_uri:X.redirectUri,client_id:X.clientId,code_verifier:X.codeVerifier}),J=await Y(Q,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:G.toString()}),B=await RQ(J),H=B.access_token,K=B.expires_in;if(!J.ok||typeof H!=="string")throw Error(`OAuth token exchange failed: ${n$(B,J.status)}`);if(typeof K!=="number"||K<=0)throw Error("OAuth token exchange returned no valid expires_in");return{accessToken:H,expiresAt:W()+K*1000}}function n$(Q,X){if(typeof Q.error_description==="string")return Q.error_description;if(typeof Q.error==="string")return Q.error;return`HTTP ${X}`}class N4{config;store;deps;constructor(Q,X,Y={}){this.config=Q;this.store=X;this.deps=Y}async getAccessToken(){let Q=await this.store.get(this.config.host);if(!Q)return null;let X=(this.deps.now??Date.now)();if(Q.expiresAt<=X)return await this.store.clear(this.config.host),null;return Q.accessToken}async login(){let Q=await(this.deps.runLoginImpl??Uz)({authBaseUrl:this.config.baseUrl,...this.deps.log?{log:this.deps.log}:{},...this.deps.now?{now:this.deps.now}:{}});await this.store.set(this.config.host,{accessToken:Q.accessToken,expiresAt:Q.expiresAt})}async logout(){await this.store.clear(this.config.host)}}var Nz="aether-wealth-mcp",M4="0.1.18";function o$(Q){return{toolContext:Q.toolContext,tools:new Map((Q.tools??Z4()).map((X)=>[X.name,X])),resources:new Map((Q.resources??K4()).map((X)=>[X.uri,X])),prompts:new Map((Q.prompts??H4()).map((X)=>[X.name,X])),...Q.clientGate?{clientGate:Q.clientGate}:{},log:Q.log??((X)=>{process.stderr.write(X)})}}function r$(Q){let X=new W8({name:Nz,version:M4},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return t$(X,Q),X}class q4{server;bundle;constructor(Q){this.bundle=o$(Q),this.server=r$(this.bundle),this.server.oninitialized=()=>{this.bundle.log(`${Nz} initialized
|
|
106
106
|
`)}}async connect(Q){await this.server.connect(Q)}async close(){await this.server.close()}isInitialized(){return this.server.getClientVersion()!==void 0}getRegistryBundle(){return this.bundle}}function t$(Q,X){let Y=!1,W=(G)=>{let J=X.clientGate?.nudge;if(J&&!Y)return Y=!0,`${J}
|
|
107
107
|
|
|
108
108
|
${G}`;return G};Q.setRequestHandler(C9,async()=>({tools:Array.from(X.tools.values()).map((G)=>({name:G.name,description:G.description,inputSchema:G.inputSchema}))})),Q.setRequestHandler(q1,async(G)=>{if(X.clientGate?.blocked)return{content:[{type:"text",text:X.clientGate.blockedMessage??"Update required."}],isError:!0};let{name:J,arguments:B}=G.params,H=X.tools.get(J);if(!H)throw new T(C.MethodNotFound,`tool not found: ${J}`);let K=SQ(H.inputSchema,B);if(!K.ok)throw new T(C.InvalidParams,`invalid arguments for ${J}: ${K.reason}`);try{let z=await H.handler(K.args,X.toolContext);return{content:[{type:"text",text:W(a$(z))}],isError:!1}}catch(z){return{content:[{type:"text",text:s$(z)}],isError:!0}}}),Q.setRequestHandler(T9,async()=>({resources:Array.from(X.resources.values()).map((G)=>({uri:G.uri,name:G.name,description:G.description,mimeType:G.mimeType}))})),Q.setRequestHandler(j9,async(G)=>{let{uri:J}=G.params,B=X.resources.get(J);if(!B)throw new T(C.MethodNotFound,`resource not found: ${J}`);let H=await B.handler(X.toolContext);return{contents:[{uri:J,mimeType:B.mimeType,text:H.text}]}}),Q.setRequestHandler(S9,async()=>({prompts:Array.from(X.prompts.values()).map((G)=>({name:G.name,description:G.description,...G.arguments?{arguments:G.arguments}:{}}))})),Q.setRequestHandler(R9,async(G)=>{let{name:J,arguments:B}=G.params,H=X.prompts.get(J);if(!H)throw new T(C.MethodNotFound,`prompt not found: ${J}`);let K={};for(let[A,Z]of Object.entries(B??{}))if(typeof Z==="string")K[A]=Z;for(let A of H.arguments??[])if(A.required&&!(A.name in K))throw new T(C.InvalidParams,`prompts/get: missing required argument: ${A.name}`);let z=H.handler(K);return{description:H.description,messages:z}})}function a$(Q){if(typeof Q==="string")return Q;return JSON.stringify(Q,null,2)}function s$(Q){if(!(Q instanceof Error))return String(Q);let X=Q,Y=[`${X.name??"Error"}: ${X.message}`];if(typeof X.status==="number")Y.push(`status=${X.status}`);if(X.code)Y.push(`code=${X.code}`);if(X.method&&X.path)Y.push(`request=${X.method} ${X.path}`);return Y.join(" | ")}import qz from"node:process";class w4{append(Q){this._buffer=this._buffer?Buffer.concat([this._buffer,Q]):Q}readMessage(){if(!this._buffer)return null;let Q=this._buffer.indexOf(`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aetherwealth/mcp",
|
|
3
|
-
"version": "0.1.18
|
|
4
|
-
"description": "Aether Wealth MCP server
|
|
3
|
+
"version": "0.1.18",
|
|
4
|
+
"description": "Official Aether Wealth MCP server for AI trading assistants: OAuth access to your trading journal, alerts, market data, macro calendar, and technical indicators.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"aether-wealth-mcp": "dist/index.js"
|
|
@@ -18,6 +18,26 @@
|
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"aether wealth",
|
|
23
|
+
"mcp",
|
|
24
|
+
"model context protocol",
|
|
25
|
+
"trading mcp",
|
|
26
|
+
"ai trading assistant",
|
|
27
|
+
"trading journal",
|
|
28
|
+
"forex",
|
|
29
|
+
"market data",
|
|
30
|
+
"technical indicators",
|
|
31
|
+
"oauth"
|
|
32
|
+
],
|
|
21
33
|
"license": "UNLICENSED",
|
|
22
|
-
"homepage": "https://aetherwealth.ai"
|
|
34
|
+
"homepage": "https://aetherwealth.ai/mcp",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/Opus-Aether-AI/webapp.git",
|
|
38
|
+
"directory": "apps/aether-wealth-mcp"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/Opus-Aether-AI/webapp/issues"
|
|
42
|
+
}
|
|
23
43
|
}
|