bykaranteli-mcp 0.35.1 → 0.36.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 +19 -0
- package/README.md +3 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +52 -8
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
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.36.1] - 2026-10-21
|
|
6
|
+
|
|
7
|
+
68 tools.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- `get_series`: the description and the `to` parameter state the public window rule the route enforces since 2026-10-20: a `to` before the newest 300 bars of the period needs member depth (Builder and higher plans) and answers 403 `history_member_only` otherwise, except daily and coarser price bars, which stay open to every plan. The handler is unchanged: the route's own sentence reaches the model as the tool error.
|
|
12
|
+
- `list_alert_recipes`: the description names `reachable` (whether a delivery channel is set up for the recipe) and `channels_available` (the delivery channels the account has connected), both in the answer since the web release of 2026-10-18.
|
|
13
|
+
- README: the 401 causes paragraph (`x-byk-mcp-auth`: `key_required`, `key_unusable`, `key_wrong_type`, `key_unrecognised`; the `WWW-Authenticate` challenge starts the OAuth sign-in).
|
|
14
|
+
- Short default answers, two more (the 0.35.0 rule; the package smoke test caught both at 46,000 and 47,000 characters): `get_factor_board` returns the first 40 rows without `limit` (`rows_total`, `rows_returned` and `trimmed` as on the other boards; `limit` up to 400 for the whole board), and `get_desk_notes` returns the newest 25 notes of the last 24 hours without arguments (`count` says how many came back; `limit` up to 100; `day` or `since` keep the route's 50).
|
|
15
|
+
|
|
16
|
+
## [0.36.0] - 2026-10-15
|
|
17
|
+
|
|
18
|
+
68 tools.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `get_desk_notes`: the desk notes, short dated observations the ByKaranteli desk writer publishes from the platform's own recorded derivatives data, newest first, with publish time, news value, the board each reads from, the coins it names and a permanent URL; one UTC day (`day`), a window of up to 7 days (`since`), one card type (`type`), the text in zh, ru or ko (`lang`).
|
|
23
|
+
|
|
5
24
|
## [0.35.1] - 2026-10-11
|
|
6
25
|
|
|
7
26
|
67 tools.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
MCP (Model Context Protocol) server for **live crypto derivatives data**: funding rates, cross-exchange funding arbitrage, open interest pressure, liquidations, options, ETF flows, Fear & Greed and BTC dominance.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
68 read-only and account tools over the public JSON API of [bykaranteli.com](https://bykaranteli.com/developers): the market data tools only read, and the alert and watchlist tools act on your own account through your key ([Account tools](#account-tools-alerts-and-watchlist)). Since 2026-09-10 the API asks programs for an account key: a **free key** comes with any verified account at <https://bykaranteli.com/dashboard/api> (30 requests a minute and 15,000 a month, public depth), and the Builder, Business and Scale plans raise the rate and the monthly fair use and unlock member depth (LiqMap on seven timeframes, 5-minute series) and a monthly allowance of x402 catalog calls within each plan's history window ([Plans and paid depth](#plans-and-paid-depth)). Set it as `BYKARANTELI_API_KEY`. Data covers Binance USDT-M perpetuals; funding arbitrage, liquidations, order book depth, options, positioning and insurance funds add the other venues each board lists on bykaranteli.com/coverage.
|
|
6
6
|
|
|
7
7
|
## Hosted endpoint (no install)
|
|
8
8
|
|
|
@@ -108,6 +108,7 @@ Requires Node.js 18 or newer.
|
|
|
108
108
|
| `get_orderbook_depth` | "Where is the biggest BTC bid wall? How deep is ETH within 2% on Coinbase vs Binance?" |
|
|
109
109
|
| `get_jupiter_perps` | "How much long vs short OI is on Jupiter SOL perps? Who topped Jupiter this week? What is the JLP APR?" |
|
|
110
110
|
| `get_solana_perps` | "Which Solana perp DEX has the most open interest? What is Pacifica's BTC funding and 24h volume? Phoenix SOL open interest? GM Trade versus Jupiter?" |
|
|
111
|
+
| `get_desk_notes` | "What did the desk observe in the derivatives data today? What happened on 14 October? Give me a dated, quotable sentence with its number and time." |
|
|
111
112
|
| `get_turkey_premium` | "What do lira buyers pay for bitcoin above the world price? What is the Turkey Premium Index and its score right now? Which Turkish exchange is dearest? What is USDT/TRY against the official rate?" |
|
|
112
113
|
| `get_data_proof` | "Can I verify a ByKaranteli number was not changed later? Show the on-chain proof for BTC funding right now. Which Solana transaction sealed the newest epoch?" |
|
|
113
114
|
| `get_cycle_indicators` | "Has the Pi Cycle crossed? Mayer Multiple and Puell today?" |
|
|
@@ -147,6 +148,7 @@ These tools read and change your own ByKaranteli account with the same key: the
|
|
|
147
148
|
- How many recipes an account keeps follows its plan; past it, `create_alert_recipe` answers with the limit instead of saving.
|
|
148
149
|
- Every call counts on the key's plan like any other request; writes are also rate limited per key, and each write is recorded on the account with the key that made it.
|
|
149
150
|
- Recipes and watchlist changes show up at once on <https://bykaranteli.com/dashboard/alerts> and <https://bykaranteli.com/dashboard/watchlist>.
|
|
151
|
+
- If a tool call answers 401, the body's `error_description` says what to send and the `x-byk-mcp-auth` header names the cause: `key_required` (no credential at all), `key_unusable` (a header or the address carried no key: the `bk_...` placeholder, an unset variable, a non-Bearer scheme, an OAuth token of the wrong shape), `key_wrong_type` (a prepaid `bk_live_` key, which pays per call on /api/x402/* and does not open the MCP) or `key_unrecognised` (mistyped, expired or revoked). The `WWW-Authenticate` challenge starts the OAuth sign-in in clients that support it. This package forwards the REST body verbatim, so the same sentence reaches the model over stdio.
|
|
150
152
|
|
|
151
153
|
## Configuration
|
|
152
154
|
|
package/dist/tools.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tool registrations for the ByKaranteli MCP server, transport-agnostic.
|
|
3
3
|
* The stdio bin (index.ts) and the hosted Streamable HTTP endpoint on
|
|
4
4
|
* bykaranteli.com both call registerByKaranteliTools on their own server
|
|
5
|
-
* instance, so
|
|
5
|
+
* instance, so every tool has exactly one definition.
|
|
6
6
|
*/
|
|
7
7
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
export type RegisterOptions = {
|
package/dist/tools.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tool registrations for the ByKaranteli MCP server, transport-agnostic.
|
|
3
3
|
* The stdio bin (index.ts) and the hosted Streamable HTTP endpoint on
|
|
4
4
|
* bykaranteli.com both call registerByKaranteliTools on their own server
|
|
5
|
-
* instance, so
|
|
5
|
+
* instance, so every tool has exactly one definition.
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod/v4";
|
|
8
8
|
import { buildProvenance, pageForApiPath } from "./provenance.js";
|
|
@@ -771,12 +771,18 @@ export function registerByKaranteliTools(target, options) {
|
|
|
771
771
|
});
|
|
772
772
|
server.registerTool("get_factor_board", {
|
|
773
773
|
title: "Factor board: what followed days like today across recorded metrics",
|
|
774
|
-
description: "Call this when the user asks which indicators currently sit in an unusual band, whether a metric's current level historically preceded BTC moves, or for a cross-metric conditional overview. Returns every recorded metric in its historical band with the median 7-day BTC move that followed versus the base rate, with an n >= 30 gate; distributions, not forecasts.",
|
|
775
|
-
inputSchema: {
|
|
774
|
+
description: "Call this when the user asks which indicators currently sit in an unusual band, whether a metric's current level historically preceded BTC moves, or for a cross-metric conditional overview. Returns every recorded metric in its historical band with the median 7-day BTC move that followed versus the base rate, with an n >= 30 gate; distributions, not forecasts. Without limit the first 40 rows in the board's own order (rows_total counts every row, trimmed names the cut); pass limit up to 400 for the whole board.",
|
|
775
|
+
inputSchema: {
|
|
776
|
+
limit: z.coerce.number().int().min(1).max(400).optional().describe("Optional. Rows to return, 1..400 (default 40)"),
|
|
777
|
+
},
|
|
776
778
|
annotations: READ_ONLY,
|
|
777
|
-
}, async () => {
|
|
779
|
+
}, async ({ limit }) => {
|
|
778
780
|
try {
|
|
779
|
-
|
|
781
|
+
/* 0.36.1: 79 rows of about 600 characters answered 46,000 characters without arguments; a first page of 40. */
|
|
782
|
+
const n = limit ?? 40;
|
|
783
|
+
return ok(compact(await fetchJson("/api/public/factors"), "/api/public/factors", (rec, t) => {
|
|
784
|
+
rec.rows = t.head(rec.rows, n, "rows", "pass limit up to 400");
|
|
785
|
+
}, "rows"));
|
|
780
786
|
}
|
|
781
787
|
catch (err) {
|
|
782
788
|
return fail(err);
|
|
@@ -1377,6 +1383,41 @@ export function registerByKaranteliTools(target, options) {
|
|
|
1377
1383
|
return fail(err);
|
|
1378
1384
|
}
|
|
1379
1385
|
});
|
|
1386
|
+
server.registerTool("get_desk_notes", {
|
|
1387
|
+
title: "Desk notes: short dated observations the ByKaranteli desk wrote from its own recorded derivatives data",
|
|
1388
|
+
description: "Call this when the user asks what happened in crypto derivatives today or on a date, what the desk observed, what moved in funding, open interest, liquidations, options, ETF flows or exchange premiums, or wants a dated, quotable sentence with its number and time. Returns the desk's notes newest first: each is one observation written by the desk writer (an AI model) from the platform's own recorded data and checked against it before publishing, with its publish time in UTC, the card's data time, the desk's 0 to 10 news value, the board it read from, the coins it names and its permanent URL. Information about the data, never advice. Default the newest 25 notes of the last 24 hours (count says how many came back; limit up to 100 for more); pass day for one UTC day, since for a window up to 7 days back (50 notes unless limit says otherwise), type for one card type (funding-arb, liqmap-btc, event-liq-burst, ...), lang for zh, ru or ko text.",
|
|
1389
|
+
inputSchema: {
|
|
1390
|
+
day: z.string().trim().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("One UTC day, YYYY-MM-DD"),
|
|
1391
|
+
since: z.string().trim().max(40).optional().describe("ISO time; notes published at or after it, at most 7 days back (ignored with day)"),
|
|
1392
|
+
type: z.string().trim().toLowerCase().regex(/^[a-z0-9][a-z0-9-]{0,60}$/).optional().describe("One card type, e.g. funding-arb, liqmap-btc, event-liq-burst"),
|
|
1393
|
+
lang: z.enum(["en", "zh", "ru", "ko"]).optional().describe("Text language (default en); a note without that translation comes back in English"),
|
|
1394
|
+
limit: z.number().int().min(1).max(100).optional().describe("Notes to return, 1..100 (default 25 for the last 24 hours, 50 with day or since)"),
|
|
1395
|
+
},
|
|
1396
|
+
annotations: READ_ONLY,
|
|
1397
|
+
}, async ({ day, since, type, lang, limit }) => {
|
|
1398
|
+
try {
|
|
1399
|
+
const q = new URLSearchParams();
|
|
1400
|
+
if (day)
|
|
1401
|
+
q.set("day", day);
|
|
1402
|
+
else if (since)
|
|
1403
|
+
q.set("since", since);
|
|
1404
|
+
if (type)
|
|
1405
|
+
q.set("type", type);
|
|
1406
|
+
if (lang && lang !== "en")
|
|
1407
|
+
q.set("lang", lang);
|
|
1408
|
+
/* 0.36.1: a day of forty notes answered 47,000 characters without arguments; the first page is 25. */
|
|
1409
|
+
if (limit)
|
|
1410
|
+
q.set("limit", String(limit));
|
|
1411
|
+
else if (!day && !since)
|
|
1412
|
+
q.set("limit", "25");
|
|
1413
|
+
const qs = q.toString();
|
|
1414
|
+
const path = `/api/public/desk${qs ? `?${qs}` : ""}`;
|
|
1415
|
+
return ok(withProvenance(await fetchJson(path), path));
|
|
1416
|
+
}
|
|
1417
|
+
catch (err) {
|
|
1418
|
+
return fail(err);
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1380
1421
|
server.registerTool("get_turkey_premium", {
|
|
1381
1422
|
title: "Turkey Premium Index: what lira buyers pay above the world price, with TRY reference prices from Turkish venues",
|
|
1382
1423
|
description: "Call this when the user asks about Bitcoin, Ether or USDT prices in Turkish lira, the Turkey premium, the USDT/TRY rate or dollar premium in Turkey, or which Turkish exchanges (BtcTurk, Bitlo, CoinTR, OKX TR, Binance TR, Bybit TR, Bitexen; KuCoin TR contributes the USDT pairs only) trade above or below the global price. Returns the live board: the Turkey Premium Index (what a lira buyer pays for bitcoin against the global dollar price at the official exchange rate, in bps) with its dollar leg and crypto leg, a 0-100 score (50 = world price) and regime, 24h and 7d averages and the same-sign streak; then five reference prices (median of eligible order books), per-venue book status, spread, depth and each venue's implied premium. Pass pair and history_days for 15-minute history of one pair. Without pair, the daily rows cover the last 7 days; pass pair, or daily_days (up to 30) for more.",
|
|
@@ -1694,6 +1735,9 @@ export function registerByKaranteliTools(target, options) {
|
|
|
1694
1735
|
const SERIES_PERIODS = ["1m", "3m", "5m", "10m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", "1d", "3d", "1w", "1M"];
|
|
1695
1736
|
const PERIOD_MS = { "1m": 60_000, "3m": 180_000, "5m": 300_000, "10m": 600_000, "15m": 900_000, "30m": 1_800_000, "1h": 3_600_000, "2h": 7_200_000, "4h": 14_400_000, "6h": 21_600_000, "8h": 28_800_000, "12h": 43_200_000, "1d": 86_400_000, "3d": 259_200_000, "1w": 604_800_000, "1M": 2_592_000_000 };
|
|
1696
1737
|
const SERIES_MEMBER_BAR_LIMIT = 5000;
|
|
1738
|
+
/* The public depth of /api/series (web lib/series/limits.ts SERIES_ANON_BAR_LIMIT): the window a plan without member
|
|
1739
|
+
* depth may page back through with `to`; an older `to` answers 403 history_member_only (web route, 2026-10-20). */
|
|
1740
|
+
const SERIES_ANON_BAR_LIMIT = 300;
|
|
1697
1741
|
const RECIPE_FIELD_KEYS = ["mark_price", "pressure_score", "funding_rate_pct", "oi24h_pct", "basis_pct", "price_change_24h_pct", "liq_cluster_distance_pct", "usdt_peg_min_usd", "usdc_peg_min_usd", "liq_1h_usd", "rsi_4h", "ls_ratio_global", "book_imbalance_2pct_pct", "withdrawal_paused_venues", "max_leverage_min", "borrow_apr_pct", "hl_whale_long_share_pct"];
|
|
1698
1742
|
const RECIPE_OPS = [">=", ">", "<=", "<", "=="];
|
|
1699
1743
|
const RECIPE_CHANNELS = ["telegram", "email", "push", "webhook"];
|
|
@@ -1783,14 +1827,14 @@ export function registerByKaranteliTools(target, options) {
|
|
|
1783
1827
|
/* ---- 0.31.0: recorded series, alert text, alert recipes, watchlists ---- */
|
|
1784
1828
|
server.registerTool("get_series", {
|
|
1785
1829
|
title: "Recorded series: bars or points of one metric for one perpetual (price, OI, funding, CVD, liquidations, long/short, RSI and more)",
|
|
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
|
|
1830
|
+
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 limit for more of the newest bars, or from and to (ISO) for a window. The public window is the newest ${SERIES_ANON_BAR_LIMIT} bars of the period: a to before it needs member depth (Builder and higher plans) and answers 403 history_member_only otherwise, except daily and coarser price bars, which stay open to every plan.`,
|
|
1787
1831
|
inputSchema: {
|
|
1788
1832
|
metric: z.string().describe("string, metric key, e.g. price, oi, funding, liquidations (list: /api/series/metrics)"),
|
|
1789
1833
|
symbol: z.string().optional().describe("string, optional Binance USDT-M perp or coin, e.g. BTCUSDT or BTC (default BTCUSDT)"),
|
|
1790
1834
|
period: z.enum(SERIES_PERIODS).optional().describe(`string, optional bar period: ${SERIES_PERIODS.join(" | ")} (default 1h; each metric has a finest period)`),
|
|
1791
1835
|
venue: z.string().optional().describe("string, optional venue id for price, oi, funding or borrow, e.g. okx (default binance)"),
|
|
1792
1836
|
from: z.string().optional().describe("string, optional ISO start, e.g. 2026-09-01T00:00:00Z"),
|
|
1793
|
-
to: z.string().optional().describe(
|
|
1837
|
+
to: z.string().optional().describe(`string, optional ISO end (default now); a to before the newest ${SERIES_ANON_BAR_LIMIT} bars of the period needs member depth, except daily and coarser price bars`),
|
|
1794
1838
|
limit: z.number().optional().describe(`number, optional newest bars, 10..${SERIES_MEMBER_BAR_LIMIT}; the plan's depth caps it (default 300 without from)`),
|
|
1795
1839
|
},
|
|
1796
1840
|
annotations: READ_ONLY,
|
|
@@ -1846,7 +1890,7 @@ export function registerByKaranteliTools(target, options) {
|
|
|
1846
1890
|
});
|
|
1847
1891
|
server.registerTool("list_alert_recipes", {
|
|
1848
1892
|
title: "Your alert recipes: every alert on your account with its conditions, scope, channels and when it last fired",
|
|
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.",
|
|
1893
|
+
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, reachable: whether a delivery channel is set up for it) and channels_available (the delivery channels the account has connected). Needs a signed-in account (OAuth sign-in or account key); reads nothing but this account.",
|
|
1850
1894
|
inputSchema: {},
|
|
1851
1895
|
annotations: ACCOUNT_READ,
|
|
1852
1896
|
}, async () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bykaranteli-mcp",
|
|
3
|
-
"version": "0.
|
|
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.
|
|
3
|
+
"version": "0.36.1",
|
|
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. 68 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": {
|
|
7
7
|
"bykaranteli-mcp": "dist/index.js"
|