@dshtrading/connector-jin10 0.6.3 → 0.7.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.
Files changed (2) hide show
  1. package/lib/tools.js +69 -2
  2. package/package.json +5 -5
package/lib/tools.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { JIN10_HEAT_LEVELS, isJin10HeatLevel } from "./web-flash.js";
1
2
  import "./macro-service.js";
2
3
  import "./service.js";
3
4
  import { defineTool } from "@deepseek-ai/dsh-tools";
@@ -20,12 +21,32 @@ const textOutput = {
20
21
  }]
21
22
  };
22
23
  const SOURCE = "Jin10 (金十数据) MCP feed";
24
+ /** 热度过滤的实际取数面:金十网页版快讯接口(官方 MCP 的 list_flash 无热度参数)。 */
25
+ const HEAT_SOURCE = "Jin10 (金十数据) web flash endpoint (public heat-filtered feed)";
26
+ /** 央行利率的实际取数面:金十日历网页版的公开利率接口,不是官方 MCP feed。 */
27
+ const RATES_SOURCE = "Jin10 (金十数据) web rate board (public interest-rate endpoint behind rili.jin10.com)";
23
28
  function renderNewsLines(items) {
24
29
  return items.map((item) => {
25
30
  const id = "id" in item && typeof item.id === "string" ? ` | id=${item.id}` : "";
26
- return `${item.publishedAt} | ${item.title} | ${item.url}${id}`;
31
+ const hot = typeof item.hot === "string" ? ` | hot=${item.hot}` : "";
32
+ return `${item.publishedAt} | ${item.title} | ${item.url}${id}${hot}`;
27
33
  });
28
34
  }
35
+ /**
36
+ * `hot` 参数解析(逗号或空白分隔的多值;取值必须是既有热度词汇)。
37
+ * 非法值显式报错并列出支持值——热度过滤是服务端语义,猜一个近义词会静默改变取数范围。
38
+ */
39
+ function parseHeatLevels(raw) {
40
+ if (raw === void 0 || raw === null) return [];
41
+ const text = typeof raw === "string" ? raw : String(raw);
42
+ const levels = [];
43
+ for (const token of text.split(/[\s,]+/)) {
44
+ if (token.length === 0) continue;
45
+ if (!isJin10HeatLevel(token)) throw new Error(`flash_list: unsupported hot level ${JSON.stringify(token)} (supported: ${JIN10_HEAT_LEVELS.join("/")}; comma-separated for several)`);
46
+ if (!levels.includes(token)) levels.push(token);
47
+ }
48
+ return levels;
49
+ }
29
50
  function pageFooter(page, tool) {
30
51
  if (page.hasMore && page.nextCursor !== void 0) return `has_more=true — pass cursor="${page.nextCursor}" to ${tool} for the next (older) page.`;
31
52
  return "has_more=false — no further pages.";
@@ -45,7 +66,7 @@ function createJin10Tools(service) {
45
66
  return [
46
67
  defineTool({
47
68
  name: "flash_list",
48
- description: `Latest market flash headlines from ${SOURCE}, newest first. Market-wide wire (macro, commodities, FX, A-shares, geopolitics) — not tied to one instrument. Each item carries publish time, headline and the source link; the full flash text stays on the linked page. Pages return up to 20 items: pass the returned cursor to read older pages. Upstream rate limit: 1500 calls per tool per Beijing calendar day.`,
69
+ description: `Latest market flash headlines from ${SOURCE}, newest first. Market-wide wire (macro, commodities, FX, A-shares, geopolitics) — not tied to one instrument. Each item carries publish time, headline and the source link; the full flash text stays on the linked page. Pages return up to 20 items: pass the returned cursor to read older pages. Optional hot (comma-separated, values ${JIN10_HEAT_LEVELS.join("/")}) filters server-side by the publisher's heat grade — that path reads ${HEAT_SOURCE} instead of the MCP feed, whose page size is fixed (up to 50 items, no limit parameter), so limit is applied locally to the page and items carry hot=<level>. An upstream error (rate limit, bad token, network) throws instead of returning an empty list — empty output means the upstream really had nothing. Upstream rate limit: 1500 calls per tool per Beijing calendar day.`,
49
70
  parameters: {
50
71
  cursor: {
51
72
  type: "string",
@@ -54,6 +75,10 @@ function createJin10Tools(service) {
54
75
  limit: {
55
76
  type: "number",
56
77
  description: `Max items to return (integer 1..50; default 20)`
78
+ },
79
+ hot: {
80
+ type: "string",
81
+ description: `Optional heat filter, comma-separated for several: ${JIN10_HEAT_LEVELS.join(" / ")} (火=least, 爆=most); any other value is rejected with the supported list`
57
82
  }
58
83
  },
59
84
  output: textOutput,
@@ -61,6 +86,20 @@ function createJin10Tools(service) {
61
86
  const args = raw ?? {};
62
87
  const limit = readLimit(args.limit, 20, 50);
63
88
  const cursor = readCursor(args.cursor);
89
+ const hot = parseHeatLevels(args.hot);
90
+ if (hot.length > 0) {
91
+ const page = await service.listFlashByHeat({
92
+ hot,
93
+ ...cursor !== void 0 ? { cursor } : {}
94
+ });
95
+ const items = page.items.slice(0, limit);
96
+ if (items.length === 0) return `flash_list: no flash items at heat ${hot.join("/")} on this page.`;
97
+ return [
98
+ `flash_list (hot=${hot.join("/")}) — ${items.length} item(s) from a fixed ${page.items.length}-item upstream page, newest-first, source: ${HEAT_SOURCE}:`,
99
+ ...renderNewsLines(items),
100
+ pageFooter(page, "flash_list")
101
+ ].join("\n");
102
+ }
64
103
  const page = await service.listFlash({
65
104
  limit,
66
105
  ...cursor !== void 0 ? { cursor } : {}
@@ -197,6 +236,34 @@ function createJin10Tools(service) {
197
236
  return [`econ_calendar — ${entries.length} entr(ies) for the current week (Beijing time), source: ${SOURCE}:`, ...entries.map(renderCalendarLine)].join("\n");
198
237
  }
199
238
  }),
239
+ defineTool({
240
+ name: "macro_rates",
241
+ description: `Latest policy interest rate for every central bank on the ${RATES_SOURCE} (~30 banks: Fed, ECB, BOJ, PBoC, BoE …), one row per bank with the publication date of that rate. Units: percent per year (the publisher's own string, e.g. "3.75" or "0"; never converted to a decimal fraction and never recomputed). Time basis: the endpoint is a latest-value snapshot and declares no snapshot timestamp, so each row carries its own publishedAt and as_of is this call's time — check the call time, not the value alone. Optional region filters on the publisher's own region label (e.g. 美国 / 欧元区 / 中国); a filter that matches nothing returns an empty list plus available_regions. An upstream failure (HTTP error, non-JSON body, publisher status != 200) throws — an empty list never stands in for "the endpoint is down". No Jin10 MCP token is needed for this reading.`,
242
+ parameters: { region: {
243
+ type: "string",
244
+ description: "Optional exact region label from the publisher vocabulary, e.g. 美国 / 欧元区 / 日本 / 中国 (omit for all banks)"
245
+ } },
246
+ output: textOutput,
247
+ async execute(raw) {
248
+ const args = raw ?? {};
249
+ const region = typeof args.region === "string" && args.region.trim().length > 0 ? args.region.trim() : void 0;
250
+ const all = await service.listRates();
251
+ const items = region === void 0 ? all : all.filter((entry) => entry.region === region);
252
+ const regions = [...new Set(all.map((entry) => entry.region).filter((value) => value.length > 0))].sort();
253
+ return JSON.stringify({
254
+ source: RATES_SOURCE,
255
+ unit: "percent per year (publisher raw string)",
256
+ as_of: (/* @__PURE__ */ new Date()).toISOString(),
257
+ snapshot_at: null,
258
+ snapshot_note: "The publisher returns a latest-value snapshot with no snapshot timestamp in the contract; each row carries its own publishedAt (publication date of that rate).",
259
+ region: region ?? null,
260
+ available_regions: regions,
261
+ total: all.length,
262
+ count: items.length,
263
+ items
264
+ });
265
+ }
266
+ }),
200
267
  defineTool({
201
268
  name: "global_instruments",
202
269
  description: `Code catalog for the ${SOURCE} quote space (spot metals, energy, FX, global and A-share indices). Call this before global_quote / global_klines whenever the code is not obvious; codes are the publisher's own (XAUUSD, USOIL, USBND, USDJPY …), NOT the market symbol vocabulary. Upstream rate limit: 1500 calls per tool per Beijing calendar day.`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dshtrading/connector-jin10",
3
3
  "description": "金十数据 MCP 连接器:把 mcp.jin10.com 的行情/快讯/资讯/财经日历封装成本仓的连接器(市场无关,host 面工具行)",
4
- "version": "0.6.3",
4
+ "version": "0.7.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "./lib/index.d.ts",
@@ -25,12 +25,12 @@
25
25
  ],
26
26
  "license": "PolyForm-Noncommercial-1.0.0",
27
27
  "dependencies": {
28
- "@dshtrading/api": "^0.6.3"
28
+ "@dshtrading/api": "^0.7.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@deepseek-ai/cordis": ">=4.0.0",
32
- "@deepseek-ai/dsh-tools": ">=0.2.1-rc.2",
33
- "@deepseek-ai/schemastery": ">=3.18.0"
31
+ "@deepseek-ai/cordis": ">=4.1.0",
32
+ "@deepseek-ai/dsh-tools": ">=0.2.2-rc.1",
33
+ "@deepseek-ai/schemastery": ">=3.19.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsdown": "^0.22.0",