Skip to content

[Bug]: MCP tools/list ignores nextCursor, so tools past page 1 are undiscoverable and uncallable #565

Description

@divya0795

Description

The MCP client never follows tools/list pagination. The MCP spec paginates tools/list with a top-level nextCursor: a client must re-issue the request with { "cursor": "<nextCursor>" } until the field is absent. Both JSON-RPC clients in src/connectors/mcp-client.ts call it exactly once with empty params:

// src/connectors/mcp-client.ts:462 (StdioJsonRpcClient) and :608 (HttpJsonRpcClient)
listTools(): Promise<unknown> {
  return this.request("tools/list", {});
}

extractToolValues (:365) then reads only result.tools from that single page, so every tool after the first page is silently dropped from discovery.

That is not just a display gap: callMcpConnectorTool hard-rejects any tool name missing from the discovered set (src/connectors/mcp-runtime.ts:88-92):

MCP tool <name> was not returned by tools/list for <connector>. Run openwiki_list_mcp_tools first and use an exact discovered name.

So on any MCP server that paginates, valid read-only tools become permanently uncallable, and the error message points the user at openwiki_list_mcp_tools — which is itself truncated to page 1, so the advice can never resolve it.

Both transports are affected (stdio and HTTP).

Steps to Reproduce

  1. Configure an MCP connector against a server whose tools/list paginates — page 1 returns some tools plus a nextCursor, page 2 returns the rest. (Hosted servers with large tool sets, e.g. Notion, do this.)
  2. Run openwiki_list_mcp_tools for that connector.
  3. Note that only the page-1 tools are listed.
  4. Call openwiki_call_mcp_tool with the exact name of a read-only tool that lives on page 2.

Minimal reproduction of the underlying behavior — a stub server that returns:

{"tools": [{"name": "page-one-tool"}], "nextCursor": "cursor-2"}

then, for a request carrying {"cursor": "cursor-2"}:

{"tools": [{"name": "page-two-tool"}]}

Expected Behavior

listMcpTools discovers the complete tool set across all pages, so page-two-tool is listed and can be called.

Actual Behavior

Only page-one-tool is discovered. The second request is never sent — tools/list is issued once with {} and nextCursor is ignored. Calling page-two-tool throws MCP tool page-two-tool was not returned by tools/list, even though the tool is valid and read-only.

Environment

  • OS: Windows 11
  • Node.js version: v24.18.1
  • OpenWiki version: main @ 398ebad

Additional Context

The sibling stdio/HTTP clients both expose an identical private request(method, params), so a single shared pagination helper can fix both without duplicating the loop. Any fix should bound the loop (stop on a repeated cursor and cap total pages) so a misbehaving server that always returns a cursor cannot spin forever.

I have a fix ready and will open a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions