From d509abe11e8608fae79a8ebcbca31fc113841e63 Mon Sep 17 00:00:00 2001 From: cxh-mac <415026664@qq.com> Date: Sat, 11 Jul 2026 14:21:47 +0800 Subject: [PATCH] refactor(plugin): shorten plugin MCP tool qualified names Drop the redundant literal 'plugin-' prefix from plugin MCP server runtime names, and omit the server-name segment entirely when a plugin declares only one MCP server (the common case). This shortens every plugin-provided MCP tool's qualified name, e.g.: mcp__plugin-ifind-mcp_s__get_financial_statements -> mcp__ifind-mcp__get_financial_statements Breaking change: previously saved per-tool permission approvals for plugin MCP tools will need to be re-granted after upgrading, since the wire-level tool name changes. --- .changeset/shorten-plugin-mcp-tool-names.md | 5 ++ packages/agent-core/src/plugin/manager.ts | 26 ++++++---- .../agent-core/test/plugin/manager.test.ts | 47 ++++++++++++++----- .../agent-core/test/rpc/plugins-rpc.test.ts | 2 +- plugins/marketplace.json | 2 +- plugins/official/kimi-datasource/CHANGELOG.md | 4 ++ plugins/official/kimi-datasource/SKILL.md | 14 +++--- .../official/kimi-datasource/kimi.plugin.json | 2 +- 8 files changed, 69 insertions(+), 33 deletions(-) create mode 100644 .changeset/shorten-plugin-mcp-tool-names.md diff --git a/.changeset/shorten-plugin-mcp-tool-names.md b/.changeset/shorten-plugin-mcp-tool-names.md new file mode 100644 index 0000000000..7ef5f4dfbb --- /dev/null +++ b/.changeset/shorten-plugin-mcp-tool-names.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": minor +--- + +Shorten plugin MCP tool names by dropping the redundant `plugin-` prefix and the server-name segment for single-server plugins (e.g. `mcp__plugin-foo-mcp_s__bar` becomes `mcp__foo-mcp__bar`). Existing per-tool permission approvals for plugin MCP tools will need to be re-granted after upgrading. diff --git a/packages/agent-core/src/plugin/manager.ts b/packages/agent-core/src/plugin/manager.ts index 65992acae3..03444b6dd3 100644 --- a/packages/agent-core/src/plugin/manager.ts +++ b/packages/agent-core/src/plugin/manager.ts @@ -230,9 +230,10 @@ export class PluginManager { const out: Record = {}; for (const record of this.records.values()) { if (!record.enabled || record.state !== 'ok' || record.manifest === undefined) continue; - for (const [name, config] of Object.entries(record.manifest.mcpServers ?? {})) { + const entries = Object.entries(record.manifest.mcpServers ?? {}); + for (const [name, config] of entries) { if (!isMcpServerEnabled(record, name, config)) continue; - out[pluginMcpRuntimeName(record.id, name)] = withPluginMcpRuntime( + out[pluginMcpRuntimeName(record.id, name, entries.length)] = withPluginMcpRuntime( withMcpServerEnabled(config, true), record.root, this.kimiHomeDir, @@ -443,8 +444,9 @@ function isMcpServerEnabled( } function pluginMcpServersInfo(record: PluginRecord): readonly PluginMcpServerInfo[] { - return Object.entries(record.manifest?.mcpServers ?? {}) - .map(([name, config]) => pluginMcpServerInfo(record, name, config)) + const entries = Object.entries(record.manifest?.mcpServers ?? {}); + return entries + .map(([name, config]) => pluginMcpServerInfo(record, name, config, entries.length)) .toSorted((a, b) => a.name.localeCompare(b.name)); } @@ -452,11 +454,12 @@ function pluginMcpServerInfo( record: PluginRecord, name: string, config: McpServerConfig, + serverCount: number, ): PluginMcpServerInfo { if (config.transport === 'http' || config.transport === 'sse') { return { name, - runtimeName: pluginMcpRuntimeName(record.id, name), + runtimeName: pluginMcpRuntimeName(record.id, name, serverCount), enabled: isMcpServerEnabled(record, name, config), transport: config.transport, url: config.url, @@ -465,7 +468,7 @@ function pluginMcpServerInfo( } return { name, - runtimeName: pluginMcpRuntimeName(record.id, name), + runtimeName: pluginMcpRuntimeName(record.id, name, serverCount), enabled: isMcpServerEnabled(record, name, config), transport: 'stdio', command: config.command, @@ -479,10 +482,13 @@ function withMcpServerEnabled(config: McpServerConfig, enabled: boolean): McpSer return { ...config, enabled }; } -function pluginMcpRuntimeName(pluginId: string, serverName: string): string { - // Plugin ids cannot contain ":", so this keeps plugin/server pairs unambiguous - // even when either side contains "-". - return `plugin-${pluginId}:${serverName}`; +function pluginMcpRuntimeName(pluginId: string, serverName: string, serverCount: number): string { + // Plugin ids are unique and cannot contain ":", so a bare pluginId is + // already unambiguous when there is nothing to disambiguate (the common + // single-server case). Only append ":serverName" when a plugin declares + // more than one MCP server — that keeps cross-plugin pairs unambiguous + // even when either half contains "-" (e.g. "a-b"+"c" vs "a"+"b-c"). + return serverCount > 1 ? `${pluginId}:${serverName}` : pluginId; } function withPluginMcpRuntime( diff --git a/packages/agent-core/test/plugin/manager.test.ts b/packages/agent-core/test/plugin/manager.test.ts index 26decd8e50..3beb25d32a 100644 --- a/packages/agent-core/test/plugin/manager.test.ts +++ b/packages/agent-core/test/plugin/manager.test.ts @@ -366,7 +366,7 @@ describe('PluginManager', () => { expect(manager.info('demo')?.mcpServers).toContainEqual( expect.objectContaining({ name: 'finance', - runtimeName: 'plugin-demo:finance', + runtimeName: 'demo:finance', enabled: true, command: 'finance-mcp', }), @@ -374,7 +374,7 @@ describe('PluginManager', () => { expect(manager.info('demo')?.mcpServers).toContainEqual( expect.objectContaining({ name: 'events', - runtimeName: 'plugin-demo:events', + runtimeName: 'demo:events', transport: 'sse', url: 'https://example.com/sse', }), @@ -388,15 +388,15 @@ describe('PluginManager', () => { expect(manager.enabledMcpServers()).toEqual( expect.objectContaining({ - 'plugin-demo:finance': expect.objectContaining({ + 'demo:finance': expect.objectContaining({ command: 'finance-mcp', cwd: managedRoot, env: expect.objectContaining({ KIMI_CODE_HOME: home, KIMI_PLUGIN_ROOT: managedRoot }), }), - 'plugin-demo:docs': expect.objectContaining({ + 'demo:docs': expect.objectContaining({ url: 'https://example.com/mcp', }), - 'plugin-demo:events': expect.objectContaining({ + 'demo:events': expect.objectContaining({ transport: 'sse', url: 'https://example.com/sse', }), @@ -405,7 +405,7 @@ describe('PluginManager', () => { await manager.setMcpServerEnabled('demo', 'finance', false); - expect(manager.enabledMcpServers()).not.toHaveProperty('plugin-demo:finance'); + expect(manager.enabledMcpServers()).not.toHaveProperty('demo:finance'); expect(manager.summaries()[0]).toEqual( expect.objectContaining({ mcpServerCount: 3, @@ -449,7 +449,7 @@ describe('PluginManager', () => { ); expect(manager.enabledMcpServers()).toEqual( expect.objectContaining({ - 'plugin-demo:finance': expect.objectContaining({ + demo: expect.objectContaining({ command: 'finance-mcp', enabled: true, }), @@ -461,7 +461,26 @@ describe('PluginManager', () => { expect(reloaded.info('demo')?.mcpServers).toContainEqual( expect.objectContaining({ name: 'finance', enabled: true }), ); - expect(reloaded.enabledMcpServers()).toHaveProperty('plugin-demo:finance'); + expect(reloaded.enabledMcpServers()).toHaveProperty('demo'); + }); + + it('omits the server segment when a plugin declares a single MCP server', async () => { + const home = await makeKimiHome(); + const root = await makePlugin('demo', { + mcpServers: { + finance: { command: 'finance-mcp' }, + }, + }); + const manager = new PluginManager({ kimiHomeDir: home }); + await manager.load(); + await manager.install(root); + + expect(manager.info('demo')?.mcpServers).toContainEqual( + expect.objectContaining({ name: 'finance', runtimeName: 'demo' }), + ); + expect(manager.enabledMcpServers()).toEqual( + expect.objectContaining({ demo: expect.objectContaining({ command: 'finance-mcp' }) }), + ); }); it('uses unambiguous runtime names for plugin MCP servers', async () => { @@ -469,11 +488,13 @@ describe('PluginManager', () => { const first = await makePlugin('a-b', { mcpServers: { c: { command: 'first-mcp' }, + d: { command: 'first-mcp-2' }, }, }); const second = await makePlugin('a', { mcpServers: { 'b-c': { command: 'second-mcp' }, + e: { command: 'second-mcp-2' }, }, }); const manager = new PluginManager({ kimiHomeDir: home }); @@ -482,20 +503,20 @@ describe('PluginManager', () => { await manager.install(second); expect(manager.info('a-b')?.mcpServers).toContainEqual( - expect.objectContaining({ name: 'c', runtimeName: 'plugin-a-b:c' }), + expect.objectContaining({ name: 'c', runtimeName: 'a-b:c' }), ); expect(manager.info('a')?.mcpServers).toContainEqual( - expect.objectContaining({ name: 'b-c', runtimeName: 'plugin-a:b-c' }), + expect.objectContaining({ name: 'b-c', runtimeName: 'a:b-c' }), ); const servers = manager.enabledMcpServers(); expect(servers).toEqual( expect.objectContaining({ - 'plugin-a-b:c': expect.objectContaining({ command: 'first-mcp' }), - 'plugin-a:b-c': expect.objectContaining({ command: 'second-mcp' }), + 'a-b:c': expect.objectContaining({ command: 'first-mcp' }), + 'a:b-c': expect.objectContaining({ command: 'second-mcp' }), }), ); - expect(Object.keys(servers)).toHaveLength(2); + expect(Object.keys(servers)).toHaveLength(4); }); it('enabledMcpServers() excludes disabled plugins', async () => { diff --git a/packages/agent-core/test/rpc/plugins-rpc.test.ts b/packages/agent-core/test/rpc/plugins-rpc.test.ts index fa7f9fd843..0799c79d61 100644 --- a/packages/agent-core/test/rpc/plugins-rpc.test.ts +++ b/packages/agent-core/test/rpc/plugins-rpc.test.ts @@ -128,7 +128,7 @@ oauth = { storage = "file", key = "oauth/kimi-code-env-1234", oauth_host = "http } ).mergePluginMcpConfig(undefined); - expect(mcpConfig.servers['plugin-kimi-datasource:data']?.env).toEqual( + expect(mcpConfig.servers['kimi-datasource']?.env).toEqual( expect.objectContaining({ KIMI_CODE_BASE_URL: 'https://api.dev.example.test/coding/v1', KIMI_CODE_OAUTH_HOST: 'https://auth.dev.example.test', diff --git a/plugins/marketplace.json b/plugins/marketplace.json index b351575322..8f3d6d7695 100644 --- a/plugins/marketplace.json +++ b/plugins/marketplace.json @@ -5,7 +5,7 @@ "id": "kimi-datasource", "tier": "official", "displayName": "Kimi Datasource", - "version": "3.2.0", + "version": "3.2.1", "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 e6918fd0b5..c29c9f9e88 100644 --- a/plugins/official/kimi-datasource/CHANGELOG.md +++ b/plugins/official/kimi-datasource/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 3.2.1 - 2026-07-11 + +- Update the tool-name examples in this skill to match the shorter `mcp__kimi-datasource__*` naming (previously `mcp__plugin-kimi-datasource_data__*`). + ## 3.2.0 - 2026-06-10 - Add the `yuandian_law` data source (元典法律数据库) for Chinese laws/regulations and judicial case search. diff --git a/plugins/official/kimi-datasource/SKILL.md b/plugins/official/kimi-datasource/SKILL.md index d9b39e6211..b0a749995d 100644 --- a/plugins/official/kimi-datasource/SKILL.md +++ b/plugins/official/kimi-datasource/SKILL.md @@ -2,7 +2,7 @@ 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, 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`. + This plugin exposes tools via MCP server `kimi-datasource`; call them in the flow `mcp__kimi-datasource__get_data_source_desc` → `mcp__kimi-datasource__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__kimi-datasource__get_data_source_desc` +- `mcp__kimi-datasource__call_data_source_tool` 这两个工具由 Kimi Code 托管执行,参数直接按 tool schema 传 JSON。 @@ -52,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__kimi-datasource__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__kimi-datasource__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__kimi-datasource__get_data_source_desc`,参数 `{"name":"arxiv"}` 3. 从文档里找到搜索类 API,看它要 `query / file_path / max_results` 等 4. 执行 `call_data_source_tool` @@ -69,7 +69,7 @@ description: | ### 例 3:用户问"字节跳动有哪些股东" 1. 企业工商 → `tianyancha` -2. 调用 `mcp__plugin-kimi-datasource_data__get_data_source_desc`,参数 `{"name":"tianyancha"}` +2. 调用 `mcp__kimi-datasource__get_data_source_desc`,参数 `{"name":"tianyancha"}` 3. 注意:tianyancha 的 API 是动态注册的,文档会指引你**先用搜索类接口找到合适的 API 名,再调用** 4. **必须使用企业全称**("北京字节跳动科技有限公司"),不要用简称。不知道全称就先用 tianyancha 文档里的"公司搜索"接口查 diff --git a/plugins/official/kimi-datasource/kimi.plugin.json b/plugins/official/kimi-datasource/kimi.plugin.json index 8ba677de73..d43f1a59c2 100644 --- a/plugins/official/kimi-datasource/kimi.plugin.json +++ b/plugins/official/kimi-datasource/kimi.plugin.json @@ -1,6 +1,6 @@ { "name": "kimi-datasource", - "version": "3.2.0", + "version": "3.2.1", "description": "Finance, macro, enterprise, academic, and legal data tools for Kimi Code.", "keywords": ["finance", "data-source", "mcp", "legal"], "mcpServers": {