MoonshotAI / MoonshotAI/kimi-code

[Bug] MCP tools/list 忽略 nextCursor,遗漏后续页工具

Open
#3,757 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

你运行的 Kimi Code 版本是?

源码复现,commit 46233953795c62051b433956db60c6c218d2cede(未使用已安装 CLI 复现)。发布前已同步上游 main 并复核相关源码。

你使用的是哪个开放平台/订阅?

不适用:不涉及登录/模型请求,源码隔离复现。

你使用的是哪个模型?

不适用:未调用模型。

你的电脑平台是?

uname -mprsLinux 6.18.38-Unraid x86_64 unknown;Node.js v26.5.1

你遇到了什么问题?

源码隔离实验中,只要 MCP server 的工具目录分多页,三个 transport 的 listTools() 都只返回第一页,后续页工具不会进入目录。

stdio/http/sse 均只调用一次 SDK 并返回 result.tools.map,未读取 nextCursor。这里使用模拟 SDK 分页响应;未连接真实生产 MCP server,也未运行完整 CLI。

复现步骤?
  1. checkout 46233953795c62051b433956db60c6c218d2cede,在仓库根目录执行。
  2. 将以下脚本保存到仓库外的 /tmp/kimi-repro-3.mjs,执行 node /tmp/kimi-repro-3.mjs。不需要登录或安装 monorepo 依赖。
  3. 本次实际观测:三个 transport 均仅返回 [{ name: 'first' }],requests: 1;未请求 cursor: 'page2',因此 second 丢失。
import fs from 'node:fs';
import vm from 'node:vm';
import { stripTypeScriptTypes } from 'node:module';
const read = p => fs.readFileSync(p, 'utf8');
const load = (source, extra = {}) => {
  const ctx = vm.createContext(extra);
  vm.runInContext(stripTypeScriptTypes(source), ctx);
  return ctx;
};
for (const transport of ['stdio', 'http', 'sse']) {
  const source = read(`packages/agent-core-v2/src/mcpCore/client-${transport}.ts`);
  const fragment = source.slice(source.indexOf('  async listTools()'), source.indexOf('  async callTool('));
  const ctx = load('class Subject {' + fragment + '}; globalThis.Subject = Subject;', {
    buildRequestOptions: () => ({}), toMcpToolDefinition: x => x,
  });
  const subject = new ctx.Subject();
  const calls = [];
  subject.client = { listTools: async params => {
    calls.push(params);
    return params?.cursor === 'page2'
      ? { tools: [{ name: 'second' }] }
      : { tools: [{ name: 'first' }], nextCursor: 'page2' };
  }};
  console.log({ transport, tools: await subject.listTools(), requests: calls.length });
}

复现边界:从当前源码摘取函数/方法执行,显式模拟依赖边界;不是完整 CLI 或仓库 Vitest 测试。

期望的行为是什么?
  • 返回 nextCursor 时继续携带 cursor 请求,合并所有页工具;单页行为不变。
  • stdio/http/sse 三个入口均覆盖至少两页目录的回归测试。
  • 后续页错误不能被当作完整目录成功返回;沿用现有请求超时机制。
补充信息

这里只报告工具目录分页遗漏,不要求机械移植其他项目的 collector,也不扩展资源分页或新增配置。锁文件固定 @modelcontextprotocol/sdk 1.29.0;核对该包 dist/esm/client/index.js 的 listTools(params, options):仅发一次 tools/list request、缓存该页 metadata 并返回 result,不自动消耗 nextCursor。包源码可查看 https://unpkg.com/@modelcontextprotocol/sdk@1.29.0/dist/esm/client/index.js 。#3688 处理工具调用结果附件,不是工具目录分页。

已检索当前 open/closed issues 和 PR:external editor/signal、surrogate/Unicode/truncation、MCP pagination/nextCursor/listTools 及对应源码符号。未发现与此具体路径和触发条件等价的记录;不据此保证绝无重复。

固定源码、对应测试与参考边界

只运行上述隔离复现,未运行仓库完整测试套件或 Codex 测试;源码引用用于定位与讨论,不代表已经实现修复。

Contribution
  • 我愿意自己提交修复此 bug 的 PR(请先等待维护者在本 issue 中批准)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with listTools() in packages/agent-core-v2/src/mcpCore/client-stdio.ts, client-http.ts, and client-sse.ts, then read the existing client-http.test.ts coverage and connection-manager.ts timeout path. Run the isolated two-page reproduction first. Done means all three transports follow nextCursor, merge every page, preserve single-page behavior, and cover at least a two-page regression case without hiding later-page errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.