bykaranteli-mcp 0.35.0 → 0.35.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Notable changes to the `bykaranteli-mcp` package. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Dates are UTC and come from the git tag of each release (the version commit where no tag exists). The tool count is the number of tools the server registers in that release.
4
4
 
5
+ ## [0.35.1] - 2026-10-11
6
+
7
+ 67 tools.
8
+
9
+ ### Changed
10
+
11
+ - Every tool carries `annotations.title`, the same text as its top-level `title`: directory portals (the Claude Connectors Directory among them) read the display name there. The read-only, destructive, idempotent and open-world hints are unchanged.
12
+ - Descriptions name plans, not keys: depth and limits follow the account's plan whether the client signed in with OAuth or sends an account key (`get_liqmap`, `get_series`, `get_options_chain`, `get_solana_perps`, the account tools).
13
+ - `get_series` returns the newest 300 bars when neither `from` nor `limit` is given (Builder and higher plans received 1,000 by default, 64,700 characters for price); `limit` and `from`/`to` still return up to 5,000.
14
+
5
15
  ## [0.35.0] - 2026-10-11
6
16
 
7
17
  67 tools.
package/dist/tools.d.ts CHANGED
@@ -25,4 +25,4 @@ export type RegisterOptions = {
25
25
  * (the hosted endpoint). Takes precedence over apiKey when it returns one. */
26
26
  authorizationProvider?: () => string | undefined;
27
27
  };
28
- export declare function registerByKaranteliTools(server: McpServer, options?: RegisterOptions): void;
28
+ export declare function registerByKaranteliTools(target: McpServer, options?: RegisterOptions): void;
package/dist/tools.js CHANGED
@@ -6,7 +6,11 @@
6
6
  */
7
7
  import { z } from "zod/v4";
8
8
  import { buildProvenance, pageForApiPath } from "./provenance.js";
9
- export function registerByKaranteliTools(server, options) {
9
+ export function registerByKaranteliTools(target, options) {
10
+ const withTitle = (def) => def.title && !(def.annotations && "title" in def.annotations) ? { ...def, annotations: { ...(def.annotations ?? {}), title: def.title } } : def;
11
+ const server = {
12
+ registerTool: (name, def, handler) => target.registerTool.call(target, name, withTitle(def), handler),
13
+ };
10
14
  const BASE_URL = (options?.baseUrl ?? process.env.BYKARANTELI_BASE_URL ?? "https://bykaranteli.com").replace(/\/+$/, "");
11
15
  const PUBLIC_URL = (options?.publicUrl ?? process.env.BYKARANTELI_PUBLIC_URL ?? "https://bykaranteli.com").replace(/\/+$/, "");
12
16
  const USER_AGENT = `bykaranteli-mcp/${options?.version ?? "dev"} (+https://github.com/bykarantelicom/bykaranteli-mcp)`;
@@ -1152,7 +1156,7 @@ export function registerByKaranteliTools(server, options) {
1152
1156
  });
1153
1157
  server.registerTool("get_liqmap", {
1154
1158
  title: "LiqMap: estimated liquidation clusters with real prints overlaid",
1155
- description: "Call this when the user asks where liquidation clusters or liquidity pools sit for a perpetual, where leveraged longs/shorts would get liquidated, or for a liquidation heatmap reading. Returns the LiqMap snapshot for one symbol: modeled liquidation levels by price, zone aggregates and real liquidation prints from every liquidation venue ByKaranteli counts (listed on bykaranteli.com/coverage). Without an account key (or on the Free plan) the 24h view; with a Builder or higher key (BYKARANTELI_API_KEY) every timeframe from 1h to 30d. By default the 30 real levels nearest the price and the 30 newest real prints; pass detail=true for all of them.",
1159
+ description: "Call this when the user asks where liquidation clusters or liquidity pools sit for a perpetual, where leveraged longs/shorts would get liquidated, or for a liquidation heatmap reading. Returns the LiqMap snapshot for one symbol: modeled liquidation levels by price, zone aggregates and real liquidation prints from every liquidation venue ByKaranteli counts (listed on bykaranteli.com/coverage). On the Free plan the 24h view; on Builder and higher plans every timeframe from 1h to 30d. By default the 30 real levels nearest the price and the 30 newest real prints; pass detail=true for all of them.",
1156
1160
  inputSchema: {
1157
1161
  symbol: z
1158
1162
  .string()
@@ -1164,7 +1168,7 @@ export function registerByKaranteliTools(server, options) {
1164
1168
  timeframe: z
1165
1169
  .enum(["1h", "4h", "12h", "24h", "3d", "1w", "30d"])
1166
1170
  .optional()
1167
- .describe("Model window. Default 24h, the only one served without a Builder or higher key."),
1171
+ .describe("Model window. Default 24h, the only one on the Free plan; Builder and higher plans get every window."),
1168
1172
  detail: z.boolean().optional().describe("Optional. true: every real level and every real print (default false: the 30 nearest levels, the 30 newest prints)."),
1169
1173
  },
1170
1174
  annotations: READ_ONLY,
@@ -1484,12 +1488,12 @@ export function registerByKaranteliTools(server, options) {
1484
1488
  });
1485
1489
  server.registerTool("get_options_chain", {
1486
1490
  title: "Options chain hour by hour: open interest and IV per expiry and strike, the change over 1h and 24h, the ATM IV path",
1487
- description: "Call this when the user asks how the BTC or ETH option chain moved today or over the last day: open interest and mark IV per expiry and strike from ByKaranteli's own hourly capture of every listed venue, the change over the last hour and the last 24 hours, and the front expiry's ATM IV hour by hour. Anonymous depth lists the largest strikes; a key with member depth lists every strike. Recorded from 2026-09-30, so the first days carry a short history.",
1491
+ description: "Call this when the user asks how the BTC or ETH option chain moved today or over the last day: open interest and mark IV per expiry and strike from ByKaranteli's own hourly capture of every listed venue, the change over the last hour and the last 24 hours, and the front expiry's ATM IV hour by hour. The Free plan lists the largest strikes; Builder and higher plans list every strike. Recorded from 2026-09-30, so the first days carry a short history.",
1488
1492
  inputSchema: {
1489
1493
  currency: z.enum(["BTC", "ETH"]).optional().describe("BTC or ETH (default BTC)"),
1490
1494
  venue: z.enum(["all", "deribit", "bybit", "binance", "okx", "delta"]).optional().describe("One venue or all (default all)"),
1491
1495
  expiry: z.string().trim().toUpperCase().regex(/^\d{1,2}[A-Z]{3}\d{2}$/).optional().describe("Expiry as DDMONYY, e.g. 31OCT26 (default: every expiry)"),
1492
- strikes: z.enum(["top", "all"]).optional().describe("top (largest strikes) or all (member depth)"),
1496
+ strikes: z.enum(["top", "all"]).optional().describe("top (largest strikes) or all (Builder and higher plans)"),
1493
1497
  },
1494
1498
  annotations: READ_ONLY,
1495
1499
  }, async ({ currency, venue, expiry, strikes }) => {
@@ -1588,7 +1592,7 @@ export function registerByKaranteliTools(server, options) {
1588
1592
  });
1589
1593
  server.registerTool("get_solana_perps", {
1590
1594
  title: "Solana Perps board: open interest, 24h volume and hourly rates across six Solana perpetual venues (Jupiter, Pacifica, Phoenix, GM Trade, Velocity, Bullet)",
1591
- description: "Call this when the user asks about perpetuals on Solana as a whole, which Solana perp DEX has the most open interest or volume, a market on Pacifica, Phoenix, GM Trade (GMX on Solana), Velocity (the Drift relaunch) or Bullet (funding, open interest, 24h volume, mark), or how Jupiter compares with the order-book venues. Returns the board read every 10 minutes: per-venue totals (one-sided open interest, both sides on pool venues, 24h volume, market count, median hourly rate, as_of), every market of every venue largest first with instrument type (perpetual, equity, index, commodity, fx), and optional hourly history of one market on any venue but Jupiter (7 days free, 30 with member depth; Jupiter history is get_jupiter_perps). Without venue, the 30 largest markets; pass venue, or limit (up to 300) for more.",
1595
+ description: "Call this when the user asks about perpetuals on Solana as a whole, which Solana perp DEX has the most open interest or volume, a market on Pacifica, Phoenix, GM Trade (GMX on Solana), Velocity (the Drift relaunch) or Bullet (funding, open interest, 24h volume, mark), or how Jupiter compares with the order-book venues. Returns the board read every 10 minutes: per-venue totals (one-sided open interest, both sides on pool venues, 24h volume, market count, median hourly rate, as_of), every market of every venue largest first with instrument type (perpetual, equity, index, commodity, fx), and optional hourly history of one market on any venue but Jupiter (7 days on the Free plan, 30 on Builder and higher plans; Jupiter history is get_jupiter_perps). Without venue, the 30 largest markets; pass venue, or limit (up to 300) for more.",
1592
1596
  inputSchema: {
1593
1597
  venue: z.string().trim().toLowerCase().regex(/^(jupiter|pacifica|phoenix|gmtrade|velocity|bullet)$/).optional().describe("Venue filter: jupiter, pacifica, phoenix, gmtrade, velocity or bullet"),
1594
1598
  /* Passed as typed: Pacifica and Phoenix list mixed-case markets (kBONK, kPEPE, kSHIB) and the route matches the
@@ -1779,7 +1783,7 @@ export function registerByKaranteliTools(server, options) {
1779
1783
  /* ---- 0.31.0: recorded series, alert text, alert recipes, watchlists ---- */
1780
1784
  server.registerTool("get_series", {
1781
1785
  title: "Recorded series: bars or points of one metric for one perpetual (price, OI, funding, CVD, liquidations, long/short, RSI and more)",
1782
- description: `Call this when the user wants the history of one recorded metric for one perpetual as a time series: price candles, volume, perp or spot CVD, open interest, funding (one venue, or OI-weighted across every venue as funding_agg), liquidations, long/short ratios, RSI, the Coinbase premium, US spot ETF flows, borrow rates or Hyperliquid whale net flow, for charting, backtesting or "what did X do over the last N days". Returns the /api/series answer (points as [t, v], or [t, o, h, l, c, v] for price, with unit, kind, source and source_kind, the bars served and whether member depth applied) plus provenance. metric is one of: ${SERIES_METRIC_KEYS.join(", ")} (unit, finest period and venue support of each: https://bykaranteli.com/api/series/metrics). Public depth serves fewer bars and no bars under 15 minutes (1m, 3m, 5m, 10m); a Builder key and above get member depth; the bar limits are in the same list. The answer names the venue it was read from (venue) and every venue a market-wide series sums (venues). Pass from and to (ISO) for a window, or limit for the newest bars.`,
1786
+ description: `Call this when the user wants the history of one recorded metric for one perpetual as a time series: price candles, volume, perp or spot CVD, open interest, funding (one venue, or OI-weighted across every venue as funding_agg), liquidations, long/short ratios, RSI, the Coinbase premium, US spot ETF flows, borrow rates or Hyperliquid whale net flow, for charting, backtesting or "what did X do over the last N days". Returns the /api/series answer (points as [t, v], or [t, o, h, l, c, v] for price, with unit, kind, source and source_kind, the bars served and whether member depth applied) plus provenance. metric is one of: ${SERIES_METRIC_KEYS.join(", ")} (unit, finest period and venue support of each: https://bykaranteli.com/api/series/metrics). The Free plan gets public depth: fewer bars and no bars under 15 minutes (1m, 3m, 5m, 10m); Builder and higher plans get member depth; the bar limits are in the same list. The answer names the venue it was read from (venue) and every venue a market-wide series sums (venues). Without from or limit, the newest 300 bars; pass from and to (ISO) for a window, or limit for more of the newest bars.`,
1783
1787
  inputSchema: {
1784
1788
  metric: z.string().describe("string, metric key, e.g. price, oi, funding, liquidations (list: /api/series/metrics)"),
1785
1789
  symbol: z.string().optional().describe("string, optional Binance USDT-M perp or coin, e.g. BTCUSDT or BTC (default BTCUSDT)"),
@@ -1787,7 +1791,7 @@ export function registerByKaranteliTools(server, options) {
1787
1791
  venue: z.string().optional().describe("string, optional venue id for price, oi, funding or borrow, e.g. okx (default binance)"),
1788
1792
  from: z.string().optional().describe("string, optional ISO start, e.g. 2026-09-01T00:00:00Z"),
1789
1793
  to: z.string().optional().describe("string, optional ISO end (default now)"),
1790
- limit: z.number().optional().describe(`number, optional newest bars, 10..${SERIES_MEMBER_BAR_LIMIT}; the key's depth caps it`),
1794
+ limit: z.number().optional().describe(`number, optional newest bars, 10..${SERIES_MEMBER_BAR_LIMIT}; the plan's depth caps it (default 300 without from)`),
1791
1795
  },
1792
1796
  annotations: READ_ONLY,
1793
1797
  }, async (args = {}) => {
@@ -1809,6 +1813,9 @@ export function registerByKaranteliTools(server, options) {
1809
1813
  const bars = from ? Math.ceil((end.getTime() - from.getTime()) / PERIOD_MS[period]) : undefined;
1810
1814
  if (bars !== undefined)
1811
1815
  limit = Math.min(limit ?? bars, bars);
1816
+ /* 0.35.1: the newest 300 bars when neither from nor limit is given (the route gives members 1000 by default). */
1817
+ if (limit === undefined)
1818
+ limit = 300;
1812
1819
  if (limit !== undefined)
1813
1820
  limit = Math.max(10, Math.min(SERIES_MEMBER_BAR_LIMIT, limit));
1814
1821
  const q = new URLSearchParams({ metric, symbol, period });
@@ -1839,7 +1846,7 @@ export function registerByKaranteliTools(server, options) {
1839
1846
  });
1840
1847
  server.registerTool("list_alert_recipes", {
1841
1848
  title: "Your alert recipes: every alert on your account with its conditions, scope, channels and when it last fired",
1842
- description: "Call this when the user asks which alerts they have, whether an alert fired, or before deleting or changing one. Returns the account's alert recipes (id, name, scope, symbols, conditions, cooldown in hours, enabled, last fired, fire count, channels). Needs the account key; reads nothing but this account.",
1849
+ description: "Call this when the user asks which alerts they have, whether an alert fired, or before deleting or changing one. Returns the account's alert recipes (id, name, scope, symbols, conditions, cooldown in hours, enabled, last fired, fire count, channels). Needs a signed-in account (OAuth sign-in or account key); reads nothing but this account.",
1843
1850
  inputSchema: {},
1844
1851
  annotations: ACCOUNT_READ,
1845
1852
  }, async () => {
@@ -1848,7 +1855,7 @@ export function registerByKaranteliTools(server, options) {
1848
1855
  });
1849
1856
  server.registerTool("create_alert_recipe", {
1850
1857
  title: "Create an alert recipe (writes to your account)",
1851
- description: `Call this when the user asks to be alerted when a metric crosses a threshold and has agreed to the exact condition (parse_alert_text turns their words into one). Saves an alert recipe on the account: it fires when every condition holds, delivers by Telegram first with email as fallback unless channels says otherwise, and waits cooldown_hours before it fires again for the same symbol. field is one of: ${RECIPE_FIELD_KEYS.join(", ")}; op is one of ${RECIPE_OPS.join(" ")}; percent fields take percent values (0.05 means 0.05%). Pass field, op and threshold for one condition, or conditions for up to ${RECIPE_LIMITS.MAX_CONDITIONS}. scope: watchlist (default), any, or symbols with symbols. The plan sets how many recipes an account keeps; past it the tool answers with the limit. Writes are rate limited per key and each one is recorded on the account.`,
1858
+ description: `Call this when the user asks to be alerted when a metric crosses a threshold and has agreed to the exact condition (parse_alert_text turns their words into one). Saves an alert recipe on the account: it fires when every condition holds, delivers by Telegram first with email as fallback unless channels says otherwise, and waits cooldown_hours before it fires again for the same symbol. field is one of: ${RECIPE_FIELD_KEYS.join(", ")}; op is one of ${RECIPE_OPS.join(" ")}; percent fields take percent values (0.05 means 0.05%). Pass field, op and threshold for one condition, or conditions for up to ${RECIPE_LIMITS.MAX_CONDITIONS}. scope: watchlist (default), any, or symbols with symbols. The plan sets how many recipes an account keeps; past it the tool answers with the limit. Writes are rate limited per connection (sign-in or key) and each one is recorded on the account.`,
1852
1859
  inputSchema: {
1853
1860
  field: z.string().optional().describe("string, one condition's metric, e.g. funding_rate_pct"),
1854
1861
  op: z.enum(RECIPE_OPS).optional().describe(`string, one condition's comparison: ${RECIPE_OPS.join(" | ")}`),
@@ -1910,7 +1917,7 @@ export function registerByKaranteliTools(server, options) {
1910
1917
  });
1911
1918
  server.registerTool("delete_alert_recipe", {
1912
1919
  title: "Delete one of your alert recipes (writes to your account)",
1913
- description: "Call this when the user asks to remove an alert. Deletes the alert recipe with this id from the account (list_alert_recipes shows the ids); an id that is not one of the account's recipes changes nothing and says so. Writes are rate limited per key and each one is recorded on the account.",
1920
+ description: "Call this when the user asks to remove an alert. Deletes the alert recipe with this id from the account (list_alert_recipes shows the ids); an id that is not one of the account's recipes changes nothing and says so. Writes are rate limited per connection (sign-in or key) and each one is recorded on the account.",
1914
1921
  inputSchema: {
1915
1922
  id: z.string().describe("string, the recipe id from list_alert_recipes"),
1916
1923
  },
@@ -1928,7 +1935,7 @@ export function registerByKaranteliTools(server, options) {
1928
1935
  });
1929
1936
  server.registerTool("list_watchlists", {
1930
1937
  title: "Your watchlists and the symbols on each",
1931
- description: "Call this when the user asks what is on their watchlist, which lists they have, or before adding or removing a symbol. Returns the account's watchlists (id, name, symbol count) and, unless include_symbols is false, the symbols on each list in order. Needs the account key; reads nothing but this account.",
1938
+ description: "Call this when the user asks what is on their watchlist, which lists they have, or before adding or removing a symbol. Returns the account's watchlists (id, name, symbol count) and, unless include_symbols is false, the symbols on each list in order. Needs a signed-in account (OAuth sign-in or account key); reads nothing but this account.",
1932
1939
  inputSchema: {
1933
1940
  include_symbols: z.boolean().optional().describe("boolean, optional: include each list's symbols (default true)"),
1934
1941
  },
@@ -1951,7 +1958,7 @@ export function registerByKaranteliTools(server, options) {
1951
1958
  });
1952
1959
  server.registerTool("add_watchlist_symbol", {
1953
1960
  title: "Add a symbol to your watchlist (writes to your account)",
1954
- description: "Call this when the user asks to watch, follow or add a coin to their watchlist. Adds the symbol to the list named by watchlist_id, else to the default list (or the only list the account has); a symbol already on the list stays once. Returns the list's symbols after the change. Writes are rate limited per key and each one is recorded on the account.",
1961
+ description: "Call this when the user asks to watch, follow or add a coin to their watchlist. Adds the symbol to the list named by watchlist_id, else to the default list (or the only list the account has); a symbol already on the list stays once. Returns the list's symbols after the change. Writes are rate limited per connection (sign-in or key) and each one is recorded on the account.",
1955
1962
  inputSchema: {
1956
1963
  symbol: z.string().describe("string, a Binance USDT-M perp or coin, e.g. SOLUSDT or SOL"),
1957
1964
  watchlist_id: z.string().optional().describe("string, optional list id from list_watchlists (default: the default list)"),
@@ -1971,7 +1978,7 @@ export function registerByKaranteliTools(server, options) {
1971
1978
  });
1972
1979
  server.registerTool("remove_watchlist_symbol", {
1973
1980
  title: "Remove a symbol from your watchlist (writes to your account)",
1974
- description: "Call this when the user asks to stop watching a coin or remove it from their watchlist. Removes the symbol from the list named by watchlist_id, else from the default list (or the only list the account has); a symbol that is not on the list changes nothing. Returns the list's symbols after the change. Writes are rate limited per key and each one is recorded on the account.",
1981
+ description: "Call this when the user asks to stop watching a coin or remove it from their watchlist. Removes the symbol from the list named by watchlist_id, else from the default list (or the only list the account has); a symbol that is not on the list changes nothing. Returns the list's symbols after the change. Writes are rate limited per connection (sign-in or key) and each one is recorded on the account.",
1975
1982
  inputSchema: {
1976
1983
  symbol: z.string().describe("string, the symbol to remove, e.g. SOLUSDT or SOL"),
1977
1984
  watchlist_id: z.string().optional().describe("string, optional list id from list_watchlists (default: the default list)"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bykaranteli-mcp",
3
- "version": "0.35.0",
3
+ "version": "0.35.1",
4
4
  "description": "MCP server for live crypto derivatives data from bykaranteli.com: funding rates, funding arbitrage, open interest pressure, liquidations, options, ETF flows, Fear & Greed and BTC dominance. 67 read-only and account tools (the alert and watchlist tools act on your own account), free account key, paid depth via plans or x402.",
5
5
  "type": "module",
6
6
  "bin": {