From 71f5926d0e5868b502c29c22de17c05d758cc040 Mon Sep 17 00:00:00 2001 From: qer Date: Wed, 10 Jun 2026 22:29:51 +0800 Subject: [PATCH] feat(datasource): add yuandian_law legal data source + request-id trace (#611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register the yuandian_law (元典法律数据库) data source for Chinese laws/regulations and judicial case search. - Append a request-id / tool-call-id trace line to every tool result so failures can be correlated with backend logs. - Fix the documented MCP tool names in SKILL.md (-data -> _data). - Also includes the dev marketplace-server env isolation fix in dev.mjs. Co-authored-by: qer --- .changeset/README.md | 2 + apps/kimi-code/scripts/dev.mjs | 19 +++- .../test/utils/kimi-datasource-plugin.test.ts | 93 +++++++++++++++++++ docs/en/customization/plugins.md | 5 +- docs/zh/customization/plugins.md | 5 +- plugins/marketplace.json | 2 +- plugins/official/kimi-datasource/CHANGELOG.md | 5 + plugins/official/kimi-datasource/SKILL.md | 19 ++-- .../kimi-datasource/bin/kimi-datasource.mjs | 40 ++++++-- .../official/kimi-datasource/kimi.plugin.json | 8 +- 10 files changed, 173 insertions(+), 25 deletions(-) diff --git a/.changeset/README.md b/.changeset/README.md index aed0865b2..9dfaa2c8e 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -39,6 +39,7 @@ Example scenarios: | SDK behavior change affects CLI user experience | Add changesets to both `@moonshot-ai/kimi-code-sdk` and `@moonshot-ai/kimi-code` | | Provider abstraction change affects SDK / CLI | Add changesets to the affected `@moonshot-ai/kimi-code-sdk` and/or `@moonshot-ai/kimi-code` | | Test-only, internal refactor, docs, or private debug tooling changes | Usually no changeset needed | +| Bundled official plugin change under `plugins/` (e.g. `kimi-datasource`) | No changeset — the plugin is versioned via its own `kimi.plugin.json` / `plugins/marketplace.json` and shipped through the marketplace CDN, not the npm package | ## Prerequisite: NPM Trusted Publishing (OIDC) @@ -138,6 +139,7 @@ The root-level `pnpm run publish` first runs typecheck, lint, sherif, test, buil ## Notes - Every PR that affects publishable-package behavior or public API should include a corresponding changeset. +- Changes under `plugins/` (the bundled official plugins such as `kimi-datasource`) do **not** need a changeset: each plugin carries its own version in `kimi.plugin.json` and `plugins/marketplace.json` and is distributed via the marketplace CDN, separately from the `@moonshot-ai/kimi-code` npm package. - Changeset files must be committed to the repository — release PRs are only triggered after they're merged. - Release PRs require human review and merge; they will not publish automatically. - Do not add release changesets for private internal packages; only select `@moonshot-ai/kimi-code` and `@moonshot-ai/kimi-code-sdk`. diff --git a/apps/kimi-code/scripts/dev.mjs b/apps/kimi-code/scripts/dev.mjs index 0e6be4cf2..3cc2d0a58 100644 --- a/apps/kimi-code/scripts/dev.mjs +++ b/apps/kimi-code/scripts/dev.mjs @@ -9,15 +9,32 @@ import { startPluginMarketplaceServer } from './dev-plugin-marketplace-server.mj const require = createRequire(import.meta.url); const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); const APP_ROOT = resolve(SCRIPT_DIR, '..'); +// Runtime variable the CLI reads to locate the marketplace JSON. const MARKETPLACE_ENV = 'KIMI_CODE_PLUGIN_MARKETPLACE_URL'; +// Opt-in for dev: point this run at an external marketplace instead of a local one. +const EXTERNAL_MARKETPLACE_ENV = 'KIMI_CODE_DEV_MARKETPLACE_URL'; let marketplaceServer; const env = { ...process.env }; -if (env[MARKETPLACE_ENV] === undefined || env[MARKETPLACE_ENV]?.trim().length === 0) { +const externalUrl = process.env[EXTERNAL_MARKETPLACE_ENV]?.trim(); +if (externalUrl !== undefined && externalUrl.length > 0) { + // Explicitly asked to use an external marketplace; don't start a local server. + env[MARKETPLACE_ENV] = externalUrl; + console.error(`Using external plugin marketplace: ${externalUrl}`); +} else { + // Default: every `pnpm run dev:cli` runs its own isolated marketplace server on a + // random port, so multiple concurrent dev instances never collide. Overwrite any + // inherited MARKETPLACE_ENV so a stale URL from a dead instance can't break this run. + const inherited = process.env[MARKETPLACE_ENV]?.trim(); marketplaceServer = await startPluginMarketplaceServer(); env[MARKETPLACE_ENV] = marketplaceServer.marketplaceUrl; console.error(`Plugin marketplace dev server: ${marketplaceServer.marketplaceUrl}`); + if (inherited !== undefined && inherited.length > 0 && inherited !== marketplaceServer.marketplaceUrl) { + console.error( + `(ignored inherited ${MARKETPLACE_ENV}=${inherited}; set ${EXTERNAL_MARKETPLACE_ENV} to use an external marketplace)`, + ); + } } const tsxCli = require.resolve('tsx/cli'); diff --git a/apps/kimi-code/test/utils/kimi-datasource-plugin.test.ts b/apps/kimi-code/test/utils/kimi-datasource-plugin.test.ts index 13f9d38d0..51b6d04a2 100644 --- a/apps/kimi-code/test/utils/kimi-datasource-plugin.test.ts +++ b/apps/kimi-code/test/utils/kimi-datasource-plugin.test.ts @@ -216,6 +216,99 @@ describe('kimi-datasource MCP server', () => { await rm(tempDir, { recursive: true, force: true }); } }); + + it('registers yuandian_law in the get_data_source_desc enum', async () => { + const tempDir = await mkdtemp(join(tmpdir(), 'kimi-datasource-plugin-')); + const kimiHome = join(tempDir, 'kimi-home'); + let child: ChildProcessWithoutNullStreams | undefined; + + try { + await mkdir(join(kimiHome, 'credentials'), { recursive: true }); + await writeFile( + join(kimiHome, 'credentials', 'kimi-code.json'), + JSON.stringify({ access_token: 'test-token', expires_at: 4_102_444_800 }), + 'utf8', + ); + child = spawn(process.execPath, [SERVER_ENTRY], { + cwd: REPO_ROOT, + env: { ...process.env, KIMI_CODE_HOME: kimiHome }, + stdio: ['pipe', 'pipe', 'pipe'], + }); + const client = createRpcClient(child); + + await client.request('initialize', {}); + const result = await client.request('tools/list', {}); + + const tools = ( + result.result as { + tools: Array<{ name: string; inputSchema: { properties: { name: { enum: string[] } } } }>; + } + ).tools; + const desc = tools.find((tool) => tool.name === 'get_data_source_desc'); + expect(desc?.inputSchema.properties.name.enum).toContain('yuandian_law'); + } finally { + child?.stdin.end(); + child?.kill(); + await rm(tempDir, { recursive: true, force: true }); + } + }); + + it('appends a request-id / tool-call-id trace line to tool results', async () => { + const tempDir = await mkdtemp(join(tmpdir(), 'kimi-datasource-plugin-')); + const kimiHome = join(tempDir, 'kimi-home'); + let child: ChildProcessWithoutNullStreams | undefined; + + const server = createServer((request, response) => { + request.on('data', () => {}); + request.on('end', () => { + response.setHeader('x-request-id', 'backend-req-test'); + response.setHeader('Content-Type', 'application/json'); + response.end( + JSON.stringify({ is_success: true, result: { assistant: [{ type: 'text', text: 'ok' }] } }), + ); + }); + }); + + try { + await mkdir(join(kimiHome, 'credentials'), { recursive: true }); + await writeFile( + join(kimiHome, 'credentials', 'kimi-code.json'), + JSON.stringify({ access_token: 'test-token', expires_at: 4_102_444_800 }), + 'utf8', + ); + await listen(server); + + const address = server.address(); + if (address === null || typeof address === 'string') { + throw new Error('Expected an ephemeral TCP port for the test server.'); + } + + child = spawn(process.execPath, [SERVER_ENTRY], { + cwd: REPO_ROOT, + env: { + ...process.env, + KIMI_CODE_HOME: kimiHome, + KIMI_DATASOURCE_API_URL: `http://127.0.0.1:${address.port}`, + }, + stdio: ['pipe', 'pipe', 'pipe'], + }); + const client = createRpcClient(child); + + await client.request('initialize', {}); + const result = await client.request('tools/call', { + name: 'get_data_source_desc', + arguments: { name: 'yuandian_law' }, + }); + + const text = (result.result as { content: Array<{ text: string }> }).content[0]!.text; + expect(text).toContain('[kimi-datasource] request-id: backend-req-test · tool-call-id:'); + } finally { + child?.stdin.end(); + child?.kill(); + await closeServer(server); + await rm(tempDir, { recursive: true, force: true }); + } + }); }); // Pin the expected credential file name to the canonical OAuth-key resolver so diff --git a/docs/en/customization/plugins.md b/docs/en/customization/plugins.md index d2d71d4b5..ef43f354c 100644 --- a/docs/en/customization/plugins.md +++ b/docs/en/customization/plugins.md @@ -55,7 +55,7 @@ Network requests only go through `github.com` redirects and `codeload.github.com ## Kimi Datasource -Kimi Datasource is the official Kimi Code data plugin. It lets you query financial market data, macroeconomic indicators, corporate registration records, and academic literature in natural language — no manual API calls or data account registration required. +Kimi Datasource is the official Kimi Code data plugin. It lets you query financial market data, macroeconomic indicators, corporate registration records, academic literature, and Chinese laws and regulations in natural language — no manual API calls or data account registration required. ### Installation @@ -79,6 +79,8 @@ Once installed, describe your need in natural language and Kimi Code will automa **Literature review acceleration**: Tracing the research arc of RLHF? Get the most-cited papers, key authors, and core findings in seconds, so your literature review outline takes shape in half the time. +**On-the-spot legal lookup**: Stuck on which statute governs a residence-right contract dispute? Pinpoint the relevant Civil Code articles — full text, authority level, and validity — then pull a few comparable precedents to back them up, without digging through statute databases. + ### Coverage | Category | Scope | @@ -87,6 +89,7 @@ Once installed, describe your need in natural language and Kimi Code will automa | Macroeconomic data | World Bank data for 189 countries, 50+ years of time series (GDP, trade, population, climate, and more) | | Corporate data | Business registration, equity chain, legal risk, and related-entity graph for mainland Chinese companies | | Academic literature | Millions of papers across physics, mathematics, CS, quantitative finance, economics — including preprints | +| Legal | Chinese laws, regulations, and judicial cases — semantic/keyword search and detail lookup for statutes across all authority levels (constitution, laws, judicial interpretations, departmental rules), plus ordinary and authoritative case search | ### Notes diff --git a/docs/zh/customization/plugins.md b/docs/zh/customization/plugins.md index f851ea8fe..46fe39c08 100644 --- a/docs/zh/customization/plugins.md +++ b/docs/zh/customization/plugins.md @@ -55,7 +55,7 @@ Plugin 管理器会展示每个安装的来源和信任徽章:`kimi-official` ## Kimi Datasource -Kimi Datasource 是 Kimi Code 官方数据插件,让你通过自然语言直接查询金融行情、宏观经济、企业工商和学术文献,无需手动调用接口或申请任何数据账号。 +Kimi Datasource 是 Kimi Code 官方数据插件,让你通过自然语言直接查询金融行情、宏观经济、企业工商、学术文献和中国法律法规,无需手动调用接口或申请任何数据账号。 ### 安装 @@ -79,6 +79,8 @@ Kimi Datasource 是 Kimi Code 官方数据插件,让你通过自然语言直 **文献综述加速**:写论文要梳理 RLHF 领域的研究脉络?直接列出高引论文、主要作者和核心结论,综述提纲半小时内成型。 +**法律条文速查**:碰上居住权的合同纠纷,拿不准法条?一句话定位《民法典》相关条文原文、效力级别和时效性,再顺手拉几个相近判例佐证,不用翻法规库。 + ### 数据覆盖 | 类别 | 覆盖范围 | @@ -87,6 +89,7 @@ Kimi Datasource 是 Kimi Code 官方数据插件,让你通过自然语言直 | 宏观经济 | 世界银行 189 个成员国、50 年以上历史时间序列(GDP、贸易、人口、气候等) | | 企业数据 | 中国大陆境内企业工商信息、股权穿透、司法风险、关联图谱 | | 学术文献 | 物理、数学、计算机、金融、经济等领域百万量级论文,支持预印本查询 | +| 法律法规 | 中国法律法规与司法案例:宪法、法律、司法解释、部门规章等各效力层次的法规语义/关键词检索与详情,普通及权威判例检索 | ### 注意事项 diff --git a/plugins/marketplace.json b/plugins/marketplace.json index baa5da7ad..70544f9d4 100644 --- a/plugins/marketplace.json +++ b/plugins/marketplace.json @@ -5,7 +5,7 @@ "id": "kimi-datasource", "tier": "official", "displayName": "Kimi Datasource", - "version": "3.1.2", + "version": "3.2.0", "description": "Official datasource workflows.", "keywords": ["data", "mcp"], "source": "./official/kimi-datasource" diff --git a/plugins/official/kimi-datasource/CHANGELOG.md b/plugins/official/kimi-datasource/CHANGELOG.md index 9c5280f25..e6918fd0b 100644 --- a/plugins/official/kimi-datasource/CHANGELOG.md +++ b/plugins/official/kimi-datasource/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 3.2.0 - 2026-06-10 + +- Add the `yuandian_law` data source (元典法律数据库) for Chinese laws/regulations and judicial case search. +- Append a trace line (`request-id` / `tool-call-id`) to every tool result so failures can be correlated with backend logs. + ## 3.1.2 - 2026-06-09 - Use OAuth credentials and datasource endpoints that match the active Kimi Code environment. diff --git a/plugins/official/kimi-datasource/SKILL.md b/plugins/official/kimi-datasource/SKILL.md index 21b91b6ec..d9b39e621 100644 --- a/plugins/official/kimi-datasource/SKILL.md +++ b/plugins/official/kimi-datasource/SKILL.md @@ -1,8 +1,8 @@ --- name: kimi-datasource description: | - Universal data-source assistant. Use this skill when the user wants external structured data such as stocks, financial reports, technical indicators, A-share/HK/US markets, global macroeconomics, Chinese enterprise registry information, arXiv papers, or Google Scholar results. - This plugin exposes tools via MCP server `plugin-kimi-datasource-data`; call them in the flow `mcp__plugin-kimi-datasource-data__get_data_source_desc` → `mcp__plugin-kimi-datasource-data__call_data_source_tool`. + Universal data-source assistant. Use this skill when the user wants external structured data such as stocks, financial reports, technical indicators, A-share/HK/US markets, global macroeconomics, Chinese enterprise registry information, arXiv papers, Google Scholar results, or Chinese laws/regulations and judicial cases. + This plugin exposes tools via MCP server `plugin-kimi-datasource_data`; call them in the flow `mcp__plugin-kimi-datasource_data__get_data_source_desc` → `mcp__plugin-kimi-datasource_data__call_data_source_tool`. --- # kimi-datasource — 通用数据源助手 @@ -11,8 +11,8 @@ description: | 本 skill 使用 datasource MCP server 注册的两个工具,不要通过 Bash 手动执行脚本: -- `mcp__plugin-kimi-datasource-data__get_data_source_desc` -- `mcp__plugin-kimi-datasource-data__call_data_source_tool` +- `mcp__plugin-kimi-datasource_data__get_data_source_desc` +- `mcp__plugin-kimi-datasource_data__call_data_source_tool` 这两个工具由 Kimi Code 托管执行,参数直接按 tool schema 传 JSON。 @@ -20,7 +20,7 @@ description: | ## 1. 这个 skill 提供什么能力 -本 plugin 后面挂了 6 个外部数据源。每一行的"数据源名"就是传给 `get_data_source_desc` 的 `name`。 +本 plugin 后面挂了 7 个外部数据源。每一行的"数据源名"就是传给 `get_data_source_desc` 的 `name`。 | 能力域 | 数据源名 | 典型问题 | |---|---|---| @@ -30,6 +30,7 @@ description: | | **中国企业工商信息** | `tianyancha` | "字节跳动股东"、"比亚迪司法风险"、"宁德时代专利" | | **arXiv 论文预印本** | `arxiv` | "找 RAG 综述"、"下载 2406.xxxxx" | | **Google Scholar 学术搜索** | `scholar` | "Hinton 最新论文"、"transformer 综述高引文献" | +| **中国法律法规 / 司法案例** | `yuandian_law` | "民法典关于居住权的规定"、"帮我查劳动合同解除的相关法条"、"找几个不当得利的判例" | **不支持的能力**:通用 Web 搜索 / 实时新闻。问到这类问题,告诉用户当前数据源不覆盖。 @@ -51,16 +52,16 @@ description: | ### 例 1:用户问"茅台最近一年走势" 1. 股票走势 → `stock_finance_data` -2. 调用 `mcp__plugin-kimi-datasource-data__get_data_source_desc`,参数 `{"name":"stock_finance_data"}` +2. 调用 `mcp__plugin-kimi-datasource_data__get_data_source_desc`,参数 `{"name":"stock_finance_data"}` 3. 从文档里找到"获取历史价格"那个 API,看它要 `ticker / start_date / end_date / file_path` 等 4. 用 web_search 核对 → 茅台 = `600519.SH` -5. 调用 `mcp__plugin-kimi-datasource-data__call_data_source_tool`,参数形如 `{"data_source_name":"stock_finance_data","api_name":"<文档里写的 api>","params":{"ticker":"600519.SH","start_date":"...","end_date":"...","file_path":"/tmp/mao_1y.csv"}}` +5. 调用 `mcp__plugin-kimi-datasource_data__call_data_source_tool`,参数形如 `{"data_source_name":"stock_finance_data","api_name":"<文档里写的 api>","params":{"ticker":"600519.SH","start_date":"...","end_date":"...","file_path":"/tmp/mao_1y.csv"}}` ### 例 2:用户问"找几篇 retrieval augmented generation 的综述" 1. 论文搜索 → `arxiv`(或 `scholar`,arxiv 更适合预印本,scholar 引用更全) -2. 调用 `mcp__plugin-kimi-datasource-data__get_data_source_desc`,参数 `{"name":"arxiv"}` +2. 调用 `mcp__plugin-kimi-datasource_data__get_data_source_desc`,参数 `{"name":"arxiv"}` 3. 从文档里找到搜索类 API,看它要 `query / file_path / max_results` 等 4. 执行 `call_data_source_tool` @@ -68,7 +69,7 @@ description: | ### 例 3:用户问"字节跳动有哪些股东" 1. 企业工商 → `tianyancha` -2. 调用 `mcp__plugin-kimi-datasource-data__get_data_source_desc`,参数 `{"name":"tianyancha"}` +2. 调用 `mcp__plugin-kimi-datasource_data__get_data_source_desc`,参数 `{"name":"tianyancha"}` 3. 注意:tianyancha 的 API 是动态注册的,文档会指引你**先用搜索类接口找到合适的 API 名,再调用** 4. **必须使用企业全称**("北京字节跳动科技有限公司"),不要用简称。不知道全称就先用 tianyancha 文档里的"公司搜索"接口查 diff --git a/plugins/official/kimi-datasource/bin/kimi-datasource.mjs b/plugins/official/kimi-datasource/bin/kimi-datasource.mjs index 5f44ef92a..f8ad0087b 100755 --- a/plugins/official/kimi-datasource/bin/kimi-datasource.mjs +++ b/plugins/official/kimi-datasource/bin/kimi-datasource.mjs @@ -18,7 +18,7 @@ import { arch, homedir, hostname, release, type } from 'node:os'; import path from 'node:path'; import readline from 'node:readline'; -const VERSION = '3.1.2'; +const VERSION = '3.2.0'; const DEFAULT_KIMI_CODE_OAUTH_HOST = 'https://auth.kimi.com'; const DEFAULT_KIMI_CODE_BASE_URL = 'https://api.kimi.com/coding/v1'; const API_URL = datasourceApiUrl(); @@ -65,6 +65,7 @@ const TOOLS = [ 'tianyancha', 'arxiv', 'scholar', + 'yuandian_law', ], description: 'Data source name.', }, @@ -123,17 +124,18 @@ async function runTool(params) { isError: true, }; } + const trace = {}; try { const built = handler.buildParams(args); - const response = await callKimiTool(handler.method, built); + const response = await callKimiTool(handler.method, built, trace); const fileWarnings = await writeResponseFiles(response, expectedResponseFilePath(built)); const text = extractText(response); const formatted = (handler.format?.(text, built) ?? text).trim(); - return { content: [{ type: 'text', text: appendWarnings(formatted, fileWarnings) }] }; + return { content: [{ type: 'text', text: appendTrace(appendWarnings(formatted, fileWarnings), trace) }] }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { - content: [{ type: 'text', text: message }], + content: [{ type: 'text', text: appendTrace(message, trace) }], isError: true, }; } @@ -206,6 +208,25 @@ function appendWarnings(text, warnings) { return `${text}\n\n${warnings.join('\n')}`; } +// Pick the backend request id from the response headers, if the gateway sends one. +function extractRequestId(headers) { + for (const key of ['x-request-id', 'x-trace-id', 'x-msh-request-id', 'x-msh-trace-id', 'request-id']) { + const value = headers.get(key); + if (typeof value === 'string' && value.trim().length > 0) return value.trim(); + } + return undefined; +} + +// Append a trace line so failures can be correlated with backend logs. The +// tool-call-id is the `X-Msh-Tool-Call-Id` header we send on every request. +function appendTrace(text, trace) { + if (trace === undefined || trace.toolCallId === undefined) return text; + const parts = []; + if (trace.requestId !== undefined) parts.push(`request-id: ${trace.requestId}`); + parts.push(`tool-call-id: ${trace.toolCallId}`); + return `${text}\n\n[kimi-datasource] ${parts.join(' · ')}`; +} + function resolveKimiHome() { const explicit = process.env.KIMI_CODE_HOME?.trim(); return explicit && explicit.length > 0 ? explicit : path.join(homedir(), '.kimi-code'); @@ -287,8 +308,10 @@ async function loadAccessToken() { return { kimiHome, token }; } -async function callKimiTool(method, params) { +async function callKimiTool(method, params, trace = {}) { const { kimiHome, token } = await loadAccessToken(); + const toolCallId = randomUUID(); + trace.toolCallId = toolCallId; const controller = new AbortController(); const timeout = setTimeout(() => { controller.abort(); @@ -296,10 +319,11 @@ async function callKimiTool(method, params) { try { const response = await fetch(API_URL, { method: 'POST', - headers: await buildHeaders(kimiHome, token), + headers: await buildHeaders(kimiHome, token, toolCallId), body: JSON.stringify({ method, params }), signal: controller.signal, }); + trace.requestId = extractRequestId(response.headers); const text = await response.text(); if (!response.ok) { throw new Error(`HTTP ${response.status} error: ${text}`); @@ -319,11 +343,11 @@ async function callKimiTool(method, params) { } } -async function buildHeaders(kimiHome, token) { +async function buildHeaders(kimiHome, token, toolCallId) { return { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', - 'X-Msh-Tool-Call-Id': randomUUID(), + 'X-Msh-Tool-Call-Id': toolCallId, 'X-Msh-Platform': asciiHeader(process.env.KIMI_MSH_PLATFORM ?? 'kimi-code-cli'), 'X-Msh-Version': asciiHeader(process.env.KIMI_MSH_VERSION ?? VERSION), 'X-Msh-Device-Name': asciiHeader(process.env.KIMI_MSH_DEVICE_NAME ?? hostname()), diff --git a/plugins/official/kimi-datasource/kimi.plugin.json b/plugins/official/kimi-datasource/kimi.plugin.json index 3f43faba0..8ba677de7 100644 --- a/plugins/official/kimi-datasource/kimi.plugin.json +++ b/plugins/official/kimi-datasource/kimi.plugin.json @@ -1,8 +1,8 @@ { "name": "kimi-datasource", - "version": "3.1.2", - "description": "Finance, macro, enterprise, and academic data tools for Kimi Code.", - "keywords": ["finance", "data-source", "mcp"], + "version": "3.2.0", + "description": "Finance, macro, enterprise, academic, and legal data tools for Kimi Code.", + "keywords": ["finance", "data-source", "mcp", "legal"], "mcpServers": { "data": { "command": "node", @@ -12,7 +12,7 @@ }, "interface": { "displayName": "Kimi Datasource", - "shortDescription": "Finance, macro, enterprise, and academic data tools", + "shortDescription": "Finance, macro, enterprise, academic, and legal data tools", "developerName": "Moonshot AI" } }