@candledottv/mcp 0.10.27 → 0.10.29

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 +4 -3
  2. package/dist/index.js +110 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @candledottv/mcp
2
2
 
3
3
  An MCP (Model Context Protocol) server for the Candle agent rail. The current source exposes Candle's REST API as
4
- eighty-two tools over stdio, plus four Hyperliquid market reads (eighty-six in all), so an MCP-capable agent can launch tokens (optionally seeded with a dev
4
+ eighty-three tools over stdio, plus four Hyperliquid market reads (eighty-seven in all), 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, read one token's signals and tracked-wallet trades and its card data, report on-chain activity,
7
7
  check an agent profile, and backtest a strategy in hacc's strategy lab without hand-rolling HTTP calls. The five
@@ -35,7 +35,7 @@ Environment below -- or skip env editing entirely: install the Candle CLI
35
35
  environment.
36
36
 
37
37
  `CANDLE_MCP_TOOLS` (optional) is a comma-separated allowlist of tool names; only those register.
38
- Unset means all eighty-two. An unknown name fails startup with the valid names in the message, rather
38
+ Unset means all eighty-three. An unknown name fails startup with the valid names in the message, rather
39
39
  than silently registering the wrong surface. `candle mcp --read-only` / `--tools` set this for
40
40
  you.
41
41
 
@@ -163,6 +163,7 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
163
163
  | `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` |
164
164
  | `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` |
165
165
  | `candle_get_fees` | The creator fees the account's launched tokens can pay: raw amounts from chain reads, and the reason a token cannot be claimed | `GET /api/v1/agent/fees` | `CANDLE_AGENT_API_KEY` (`account:read`) |
166
+ | `candle_atomic_launch_dry_run` | Check a Solana launch with first buys and price each buy on the curve it would deploy; builds, reserves and writes nothing | `POST /api/v1/launch/atomic/dry-run` | `CANDLE_AGENT_API_KEY` (`launch:write`, `swap:write`, Pro or Max) |
166
167
  | `candle_claim_fees` | Collect one token's creator fees to the wallet fixed at launch (no destination argument); `dryRun` sends nothing | `POST /api/v1/agent/fees/:mint/claim` | `CANDLE_AGENT_API_KEY` (`launch:write`) |
167
168
  | `candle_get_staking` | Read CNDL/sCNDL, withdrawals, rewards, pool wait and wallet eligibility notes | `GET /api/v1/agent/staking` |
168
169
  | `candle_stake` | Stake raw CNDL; stable clientStakeId, dryRun first | `POST /api/v1/agent/staking/stake/build` |
@@ -239,7 +240,7 @@ explicitly. Assets with nothing spendable report `empty`; a failed asset never s
239
240
  ## Errors
240
241
 
241
242
  This package never reinterprets an error body, and that body is not one uniform shape across all
242
- eighty-two tools:
243
+ eighty-three tools:
243
244
 
244
245
  - `candle_token_events`, called with `kind`, is the one narrowing of a SUCCESS body, never an
245
246
  error one: the relayed `events` are filtered to that kind and the body gains `filteredByKind`.
package/dist/index.js CHANGED
@@ -189,7 +189,7 @@ function readClusterResult(value, mint) {
189
189
  }
190
190
 
191
191
  // src/version.ts
192
- var SERVER_VERSION = "0.10.27";
192
+ var SERVER_VERSION = "0.10.29";
193
193
 
194
194
  // src/update-notice.ts
195
195
  var PLAIN_VERSION = /^\d+\.\d+\.\d+$/;
@@ -1442,6 +1442,77 @@ var LAUNCH_DEFINITION = {
1442
1442
  }
1443
1443
  }
1444
1444
  },
1445
+ {
1446
+ key: "feeWallet",
1447
+ type: "string",
1448
+ help: "Solana only: the wallet this launch's curve and pool fees earn to, an on-curve wallet or a Squads v4 vault; defaults to the wallet that launches the token (the account wallet on a server without LAUNCH_FEE_WALLET_FROM_LAUNCHER, except an embedded launch).",
1449
+ chains: [
1450
+ "solana"
1451
+ ],
1452
+ surfaces: {
1453
+ cli: {
1454
+ flag: "--fee-wallet",
1455
+ value: "<address>"
1456
+ },
1457
+ mcp: {
1458
+ key: "feeWallet"
1459
+ },
1460
+ sdk: {
1461
+ key: "feeWallet"
1462
+ }
1463
+ }
1464
+ },
1465
+ {
1466
+ key: "feeWalletMultisig.address",
1467
+ type: "string",
1468
+ help: "The Squads v4 multisig behind an off-curve --fee-wallet vault; takes --fee-wallet-multisig-vault-index.",
1469
+ chains: [
1470
+ "solana"
1471
+ ],
1472
+ requires: [
1473
+ "feeWallet"
1474
+ ],
1475
+ surfaces: {
1476
+ cli: {
1477
+ flag: "--fee-wallet-multisig",
1478
+ value: "<address>"
1479
+ },
1480
+ mcp: {
1481
+ key: "feeWalletMultisig.address"
1482
+ },
1483
+ sdk: {
1484
+ key: "feeWalletMultisig.address"
1485
+ }
1486
+ }
1487
+ },
1488
+ {
1489
+ key: "feeWalletMultisig.vaultIndex",
1490
+ type: "integer",
1491
+ help: "The Squads vault index, 0 to 255, that with the multisig derives an off-curve --fee-wallet.",
1492
+ chains: [
1493
+ "solana"
1494
+ ],
1495
+ range: {
1496
+ min: "0",
1497
+ max: "255",
1498
+ unit: "vault index"
1499
+ },
1500
+ requires: [
1501
+ "feeWalletMultisig.address"
1502
+ ],
1503
+ surfaces: {
1504
+ cli: {
1505
+ flag: "--fee-wallet-multisig-vault-index",
1506
+ value: "<n>"
1507
+ },
1508
+ mcp: {
1509
+ key: "feeWalletMultisig.vaultIndex"
1510
+ },
1511
+ sdk: {
1512
+ key: "feeWalletMultisig.vaultIndex"
1513
+ }
1514
+ }
1515
+ },
1445
1516
  {
1446
1517
  key: "buy",
1447
1518
  type: "decimal",
@@ -1486,7 +1557,7 @@ var LAUNCH_DEFINITION = {
1486
1557
  };
1487
1558
 
1488
1559
  // src/launch-schema.ts
1489
- var M2_TOP_KEYS = new Set(["wallet", "buy"]);
1560
+ var M2_TOP_KEYS = new Set(["wallet", "buy", "feeWallet", "feeWalletMultisig"]);
1490
1561
  var GROUPED_TOP_KEYS = new Set(["socials", "curve", "poolFee"]);
1491
1562
  function mcpKey(field) {
1492
1563
  const surface = field.surfaces.mcp;
@@ -6267,6 +6338,7 @@ var TOOL_NAMES = [
6267
6338
  "candle_get_plans",
6268
6339
  "candle_trade",
6269
6340
  "candle_launch_and_seed",
6341
+ "candle_atomic_launch_dry_run",
6270
6342
  "candle_swap",
6271
6343
  "candle_transfer",
6272
6344
  "candle_sweep",
@@ -6401,6 +6473,18 @@ function buildRequest(name, args, cfg) {
6401
6473
  init: { method: "POST", headers: jsonHeaders(apiKey), body: JSON.stringify(body) }
6402
6474
  };
6403
6475
  }
6476
+ case "candle_atomic_launch_dry_run": {
6477
+ const apiKey = requireApiKey2(cfg);
6478
+ const { payer, chain: _chain, buyAmount: _buyAmount, ...rest } = args;
6479
+ return {
6480
+ url: `${base2}/api/v1/launch/atomic/dry-run`,
6481
+ init: {
6482
+ method: "POST",
6483
+ headers: jsonHeaders(apiKey),
6484
+ body: JSON.stringify({ ...rest, chain: "solana", payer: payer ?? { type: "main" } })
6485
+ }
6486
+ };
6487
+ }
6404
6488
  case "candle_get_market": {
6405
6489
  const { chain, mint } = args;
6406
6490
  return {
@@ -6840,6 +6924,22 @@ var getFeesShape = {
6840
6924
  cursor: z9.string().optional().describe("The previous page's continueCursor, verbatim"),
6841
6925
  limit: z9.number().optional().describe("Tokens per page, 1 to 50 (default 20). Each one costs chain reads")
6842
6926
  };
6927
+ var atomicPayerShape = z9.union([
6928
+ z9.object({ type: z9.literal("main") }),
6929
+ z9.object({ type: z9.literal("linked"), linkedWalletId: z9.string().min(1) })
6930
+ ]);
6931
+ var atomicLaunchDryRunShape = (() => {
6932
+ const { buyAmount: _buyAmount, chain: _chain, ...launch } = launchTokenShape;
6933
+ return {
6934
+ ...launch,
6935
+ clientLaunchId: z9.string().optional().describe("Not used by a dry run; send the id you will launch with"),
6936
+ payer: atomicPayerShape.optional().describe("Who pays for the launch: {type:'main'} (default) or {type:'linked', linkedWalletId}"),
6937
+ firstBuys: z9.array(z9.object({
6938
+ payer: atomicPayerShape,
6939
+ amountRaw: z9.string().regex(/^[1-9][0-9]*$/).describe("Quote-asset raw units")
6940
+ })).min(1).max(4).describe("One to four first buys, each priced on the curve this launch would deploy")
6941
+ };
6942
+ })();
6843
6943
  var claimFeesShape = {
6844
6944
  mint: z9.string().describe("The launched token: a Solana mint or a Hood token address, as candle_get_fees lists it"),
6845
6945
  dryRun: z9.boolean().optional().describe("Check and read only. Sends nothing and writes nothing. Use it first to see what would be claimed")
@@ -7232,12 +7332,12 @@ MARKET_NOT_FOUND means Candle has no market for that token and this could not ru
7232
7332
  }, async (args) => callAndRelay("candle_claim_staking_reward", args, getConfig(), doFetch));
7233
7333
  register("candle_get_fees", {
7234
7334
  title: "Read the creator fees this account's tokens can pay",
7235
- description: "The tokens launched by the account's own wallets, with what each could pay now in creator fees " + "(raw units from direct chain reads) and `claimable: true` or the `reason` it is not. Reads only; " + "moves nothing. It returns no earned or paid-out totals. An unreadable token is marked, never " + "shown as zero. Paged: pass `continueCursor` back as `cursor`.",
7335
+ description: "The tokens launched by the account's own wallets, with what each could pay now in creator fees " + "(raw units from direct chain reads) and a `reason` saying who can claim: `claimable_by_key` on a " + "claimable Solana row, and otherwise why this key cannot (including `claimable_via_web_session` " + "and `fee_wallet_designated`, which name whose authority collects). Reads only; " + "moves nothing. It returns no earned or paid-out totals. An unreadable token is marked, never " + "shown as zero. Paged: pass `continueCursor` back as `cursor`.",
7236
7336
  inputSchema: getFeesShape
7237
7337
  }, async (args) => callAndRelay("candle_get_fees", args, getConfig(), doFetch));
7238
7338
  register("candle_claim_fees", {
7239
7339
  title: "Claim a token's creator fees",
7240
- description: "Collect one token's creator fees and pay them to the wallet fixed at launch. There is no destination " + "argument and the tool cannot send funds anywhere else. Candle signs with the embedded wallet, which " + "pays the network fee. Needs launch:write. " + "Call it with dryRun: true first; a real claim moves real funds into the recipient wallet, which may be " + "the wallet this agent trades from. Not idempotent by id: if the result is lost, read candle_get_fees " + "before claiming again.",
7340
+ description: "Collect one token's creator fees and pay them to the wallet fixed at launch. There is no destination " + "argument and the tool cannot send funds anywhere else. Candle signs with the embedded wallet, which " + "pays the network fee. A fee recipient that is a TEE wallet is refused here: claim it with the candle CLI " + "(`candle fees claim`). The dry run reports the same refusal (`claimable: false`, `reason: " + "wallet_not_signable`) and counts only what this tool could claim. Needs launch:write. " + "Call it with dryRun: true first; a real claim moves real funds into the recipient wallet, which may be " + "the wallet this agent trades from. Not idempotent by id: if the result is lost, read candle_get_fees " + "before claiming again.",
7241
7341
  inputSchema: claimFeesShape
7242
7342
  }, async (args) => callAndRelay("candle_claim_fees", args, getConfig(), doFetch));
7243
7343
  register("candle_get_wallets", {
@@ -7345,6 +7445,12 @@ MARKET_NOT_FOUND means Candle has no market for that token and this could not ru
7345
7445
  const result = await executeTrade(args, getConfig(), doFetch);
7346
7446
  return { content: [{ type: "text", text: result.text }], ...result.isError ? { isError: true } : {} };
7347
7447
  });
7448
+ register("candle_atomic_launch_dry_run", {
7449
+ title: "Dry-run an atomic Solana launch",
7450
+ description: "Check a Solana launch bundled with first buys and price each buy, without building anything. Runs the " + "same checks as the atomic build, in the same order (payers, Believer check, fee and spend limits, the " + "key's transaction cap), then returns the launch preview (curveTerms) and one fill per first buy: the " + "tokens it would receive and the floor the build would sign it at. Reads only; moves nothing, reserves " + "nothing, and the clientLaunchId stays unused. It does not check balances, the daily cap, or the " + "transaction's size, so the real launch can still refuse. Needs launch:write, swap:write and Pro or Max.",
7451
+ inputSchema: atomicLaunchDryRunShape,
7452
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
7453
+ }, async (args) => callAndRelay("candle_atomic_launch_dry_run", args, getConfig(), doFetch));
7348
7454
  register("candle_launch_and_seed", {
7349
7455
  title: "Launch a token and seed it",
7350
7456
  description: "Launch a new token from the account's embedded wallet, with an optional dev-buy seed, then " + "return the fresh market state and token links in one result. On solana a seed makes this " + (options.headlessSeed === true ? "the seed is a separate first-buy transaction in the same Jito bundle as the launch, so " + "both land or neither does. That works on every plan, Free included, and needs no " + "swap:write. On hood the seed is " : "the atomic launch: the launch and the seed are two transactions Candle signs and sends as " + "one Jito bundle, so both land or neither does. That needs Pro or Max (TIER_REQUIRED " + "otherwise) and swap:write on the key, and the result carries bundleId. On hood the seed is ") + "a best-effort follow-up. A launch with no seed works on every plan, Free included. MOVES " + "REAL FUNDS unless dryRun; dry-run first, which spends nothing. Seeds above the platform " + "dev-buy ceiling are rejected (DEV_BUY_TOO_HIGH): at most 0.5 SOL / 500 USDC / 2,000,000 " + "CNDL, or on an exp- curve 10% of the threshold when that is lower; the server holds the " + "creator's own seed to the effective ceiling, so launch with the largest devBuy it allows " + "and top up with candle_trade. " + LAUNCH_SHARED_SENTENCES + (imageDir ? IMAGE_PATH_DISCLOSURE : ""),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@candledottv/mcp",
3
- "version": "0.10.27",
3
+ "version": "0.10.29",
4
4
  "description": "MCP server for the Candle agent rail: launch tokens, read markets, report activity",
5
5
  "type": "module",
6
6
  "license": "MIT",