@candledottv/mcp 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +65 -19
  2. package/dist/index.js +1037 -67
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
1
  # @candledottv/mcp
2
2
 
3
3
  An MCP (Model Context Protocol) server for the Candle agent rail. It exposes Candle's REST API as
4
- twenty tools over stdio, so an MCP-capable agent can launch tokens (optionally seeded with a dev
4
+ twenty-nine tools over stdio, so an MCP-capable agent can launch tokens (optionally seeded with a dev
5
5
  buy in the same call), trade, convert between base assets (including across chains), read market
6
6
  and feed data, report on-chain activity, and check an agent profile without hand-rolling HTTP
7
7
  calls.
8
8
 
9
9
  ## Try it without a key
10
10
 
11
- Five tools are read-only and need nothing but `CANDLE_API_URL` (which already defaults to
11
+ Six tools are read-only and need nothing but `CANDLE_API_URL` (which already defaults to
12
12
  production): `candle_get_market`, `candle_get_feed`, `candle_token_forensics`,
13
- `candle_get_agent_profile`, and `candle_resolve_token`. Install the
14
- server with no `env` block at all and those five work immediately:
13
+ `candle_get_agent_profile`, `candle_resolve_token` and `candle_get_plans`. Install the
14
+ server with no `env` block at all and those six work immediately:
15
15
 
16
16
  ```json
17
17
  {
@@ -31,11 +31,11 @@ Environment below -- or skip env editing entirely: install the Candle CLI
31
31
  environment.
32
32
 
33
33
  `CANDLE_MCP_TOOLS` (optional) is a comma-separated allowlist of tool names; only those register.
34
- Unset means all twenty. An unknown name fails startup with the valid names in the message, rather
34
+ Unset means all twenty-nine. An unknown name fails startup with the valid names in the message, rather
35
35
  than silently registering the wrong surface. `candle mcp --read-only` / `--tools` set this for
36
36
  you.
37
37
 
38
- Most tools are a thin wrapper: a one-request mapping onto `apps/api`
38
+ Most tools are a thin wrapper: a one-request mapping onto Candle's REST API
39
39
  (`POST /api/v1/launch/headless`, `GET /api/v1/markets/:chain/:mint`, `GET /api/v1/markets/feed`,
40
40
  `POST /api/v1/activity/report`, `GET /api/v1/users/:idOrWallet/agent`) that hands the response body
41
41
  straight back to the caller, unchanged, error responses included. `candle_trade` and
@@ -48,7 +48,8 @@ Both take decimal amounts, never raw base units, and resolve the scale themselve
48
48
  - A `candle_trade` **buy** is denominated in the token's OWN quote asset, whatever it was launched
49
49
  against (SOL for a SOL-launched token, USDC or CNDL for those quote pairs). The tool reads the
50
50
  market first and converts against its `quoteDecimals`; the `quoteAsset` field applies only to a
51
- mint Candle never launched, the arbitrary-token path a Pro or Max key trades through Jupiter. A
51
+ mint Candle never launched, the path traded through Jupiter (buying needs Pro or Max; selling
52
+ works on any plan). A
52
53
  **sell** is denominated in tokens and converts against the market's own `decimals`.
53
54
  - A `candle_launch_and_seed` `devBuy` is denominated in the quote asset that launch selects, since
54
55
  there the caller genuinely picks the new token's quote pair: `quoteAsset` if given, otherwise
@@ -56,11 +57,11 @@ Both take decimal amounts, never raw base units, and resolve the scale themselve
56
57
 
57
58
  For a full walkthrough of `candle_launch_and_seed` and `candle_trade`, including the keyless read
58
59
  tools, getting a key, funding the embedded wallet, and idempotent retries, see
59
- `docs/mcp-launch-and-seed.md` in the `candle-monorepo` repo.
60
+ [Candle MCP server](https://docs.candle.tv/developers/mcp-server).
60
61
 
61
62
  ## Environment
62
63
 
63
- - `CANDLE_API_URL` -- base URL of the Candle API. Defaults to `https://api.alpha.candle.tv` (the alpha deployment; production does not serve the agent API yet). Set it to
64
+ - `CANDLE_API_URL` -- base URL of the Candle API. Defaults to `https://api.alpha.candle.tv`, production. Set it to
64
65
  `http://localhost:3001` when developing against a local API. A cleartext `http://` URL pointing
65
66
  at a NON-loopback host is refused at startup, since every write tool sends `x-api-key`; loopback
66
67
  (`localhost`, `127.0.0.0/8`, `::1`) needs no opt-in.
@@ -68,13 +69,18 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
68
69
  non-loopback host. For a trusted local endpoint that is not loopback, such as a devcontainer
69
70
  reaching its host; not for anything that leaves the machine.
70
71
  - `CANDLE_AGENT_API_KEY` -- an agent API key (`cndl_live_...` / `cndl_test_...`), issued from a
71
- Candle account's agent settings page. Required by every tool except the five read-only ones
72
+ Candle account's agent settings page. Required by every tool except the six read-only ones
72
73
  listed above, which includes the account-scoped reads (`candle_get_wallets`,
73
- `candle_execution_status`, `candle_get_operation`) as well as the writes; those five
74
+ `candle_execution_status`, `candle_get_operation`) as well as the writes; those six
74
75
  work without it, so the server is useful the moment it is installed and only asks for a key when
75
76
  you try to write. `candle_trade` additionally needs the key's `swap:write` scope server-side,
76
- which is opt-in only and never granted by omission, see `docs/mcp-launch-and-seed.md` in the
77
- `candle-monorepo` repo.
77
+ which is opt-in only and never granted by omission, see
78
+ [Agent access](https://docs.candle.tv/developers/agent-access).
79
+ - `CANDLE_KEY_SIGNER_PEM_FILE` -- the perps write tools only: the path to the key signer's PEM
80
+ (`candle tee signer new --out <pem>` writes one). The relay's authorization is signed with it;
81
+ without it those tools refuse before anything is built.
82
+ - `CANDLE_HYPERLIQUID_BUILDER` / `CANDLE_HYPERLIQUID_NETWORK` -- the perps tools: pin Candle's
83
+ Hyperliquid builder address for the pre-sign check, and set `testnet` to trade testnet.
78
84
  - `CANDLE_API_KEY` -- alias for `CANDLE_AGENT_API_KEY`, the same variable name the Candle CLI uses
79
85
  for this credential. Set either one; if both are set, `CANDLE_AGENT_API_KEY` takes precedence.
80
86
 
@@ -88,6 +94,7 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
88
94
  | `candle_token_forensics` | Deployer history, deploy-window buyers, sourced token safety flags | `GET /api/v1/markets/:chain/:mint/forensics` | none |
89
95
  | `candle_report_activity` | Report on-chain activity | `POST /api/v1/activity/report` | `CANDLE_AGENT_API_KEY` |
90
96
  | `candle_get_agent_profile` | Get an agent profile | `GET /api/v1/users/:idOrWallet/agent` | none |
97
+ | `candle_get_plans` | Plans: prices, fees, limits and what each can do, as JSON and a Markdown table | `GET /api/v1/agent/plans` | none |
91
98
  | `candle_trade` | Buy or sell a token | Reads the market for its decimals (or wallet balance, for a percent sell) then `POST /api/v1/trade/agent/build` | `CANDLE_AGENT_API_KEY` (`swap:write`) |
92
99
  | `candle_launch_and_seed` | Launch a token and seed it | `POST /api/v1/launch/headless` (or `/dry-run`), then a follow-up `GET /api/v1/markets/:chain/:mint` | `CANDLE_AGENT_API_KEY` |
93
100
  | `candle_swap` | Swap between base assets | `POST /api/v1/agent/swap` | `CANDLE_AGENT_API_KEY` (`swap:write`) |
@@ -97,11 +104,19 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
97
104
  | `candle_get_wallets` | The account's embedded wallets, one per chain, with delegation state | `GET /api/v1/agent/wallets/embedded` | `CANDLE_AGENT_API_KEY` |
98
105
  | `candle_get_profile_wallets` | Which wallets an agent profile may spend from, and whether it is scoped | `GET /api/v1/agent/keys/:prefix/wallets` | `CANDLE_AGENT_API_KEY` |
99
106
  | `candle_set_profile_wallets` | Replace the wallets an agent profile may spend from | `PUT /api/v1/agent/keys/:prefix/wallets` | `CANDLE_AGENT_API_KEY` |
100
- | `candle_get_profile_pnl` | An agent profile's realized P&L, fees, and open positions at cost basis, marked at current prices (unpriced positions counted, not zeroed), split by the wallet that paid (`pnl.byWallet`) and by chain (`pnl.byChain`), with `chain` on every position and wallet row | `GET /api/v1/agent/keys/:prefix/pnl` | `CANDLE_AGENT_API_KEY` |
107
+ | `candle_get_profile_pnl` | An agent profile's share of the account's P&L, the console's figures to the cent: realized on its sales, fees, and the open positions that belong to it at cost basis, marked at current prices (unpriced positions counted, not zeroed), with `totalUsd`, the closed positions as made, lost and partial sells (`closed`), dust flagged and counted apart (`openPositionsExDust`), split by wallet (`pnl.byWallet`, summing to the total) and by chain (`pnl.byChain`), with `chain` and `wallet` on every position | `GET /api/v1/agent/keys/:prefix/pnl` | `CANDLE_AGENT_API_KEY` |
101
108
  | `candle_get_profile_trades` | An agent profile's orders, fills, fees and transaction hashes | `GET /api/v1/agent/keys/:prefix/trades` | `CANDLE_AGENT_API_KEY` |
102
109
  | `candle_get_portfolio` | What the account's embedded and TEE wallets hold on Solana and Hood (Hood in `hood`), with prices; unpriced holdings say why, never zero | `GET /api/v1/agent/portfolio` | `CANDLE_AGENT_API_KEY` (`account:read`) |
103
110
  | `candle_execution_status` | One call before trading: wallets to spend from, tier, and whether trading is possible | Composes the wallet and tier reads | `CANDLE_AGENT_API_KEY` |
104
111
  | `candle_get_operation` | Look up a trade or launch by the id its write used, and whether it landed | `GET /api/v1/trade/agent/jobs/:clientId` or `/api/v1/launch/headless/jobs/:clientId` | `CANDLE_AGENT_API_KEY` |
112
+ | `candle_perps_setup` | Approve Candle's Hyperliquid builder fee once; report the account's mode and balance | `POST /api/v1/agent/perps/setup`, then relay sign and Hyperliquid submit | `CANDLE_AGENT_API_KEY` (`perps:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
113
+ | `candle_perps_open` | Open or add to a perps position, with optional take-profit and stop-loss | `POST /api/v1/agent/perps/open`, checked here, relay-signed, submitted to Hyperliquid | `CANDLE_AGENT_API_KEY` (`perps:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
114
+ | `candle_perps_close` | Close all or part of a perps position, reduce-only | `POST /api/v1/agent/perps/close`, the same | `CANDLE_AGENT_API_KEY` (`perps:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
115
+ | `candle_perps_cancel` | Cancel a perps order Candle built, by cloid | `POST /api/v1/agent/perps/cancel`, the same | `CANDLE_AGENT_API_KEY` (`perps:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
116
+ | `candle_perps_leverage` | Set a market's leverage and margin mode | `POST /api/v1/agent/perps/leverage`, the same | `CANDLE_AGENT_API_KEY` (`perps:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
117
+ | `candle_perps_deposit` | Deposit onto the key's Hyperliquid account through Relay, from its Solana or Hood TEE wallet | `POST /api/v1/agent/perps/deposit`, checked here, relay-signed, `POST /api/v1/agent/perps/deposit/submit` | `CANDLE_AGENT_API_KEY` (`swap:write`), `CANDLE_KEY_SIGNER_PEM_FILE` |
118
+ | `candle_perps_orders` | Open Hyperliquid orders and every action Candle built | `GET /api/v1/agent/perps/orders` | `CANDLE_AGENT_API_KEY` |
119
+ | `candle_perps_positions` | Perps positions and account value, read live | `GET /api/v1/agent/perps/positions` | `CANDLE_AGENT_API_KEY` |
105
120
 
106
121
  ### Transfers and sweeps
107
122
 
@@ -118,13 +133,13 @@ explicitly. Assets with nothing spendable report `empty`; a failed asset never s
118
133
  ## Errors
119
134
 
120
135
  This package never reinterprets an error body, and that body is not one uniform shape across all
121
- twenty tools:
136
+ twenty-nine tools:
122
137
 
123
138
  - `candle_launch_token`, `candle_get_market`, and `candle_get_feed` hit endpoints that use the
124
139
  structured envelope `{ success: false, error: { code, message, ... } }`. Branch on `error.code`.
125
- - `candle_report_activity` relays `apps/api/src/routes/activity.ts`'s own plain error shape
140
+ - `candle_report_activity` relays the activity endpoint's own plain error shape
126
141
  verbatim: `{ error: true, payload: string }`.
127
- - `candle_get_agent_profile` relays `apps/api/src/routes/users.ts`'s own plain error shape
142
+ - `candle_get_agent_profile` relays the users endpoint's own plain error shape
128
143
  verbatim: `{ error: string }`.
129
144
  - `candle_trade` and `candle_launch_and_seed` wrap the underlying REST body instead of relaying it
130
145
  bare, in one of two shapes depending on how far the call got:
@@ -153,8 +168,9 @@ twenty tools:
153
168
  `candle_get_market` to fetch it separately.
154
169
  - Either way, both tools echo their idempotency id (`clientTradeId` / `clientLaunchId`) at the
155
170
  top level, so a caller can always find it to retry safely: retrying with the SAME id is a safe
156
- replay, a new id is a second trade or launch. See `docs/mcp-launch-and-seed.md` in the
157
- `candle-monorepo` repo for the full idempotent-retry rule.
171
+ replay, a new id is a second trade or launch. See
172
+ [Candle MCP server](https://docs.candle.tv/developers/mcp-server) for the full idempotent-retry
173
+ rule.
158
174
 
159
175
  ## MCP client config
160
176
 
@@ -209,3 +225,33 @@ this on machines that have node and may not have bun.
209
225
  calls with multi-field zod input shapes coexist in one file, which this package's tools
210
226
  always will. `1.22.0` predates that rewrite and type-checks cleanly with the exact same tool
211
227
  code. Re-check this pin when bumping the SDK.
228
+
229
+ ### Hyperliquid per-key PnL
230
+
231
+ `candle pnl --profile <name>` / SDK `getProfilePnl(keyPrefix)` / MCP `candle_get_profile_pnl`
232
+ read the existing `GET /api/v1/agent/keys/{prefix}/pnl`. The answer adds an optional
233
+ `hyperliquid` section, and the CLI prints it under **Hyperliquid**. The existing read
234
+ authentication applies; on an older API the section is simply absent. No additional signing, deposit or setup is needed for this read.
235
+
236
+ The section reports main-exchange perp `realizedGrossUsd` (venue `closedPnl`), signed
237
+ `fundingUsd` (received positive, paid negative), `feesUsd` (venue fees including builder fees;
238
+ rebates are negative), and `realizedNetUsd = realizedGrossUsd + fundingUsd - feesUsd`.
239
+ Builder fees are already included in the venue fee and are not subtracted again. These figures
240
+ stay separate from spot and LP totals and exclude unrealized perps, deposits and withdrawals.
241
+
242
+ Coverage is **currently bound EVM TEE wallets since the current TEE binding**,
243
+ shown in `byWallet` with `startTime` in epoch milliseconds. That start is the latest rebind
244
+ onto this key, or the wallet's creation time when it was bound then and never rebound. A
245
+ rebound wallet does not bring its previous key's history. A wallet-set row is not required,
246
+ and an older one cannot move the start earlier than the binding. Revoked and previous
247
+ bindings, spot and HIP-3 fills are excluded. This is a binding-period read, not lifetime or
248
+ order-level attribution.
249
+
250
+ Reads use the venue client's two-second cache. `userFills` is capped at 2,000 recent rows;
251
+ `userFunding` at 500 rows from `startTime`, and this response covers at most 20 bound
252
+ wallets. `truncated` flags any reached history cap or remaining wallet page; `byWallet` names
253
+ `fillsTruncated` and `fundingTruncated`. Funding and fills can cover different time spans when
254
+ capped: a partial net must not be quoted as a lifetime figure. On upstream, wallet-discovery or
255
+ malformed-data failure the section is `{ read: false, reason }`, without amounts; spot PnL still
256
+ answers. An empty successful read is `{ read: true, ... }` with zero amounts. `--json` preserves
257
+ the section and its coverage fields. Agent boards are outside this slice.