@candledottv/mcp 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +25 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -106,7 +106,7 @@ function percentOfBalance(balanceRaw, percent) {
|
|
|
106
106
|
import { randomUUID } from "node:crypto";
|
|
107
107
|
|
|
108
108
|
// src/version.ts
|
|
109
|
-
var SERVER_VERSION = "0.
|
|
109
|
+
var SERVER_VERSION = "0.9.0";
|
|
110
110
|
|
|
111
111
|
// src/update-notice.ts
|
|
112
112
|
var PLAIN_VERSION = /^\d+\.\d+\.\d+$/;
|
|
@@ -315,7 +315,8 @@ async function executeTrade(args, cfg, doFetch) {
|
|
|
315
315
|
amountRaw,
|
|
316
316
|
payer: { type: "main" },
|
|
317
317
|
...args.quoteAsset !== undefined ? { quoteAsset: args.quoteAsset } : {},
|
|
318
|
-
...args.maxSlippageBps !== undefined ? { maxSlippageBps: args.maxSlippageBps } : {}
|
|
318
|
+
...args.maxSlippageBps !== undefined ? { maxSlippageBps: args.maxSlippageBps } : {},
|
|
319
|
+
...args.paper === true ? { paper: true } : {}
|
|
319
320
|
}, doFetch);
|
|
320
321
|
if ("thrown" in posted)
|
|
321
322
|
return transportError("clientTradeId", clientTradeId, posted.thrown);
|
|
@@ -576,8 +577,15 @@ function buildRequest(name, args, cfg) {
|
|
|
576
577
|
};
|
|
577
578
|
}
|
|
578
579
|
case "candle_get_feed": {
|
|
579
|
-
const { bucket, chain } = args;
|
|
580
|
-
const query = new URLSearchParams({
|
|
580
|
+
const { bucket, chain, where, sort, fields, limit } = args;
|
|
581
|
+
const query = new URLSearchParams({
|
|
582
|
+
bucket,
|
|
583
|
+
...chain ? { chain } : {},
|
|
584
|
+
...where ? { where } : {},
|
|
585
|
+
...sort ? { sort } : {},
|
|
586
|
+
...fields ? { fields } : {},
|
|
587
|
+
...limit ? { limit } : {}
|
|
588
|
+
});
|
|
581
589
|
return {
|
|
582
590
|
url: `${base2}/api/v1/markets/feed?${query.toString()}`,
|
|
583
591
|
init: { method: "GET", headers: jsonHeaders() }
|
|
@@ -696,7 +704,11 @@ var tokenForensicsShape = {
|
|
|
696
704
|
};
|
|
697
705
|
var getFeedShape = {
|
|
698
706
|
bucket: z.enum(["new", "graduated", "onfire", "bluechip"]),
|
|
699
|
-
chain: z.string().optional().describe("Optional chain filter")
|
|
707
|
+
chain: z.string().optional().describe("Optional chain filter"),
|
|
708
|
+
where: z.string().optional().describe('JSON filter, e.g. {"marketCap":{"lt":150000},"liquidityUsd":{"gte":25000},"mintAuthorityDisabled":{"eq":true}}. ' + "Comparators: eq, ne, lt, lte, gt, gte, present. An ABSENT field satisfies none of them except " + "present:false, so a filter for mintAuthorityDisabled eq true returns only tokens that actually say " + "true, never ones where the flag is simply missing. Use present:false to find the tokens with no data."),
|
|
709
|
+
sort: z.string().optional().describe('Sort as "field" or "field:asc" / "field:desc". A bare field means desc.'),
|
|
710
|
+
fields: z.string().optional().describe("Comma-separated fields to return, e.g. symbol,marketCap,liquidityUsd. chain, address and symbol always " + "ride along. Cuts a 135KB response to a couple of KB."),
|
|
711
|
+
limit: z.string().optional().describe("Max rows to return, 1-200.")
|
|
700
712
|
};
|
|
701
713
|
var reportActivityShape = {
|
|
702
714
|
chain: z.string().describe('"solana" or "hood"'),
|
|
@@ -741,7 +753,8 @@ var tradeShape = {
|
|
|
741
753
|
percent: z.number().optional().describe("Sells only: sell this percent (integer 1-100) of the wallet's holding, on either chain."),
|
|
742
754
|
quoteAsset: z.string().optional().describe('What the wallet spends on a buy or receives on a sell: "sol", "usdc" or "cndl" on Solana, ' + '"eth" or "usdg" on Hood. Safe to pass through from candle_quote. On Solana it applies only ' + "to an arbitrary mint Candle never launched (Pro/Max) and is ignored for a Candle token, " + "whose quote comes from the token itself. On Hood it is the settlement asset of a DEX " + "trade; a USDG buy adds an approval transaction an ETH buy does not. It is not the route: " + "the cheapest path to the asset is chosen separately. Defaults to sol / ETH settlement."),
|
|
743
755
|
maxSlippageBps: z.number().optional().describe("Max slippage in basis points; API default applies when omitted"),
|
|
744
|
-
clientTradeId: z.string().optional().describe("Idempotency key. Auto-generated when omitted and echoed in the result. Retrying with the " + "SAME id is safe (idempotent replay); a new id is a SECOND trade.")
|
|
756
|
+
clientTradeId: z.string().optional().describe("Idempotency key. Auto-generated when omitted and echoed in the result. Retrying with the " + "SAME id is safe (idempotent replay); a new id is a SECOND trade."),
|
|
757
|
+
paper: z.boolean().optional().describe("Rehearse instead of trading. The request passes every admission rule a live trade passes " + "-- the same planner, spend gate, key cap and loss limits -- and records the quote, but " + "nothing is ever broadcast and no funds move. Use it to check that a strategy is admitted " + "before risking anything on it. A paper fill is optimistic by construction: it books the " + "quoted price, so the gap between a paper arm and a live one IS the execution cost.")
|
|
745
758
|
};
|
|
746
759
|
var { buyAmount: _rawBuyAmount, ...seedableLaunchShape } = launchTokenShape;
|
|
747
760
|
var launchAndSeedShape = {
|
|
@@ -786,14 +799,16 @@ function registerTools(server, env = process.env) {
|
|
|
786
799
|
title: "Token forensics",
|
|
787
800
|
description: `Gate a buy before making it: deployer history, who bought in the deploy window (the creator's own wallets are marked disclosed; strangers in the same slot are the bundle signal), holder concentration, and a risk tier (LOW/MODERATE/HIGH/CRITICAL) with per-factor reasons. Every measurement carries a coverage note -- 'unavailable' is not 'clean'. No key needed.
|
|
788
801
|
|
|
789
|
-
MARKET_NOT_FOUND means Candle has no market for that token and this could not run. That is also not 'clean': report that you could not check it, rather than reporting the token as safe.`,
|
|
802
|
+
MARKET_NOT_FOUND means Candle has no market for that token and this could not run. That is also not 'clean': report that you could not check it, rather than reporting the token as safe. That refusal now carries error.coverage -- covered:false, a reason ('external_launchpad' when the token launched somewhere else, 'unknown_mint' when nobody has indexed it), the launchpad when known, and every check that consequently did not run. Read it instead of guessing. Most of the feed answers this way.`,
|
|
790
803
|
inputSchema: tokenForensicsShape
|
|
791
804
|
}, async (args) => callAndRelay("candle_token_forensics", args, cfg));
|
|
792
805
|
register("candle_get_feed", {
|
|
793
806
|
title: "Get a token feed",
|
|
794
807
|
description: "Read one of the trade page's public feeds: new, graduated, onfire, or bluechip. Reads " + `only; moves nothing. No key needed. Start here when nobody has named a token.
|
|
795
808
|
|
|
796
|
-
` + "This indexes the WIDER market, not just Candle's own launches, so rows carry a " + "`launchpad` (pump.fun, pons.family, ...). A row appearing here does NOT mean Candle " + "has a market for it: candle_get_market and candle_token_forensics can legitimately " +
|
|
809
|
+
` + "This indexes the WIDER market, not just Candle's own launches, so rows carry a " + "`launchpad` (pump.fun, pons.family, ...). A row appearing here does NOT mean Candle " + "has a market for it: candle_get_market and candle_token_forensics can legitimately " + `answer MARKET_NOT_FOUND for a mint this returned.
|
|
810
|
+
|
|
811
|
+
` + "Filter, sort and pick fields SERVER-SIDE rather than reading the whole feed: an " + "unfiltered response is around 135KB and will not fit in a tool result. See `where`, " + "`sort` and `fields`.\n\n" + "One rule to know before screening on safety: a missing field is NOT a false one. " + "mintAuthorityDisabled and freezeAuthorityDisabled are absent on a real share of rows, " + "and absent means nobody checked, not that the authority is disabled. `where` never lets " + 'an absent field satisfy a comparison, so {"mintAuthorityDisabled":{"eq":true}} returns ' + "only tokens that actually say so.",
|
|
797
812
|
inputSchema: getFeedShape
|
|
798
813
|
}, async (args) => callAndRelay("candle_get_feed", args, cfg));
|
|
799
814
|
register("candle_report_activity", {
|
|
@@ -898,6 +913,8 @@ MARKET_NOT_FOUND means Candle has no market for that token and this could not ru
|
|
|
898
913
|
|
|
899
914
|
` + "Arguments: `mint` and `side` are required. Amounts are DECIMAL, never raw base units " + '(amount: "0.5", not lamports). Omitting the amount on a sell sells the whole ' + `position.
|
|
900
915
|
|
|
916
|
+
` + "Pass `paper: true` to rehearse: every admission rule runs and the quote is recorded, but " + "nothing broadcasts and no funds move. Do this before the first live trade of a new " + `strategy, and whenever you are unsure a trade would be admitted at all.
|
|
917
|
+
|
|
901
918
|
` + `After the call:
|
|
902
919
|
` + "- A timeout is not a failure. Retry with the SAME clientTradeId from the result -- it " + `coalesces the duplicate. A NEW id is a SECOND trade, and that is how you double-spend.
|
|
903
920
|
` + "- If you no longer hold the result, do not re-send to find out what happened. Ask " + "candle_get_operation with the clientTradeId; a 404 there means the trade never reached " + "the rail and nothing moved.",
|