bykaranteli-mcp 0.7.2 → 0.8.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/README.md CHANGED
@@ -2,7 +2,12 @@
2
2
 
3
3
  MCP (Model Context Protocol) server for **live crypto derivatives data**: funding rates, cross-exchange funding arbitrage, open interest pressure, Fear & Greed, BTC dominance and a verified signal track record.
4
4
 
5
- Backed by the free, no-auth public JSON API of [bykaranteli.com](https://bykaranteli.com/developers). No API key, no account, no rate-limit registration. Data covers Binance USDT-M perpetuals (funding arbitrage additionally compares OKX, Bybit, Gate, HTX and BingX).
5
+ 20 read-only tools over the free, no-auth public JSON API of [bykaranteli.com](https://bykaranteli.com/developers). No API key, no account, no rate-limit registration. Data covers Binance USDT-M perpetuals (funding arbitrage additionally compares OKX, Bybit, Gate, HTX and BingX).
6
+
7
+ ## Hosted endpoint (no install)
8
+
9
+ Paste `https://mcp.bykaranteli.com` as a custom connector in any MCP-capable
10
+ assistant. Same 20 tools, nothing to install, no key.
6
11
 
7
12
  ## Quick start
8
13
 
@@ -83,3 +88,11 @@ node dist/index.js # speaks MCP over stdio
83
88
  ## License
84
89
 
85
90
  MIT. Attribution appreciated: "ByKaranteli (bykaranteli.com)".
91
+
92
+ ## Paid depth (optional)
93
+
94
+ The 20 tools above are free and stay free. For recorded history and raw records
95
+ beyond the live snapshots, bykaranteli.com also exposes pay-per-call x402
96
+ endpoints (USDC on Solana or Base, priced per call, no account):
97
+ <https://bykaranteli.com/developers#x402> · machine catalog:
98
+ <https://bykaranteli.com/api/x402>
package/dist/tools.d.ts CHANGED
@@ -2,12 +2,17 @@
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 the 10 tools have exactly one definition.
5
+ * instance, so all 20 tools have exactly one definition.
6
6
  */
7
7
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
8
  export type RegisterOptions = {
9
- /** Override the public API origin (hosted endpoint uses the internal one). */
9
+ /** Override the API origin used for OUTBOUND fetches (the hosted endpoint
10
+ * points this at the container-internal origin). */
10
11
  baseUrl?: string;
12
+ /** Origin used in citations returned to the caller. Defaults to baseUrl.
13
+ * The hosted endpoint must set this, otherwise every response cites the
14
+ * container-internal address, which is useless to the agent reading it. */
15
+ publicUrl?: string;
11
16
  /** Version string for the outbound user-agent. */
12
17
  version?: string;
13
18
  };
package/dist/tools.js CHANGED
@@ -2,11 +2,12 @@
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 the 10 tools have exactly one definition.
5
+ * instance, so all 20 tools have exactly one definition.
6
6
  */
7
7
  import { z } from "zod/v4";
8
8
  export function registerByKaranteliTools(server, options) {
9
9
  const BASE_URL = (options?.baseUrl ?? process.env.BYKARANTELI_BASE_URL ?? "https://bykaranteli.com").replace(/\/+$/, "");
10
+ const PUBLIC_URL = (options?.publicUrl ?? process.env.BYKARANTELI_PUBLIC_URL ?? "https://bykaranteli.com").replace(/\/+$/, "");
10
11
  const USER_AGENT = `bykaranteli-mcp/${options?.version ?? "dev"} (+https://github.com/bykarantelicom/bykaranteli-mcp)`;
11
12
  const TIMEOUT_MS = 15_000;
12
13
  // Read-only GET tools over an open-world public API, all of them.
@@ -78,7 +79,7 @@ export function registerByKaranteliTools(server, options) {
78
79
  explainer: euphoria.explainer,
79
80
  }
80
81
  : undefined,
81
- source: `${BASE_URL}/indices`,
82
+ source: `${PUBLIC_URL}/indices`,
82
83
  });
83
84
  }
84
85
  catch (err) {
@@ -109,8 +110,8 @@ export function registerByKaranteliTools(server, options) {
109
110
  const filtered = rows.filter((r) => dateSet.has(String(r.date)) && (!symbol || String(r.symbol).toUpperCase() === symbol));
110
111
  return ok({
111
112
  rows: filtered.slice(0, 400),
112
- note: "Recorded from public exchange streams; totals are a floor (Binance throttles its stream). Live 24h view: " + BASE_URL + "/liquidations",
113
- source: `${BASE_URL}/liquidations`,
113
+ note: "Recorded from public exchange streams; totals are a floor (Binance throttles its stream). Live 24h view: " + PUBLIC_URL + "/liquidations",
114
+ source: `${PUBLIC_URL}/liquidations`,
114
115
  });
115
116
  }
116
117
  catch (err) {
@@ -133,7 +134,7 @@ export function registerByKaranteliTools(server, options) {
133
134
  return ok({
134
135
  rows: filtered.slice(0, (days ?? 10) * (asset ? 1 : 2)),
135
136
  note: "Finalized US trading days only; a positive net_inflow_usd means the funds bought more of the asset than they sold that day.",
136
- source: `${BASE_URL}/etf`,
137
+ source: `${PUBLIC_URL}/etf`,
137
138
  });
138
139
  }
139
140
  catch (err) {
@@ -162,9 +163,9 @@ export function registerByKaranteliTools(server, options) {
162
163
  note: `${want} is not in the top-30 heatmap set. Tracked symbols: ${d.rows.map((r) => r.symbol).join(", ")}`,
163
164
  });
164
165
  }
165
- return ok({ generatedAt: d.generatedAt, row, source: `${BASE_URL}/heatmap` });
166
+ return ok({ generatedAt: d.generatedAt, row, source: `${PUBLIC_URL}/heatmap` });
166
167
  }
167
- return ok({ ...d, source: `${BASE_URL}/heatmap` });
168
+ return ok({ ...d, source: `${PUBLIC_URL}/heatmap` });
168
169
  }
169
170
  catch (err) {
170
171
  return fail(err);
@@ -178,7 +179,7 @@ export function registerByKaranteliTools(server, options) {
178
179
  }, async () => {
179
180
  try {
180
181
  const d = (await fetchJson("/api/public/funding-arb"));
181
- return ok({ ...d, source: `${BASE_URL}/funding-arb` });
182
+ return ok({ ...d, source: `${PUBLIC_URL}/funding-arb` });
182
183
  }
183
184
  catch (err) {
184
185
  return fail(err);
@@ -221,13 +222,13 @@ export function registerByKaranteliTools(server, options) {
221
222
  note: `${want} is not in the tracked pressure universe right now.`,
222
223
  });
223
224
  }
224
- return ok({ generatedAt: d.generatedAt, item: slim(item), source: `${BASE_URL}/pressure` });
225
+ return ok({ generatedAt: d.generatedAt, item: slim(item), source: `${PUBLIC_URL}/pressure` });
225
226
  }
226
227
  return ok({
227
228
  generatedAt: d.generatedAt,
228
229
  items: d.items.slice(0, limit ?? 20).map(slim),
229
230
  totalTracked: d.items.length,
230
- source: `${BASE_URL}/pressure`,
231
+ source: `${PUBLIC_URL}/pressure`,
231
232
  });
232
233
  }
233
234
  catch (err) {
@@ -242,7 +243,7 @@ export function registerByKaranteliTools(server, options) {
242
243
  }, async () => {
243
244
  try {
244
245
  const d = (await fetchJson("/api/public/top-movers"));
245
- return ok({ ...d, source: `${BASE_URL}/top-movers` });
246
+ return ok({ ...d, source: `${PUBLIC_URL}/top-movers` });
246
247
  }
247
248
  catch (err) {
248
249
  return fail(err);
@@ -256,7 +257,7 @@ export function registerByKaranteliTools(server, options) {
256
257
  }, async () => {
257
258
  try {
258
259
  const d = (await fetchJson("/api/public/recent"));
259
- return ok({ ...d, source: `${BASE_URL}/signals` });
260
+ return ok({ ...d, source: `${PUBLIC_URL}/signals` });
260
261
  }
261
262
  catch (err) {
262
263
  return fail(err);
@@ -288,7 +289,7 @@ export function registerByKaranteliTools(server, options) {
288
289
  return ok({
289
290
  symbol: want,
290
291
  window_days: w,
291
- note: `No closed signals recorded for ${want} in the last ${w} days (or the symbol is not tracked). Try window_days: 180, or check ${BASE_URL}/symbols/${want}.`,
292
+ note: `No closed signals recorded for ${want} in the last ${w} days (or the symbol is not tracked). Try window_days: 180, or check ${PUBLIC_URL}/symbols/${want}.`,
292
293
  });
293
294
  }
294
295
  throw err;
@@ -298,7 +299,7 @@ export function registerByKaranteliTools(server, options) {
298
299
  return ok({
299
300
  ...d,
300
301
  daily_points: Array.isArray(daily) ? daily.slice(-30) : daily,
301
- source: `${BASE_URL}/symbols/${want}`,
302
+ source: `${PUBLIC_URL}/symbols/${want}`,
302
303
  });
303
304
  }
304
305
  catch (err) {
@@ -313,7 +314,7 @@ export function registerByKaranteliTools(server, options) {
313
314
  }, async () => {
314
315
  try {
315
316
  const d = (await fetchJson("/api/v1/public/leaderboard"));
316
- return ok({ ...d, source: `${BASE_URL}/leaderboard` });
317
+ return ok({ ...d, source: `${PUBLIC_URL}/leaderboard` });
317
318
  }
318
319
  catch (err) {
319
320
  return fail(err);
@@ -449,4 +450,48 @@ export function registerByKaranteliTools(server, options) {
449
450
  return fail(err);
450
451
  }
451
452
  });
453
+ server.registerTool("get_altseason", {
454
+ title: "Altcoin Season Index (live + recorded history)",
455
+ description: "Call this when the user asks whether it is altseason, how altcoins are doing against Bitcoin, or about market rotation. Returns the live Altcoin Season Index (share of the top 50 Binance perpetual altcoins beating BTC over the trailing 90 days; >=75 altseason, <=25 bitcoin season), the strongest and weakest large alts, and the recorded daily history (never reconstructed).",
456
+ inputSchema: {},
457
+ annotations: READ_ONLY,
458
+ }, async () => {
459
+ try {
460
+ return ok(await fetchJson("/api/public/altseason"));
461
+ }
462
+ catch (err) {
463
+ return fail(err);
464
+ }
465
+ });
466
+ server.registerTool("get_quantum_exposure", {
467
+ title: "Quantum-exposed Bitcoin (daily first-party measurement)",
468
+ description: "Call this when the user asks how much Bitcoin is vulnerable to a quantum computer, about quantum-exposed supply, P2PK coins, or Satoshi-era exposure. Returns the latest daily measurement from ByKaranteli's own Bitcoin Core node: exposed BTC and its share of held value and UTXO count, composition by script family, dormancy cohorts, the dormant-P2PK watch set, and provenance hashes (base_height, base_hash, txoutset_hash) so any figure can be re-verified against any node.",
469
+ inputSchema: {},
470
+ annotations: READ_ONLY,
471
+ }, async () => {
472
+ try {
473
+ return ok(await fetchJson("/api/public/quantum"));
474
+ }
475
+ catch (err) {
476
+ return fail(err);
477
+ }
478
+ });
479
+ server.registerTool("get_metric_context", {
480
+ title: "Historical context for any recorded metric (conditional distribution)",
481
+ description: "Call this when the user asks whether a metric's current reading is high or low, or what happened after similar readings. Buckets today's value against the metric's own recorded daily history and returns the median forward BTC return and up-share per bucket at +1/+3/+7 days, with the all-days base rate alongside. Honesty rules: buckets under 30 days are suppressed, and most metrics do NOT separate from the base rate; the interpretation says so plainly. History, not a forecast. Metrics include coinbase_premium_pct, kraken_btc_premium_pct, dvol_btc, fear_greed, funding_btc_daily_pct, etf_btc_net_flow_usd, vpin_btc, altseason_index, stablecoin_total_mcap_busd, fred_dff, fred_dgs10, fred_walcl_busd, fred_rrp_busd and the btc_* network series.",
482
+ inputSchema: {
483
+ metric: z
484
+ .string()
485
+ .regex(/^[a-z0-9_]{2,50}$/)
486
+ .describe("Metric key, e.g. coinbase_premium_pct, fear_greed, altseason_index, stablecoin_total_mcap_busd."),
487
+ },
488
+ annotations: READ_ONLY,
489
+ }, async ({ metric }) => {
490
+ try {
491
+ return ok(await fetchJson(`/api/public/context?metric=${encodeURIComponent(metric)}`));
492
+ }
493
+ catch (err) {
494
+ return fail(err);
495
+ }
496
+ });
452
497
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bykaranteli-mcp",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "MCP server for live crypto derivatives data from bykaranteli.com: funding rates, funding arbitrage, open interest pressure, Fear & Greed, BTC dominance and verified signal performance. Free, no API key.",
5
5
  "type": "module",
6
6
  "bin": {