blockbeats-mcp 1.0.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.
Files changed (2) hide show
  1. package/dist/index.js +345 -0
  2. package/package.json +37 -0
package/dist/index.js ADDED
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const BASE_URL = "http://api-pro.theblockbeats.info";
8
+ function getApiKey() {
9
+ const key = process.env.BLOCKBEATS_API_KEY;
10
+ if (!key) {
11
+ throw new Error("未设置 BLOCKBEATS_API_KEY 环境变量,请先申请:https://www.theblockbeats.info/");
12
+ }
13
+ return key;
14
+ }
15
+ async function fetchApi(path, params) {
16
+ const apiKey = getApiKey();
17
+ const url = new URL(`${BASE_URL}${path}`);
18
+ if (params) {
19
+ for (const [k, v] of Object.entries(params)) {
20
+ url.searchParams.set(k, v);
21
+ }
22
+ }
23
+ const res = await fetch(url.toString(), {
24
+ headers: { "api-key": apiKey },
25
+ });
26
+ if (res.status === 401)
27
+ throw new Error("API Key 无效或已过期,请检查密钥是否正确");
28
+ if (res.status === 403)
29
+ throw new Error("当前套餐无权访问该接口,请升级套餐");
30
+ if (!res.ok)
31
+ throw new Error(`HTTP ${res.status}`);
32
+ const json = await res.json();
33
+ if (json.status !== 0)
34
+ throw new Error(json.message || "API 返回错误");
35
+ return json.data;
36
+ }
37
+ const server = new index_js_1.Server({ name: "blockbeats-mcp", version: "1.0.0" }, { capabilities: { tools: {} } });
38
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
39
+ tools: [
40
+ {
41
+ name: "get_newsflash",
42
+ description: "获取加密货币快讯,支持按分类(全部/重要/原创/首发/链上/融资/预测/AI)、页码和语言筛选",
43
+ inputSchema: {
44
+ type: "object",
45
+ properties: {
46
+ category: {
47
+ type: "string",
48
+ enum: ["all", "important", "original", "first", "onchain", "financing", "prediction", "ai"],
49
+ default: "all",
50
+ description: "快讯分类:all全部 | important重要 | original原创 | first首发 | onchain链上 | financing融资 | prediction预测市场 | ai(AI快讯)",
51
+ },
52
+ page: { type: "integer", minimum: 1, default: 1, description: "页码" },
53
+ size: { type: "integer", minimum: 1, maximum: 100, default: 10, description: "每页数量" },
54
+ lang: { type: "string", enum: ["cn", "en"], default: "cn", description: "语言" },
55
+ },
56
+ },
57
+ },
58
+ {
59
+ name: "get_articles",
60
+ description: "获取加密货币深度文章,支持按分类(全部/重要/原创)和页码筛选",
61
+ inputSchema: {
62
+ type: "object",
63
+ properties: {
64
+ category: {
65
+ type: "string",
66
+ enum: ["all", "important", "original"],
67
+ default: "all",
68
+ description: "文章分类:all全部 | important重要 | original原创",
69
+ },
70
+ page: { type: "integer", minimum: 1, default: 1, description: "页码" },
71
+ size: { type: "integer", minimum: 1, maximum: 100, default: 10, description: "每页数量" },
72
+ lang: { type: "string", enum: ["cn", "en"], default: "cn", description: "语言" },
73
+ },
74
+ },
75
+ },
76
+ {
77
+ name: "search_news",
78
+ description: "按关键词搜索快讯和文章",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ keyword: { type: "string", minLength: 1, description: "搜索关键词" },
83
+ size: { type: "integer", minimum: 1, maximum: 100, default: 10, description: "返回数量" },
84
+ lang: { type: "string", enum: ["cn", "en"], default: "cn", description: "语言" },
85
+ },
86
+ required: ["keyword"],
87
+ },
88
+ },
89
+ {
90
+ name: "get_btc_etf_flow",
91
+ description: "获取 BTC ETF 净流入数据(机构资金)",
92
+ inputSchema: { type: "object", properties: {} },
93
+ },
94
+ {
95
+ name: "get_daily_onchain_tx",
96
+ description: "获取每日链上交易量数据",
97
+ inputSchema: { type: "object", properties: {} },
98
+ },
99
+ {
100
+ name: "get_ibit_fbtc_flow",
101
+ description: "获取 IBIT/FBTC 净流入数据",
102
+ inputSchema: { type: "object", properties: {} },
103
+ },
104
+ {
105
+ name: "get_stablecoin_marketcap",
106
+ description: "获取 USDT、USDC 等主流稳定币市值数据",
107
+ inputSchema: { type: "object", properties: {} },
108
+ },
109
+ {
110
+ name: "get_compliant_exchange_total",
111
+ description: "获取主流合规交易所总资产",
112
+ inputSchema: { type: "object", properties: {} },
113
+ },
114
+ {
115
+ name: "get_us_treasury_yield",
116
+ description: "获取美国 10Y 国债收益率,支持多时间维度",
117
+ inputSchema: {
118
+ type: "object",
119
+ properties: {
120
+ timeframe: {
121
+ type: "string",
122
+ enum: ["1D", "1W", "1M"],
123
+ default: "1D",
124
+ description: "时间维度:1D日 | 1W周 | 1M月",
125
+ },
126
+ },
127
+ },
128
+ },
129
+ {
130
+ name: "get_dxy_index",
131
+ description: "获取美元指数(DXY),支持多时间维度",
132
+ inputSchema: {
133
+ type: "object",
134
+ properties: {
135
+ timeframe: {
136
+ type: "string",
137
+ enum: ["1D", "1W", "1M"],
138
+ default: "1D",
139
+ description: "时间维度:1D日 | 1W周 | 1M月",
140
+ },
141
+ },
142
+ },
143
+ },
144
+ {
145
+ name: "get_m2_supply",
146
+ description: "获取全球 M2 货币供应量,支持多时间维度",
147
+ inputSchema: {
148
+ type: "object",
149
+ properties: {
150
+ timeframe: {
151
+ type: "string",
152
+ enum: ["3M", "6M", "1Y", "3Y"],
153
+ default: "1Y",
154
+ description: "时间维度:3M(3个月) | 6M(半年) | 1Y(1年) | 3Y(3年)",
155
+ },
156
+ },
157
+ },
158
+ },
159
+ {
160
+ name: "get_bitfinex_long_positions",
161
+ description: "获取 Bitfinex 杠杆多头持仓数据,反映大户做多情绪",
162
+ inputSchema: {
163
+ type: "object",
164
+ properties: {
165
+ symbol: { type: "string", default: "btc", description: "币种符号,默认 btc" },
166
+ timeframe: {
167
+ type: "string",
168
+ enum: ["h24", "1D", "1W", "1M"],
169
+ default: "1D",
170
+ description: "时间维度:h24(24小时近实时) | 1D日 | 1W周 | 1M月",
171
+ },
172
+ },
173
+ },
174
+ },
175
+ {
176
+ name: "get_contract_oi_data",
177
+ description: "获取 Binance、Bybit、Hyperliquid 等主流合约平台未平仓合约(OI)数据",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ dataType: {
182
+ type: "string",
183
+ enum: ["1D", "1W", "1M", "3M", "6M", "12M"],
184
+ default: "1D",
185
+ description: "时间维度:1D日 | 1W周 | 1M月 | 3M | 6M | 12M年",
186
+ },
187
+ },
188
+ },
189
+ },
190
+ {
191
+ name: "get_sentiment_indicator",
192
+ description: "获取抄底逃顶市场情绪指标(<20 潜在买入区间 / 20-80 中性 / >80 潜在卖出区间)",
193
+ inputSchema: { type: "object", properties: {} },
194
+ },
195
+ {
196
+ name: "get_top10_netflow",
197
+ description: "获取指定链上净流入最多的前十个代币",
198
+ inputSchema: {
199
+ type: "object",
200
+ properties: {
201
+ network: {
202
+ type: "string",
203
+ enum: ["solana", "base", "ethereum"],
204
+ default: "solana",
205
+ description: "区块链网络:solana | base | ethereum",
206
+ },
207
+ },
208
+ },
209
+ },
210
+ {
211
+ name: "get_exchange_rankings",
212
+ description: "获取合约交易所成交量和未平仓合约排名",
213
+ inputSchema: {
214
+ type: "object",
215
+ properties: {
216
+ exchange_name: { type: "string", description: "交易所名称过滤(可选),如 Binance" },
217
+ page: { type: "integer", minimum: 1, default: 1, description: "页码" },
218
+ size: { type: "integer", minimum: 1, maximum: 100, default: 10, description: "每页数量" },
219
+ },
220
+ },
221
+ },
222
+ ],
223
+ }));
224
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (req) => {
225
+ const { name, arguments: args = {} } = req.params;
226
+ const a = args;
227
+ try {
228
+ let data;
229
+ switch (name) {
230
+ case "get_newsflash": {
231
+ const category = a.category || "all";
232
+ const params = {
233
+ page: String(a.page ?? 1),
234
+ size: String(a.size ?? 10),
235
+ lang: a.lang || "cn",
236
+ };
237
+ if (category === "ai") {
238
+ params.type = "ai";
239
+ data = await fetchApi("/v1/newsflash", params);
240
+ }
241
+ else if (category === "all") {
242
+ data = await fetchApi("/v1/newsflash", params);
243
+ }
244
+ else {
245
+ data = await fetchApi(`/v1/newsflash/${category}`, params);
246
+ }
247
+ break;
248
+ }
249
+ case "get_articles": {
250
+ const category = a.category || "all";
251
+ const params = {
252
+ page: String(a.page ?? 1),
253
+ size: String(a.size ?? 10),
254
+ lang: a.lang || "cn",
255
+ };
256
+ if (category === "all") {
257
+ data = await fetchApi("/v1/article", params);
258
+ }
259
+ else {
260
+ data = await fetchApi(`/v1/article/${category}`, params);
261
+ }
262
+ break;
263
+ }
264
+ case "search_news":
265
+ data = await fetchApi("/v1/search", {
266
+ name: String(a.keyword),
267
+ size: String(a.size ?? 10),
268
+ lang: a.lang || "cn",
269
+ });
270
+ break;
271
+ case "get_btc_etf_flow":
272
+ data = await fetchApi("/v1/data/btc_etf");
273
+ break;
274
+ case "get_daily_onchain_tx":
275
+ data = await fetchApi("/v1/data/daily_tx");
276
+ break;
277
+ case "get_ibit_fbtc_flow":
278
+ data = await fetchApi("/v1/data/ibit_fbtc");
279
+ break;
280
+ case "get_stablecoin_marketcap":
281
+ data = await fetchApi("/v1/data/stablecoin_marketcap");
282
+ break;
283
+ case "get_compliant_exchange_total":
284
+ data = await fetchApi("/v1/data/compliant_total");
285
+ break;
286
+ case "get_us_treasury_yield":
287
+ data = await fetchApi("/v1/data/us10y", { type: a.timeframe || "1D" });
288
+ break;
289
+ case "get_dxy_index":
290
+ data = await fetchApi("/v1/data/dxy", { type: a.timeframe || "1D" });
291
+ break;
292
+ case "get_m2_supply":
293
+ data = await fetchApi("/v1/data/m2_supply", { type: a.timeframe || "1Y" });
294
+ break;
295
+ case "get_bitfinex_long_positions":
296
+ data = await fetchApi("/v1/data/bitfinex_long", {
297
+ symbol: a.symbol || "btc",
298
+ type: a.timeframe || "1D",
299
+ });
300
+ break;
301
+ case "get_contract_oi_data":
302
+ data = await fetchApi("/v1/data/contract", { dataType: a.dataType || "1D" });
303
+ break;
304
+ case "get_sentiment_indicator":
305
+ data = await fetchApi("/v1/data/bottom_top_indicator");
306
+ break;
307
+ case "get_top10_netflow":
308
+ data = await fetchApi("/v1/data/top10_netflow", {
309
+ network: a.network || "solana",
310
+ });
311
+ break;
312
+ case "get_exchange_rankings": {
313
+ const params = {
314
+ page: String(a.page ?? 1),
315
+ size: String(a.size ?? 10),
316
+ };
317
+ if (a.exchange_name)
318
+ params.name = String(a.exchange_name);
319
+ data = await fetchApi("/v1/data/exchanges", params);
320
+ break;
321
+ }
322
+ default:
323
+ throw new Error(`未知工具: ${name}`);
324
+ }
325
+ return {
326
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
327
+ };
328
+ }
329
+ catch (err) {
330
+ const message = err instanceof Error ? err.message : String(err);
331
+ return {
332
+ content: [{ type: "text", text: `错误:${message}` }],
333
+ isError: true,
334
+ };
335
+ }
336
+ });
337
+ async function main() {
338
+ const transport = new stdio_js_1.StdioServerTransport();
339
+ await server.connect(transport);
340
+ console.error("BlockBeats MCP Server 已启动");
341
+ }
342
+ main().catch((err) => {
343
+ console.error("启动失败:", err);
344
+ process.exit(1);
345
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "blockbeats-mcp",
3
+ "version": "1.0.0",
4
+ "description": "BlockBeats Pro API MCP Server for crypto news, newsflashes, and on-chain market data",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "blockbeats-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "start": "node dist/index.js",
18
+ "dev": "ts-node src/index.ts"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "blockbeats",
23
+ "crypto",
24
+ "news",
25
+ "bitcoin",
26
+ "on-chain"
27
+ ],
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "typescript": "^5.0.0",
35
+ "ts-node": "^10.0.0"
36
+ }
37
+ }