CopilotKit / CopilotKit/CopilotKit
@ag-ui/mcp-middleware@0.0.1 pins @ag-ui/client 0.0.54, nesting a 7.3 MB duplicate tree in every runtime install
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 4.6k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 444
Description
Every @copilotkit/runtime install ships a second, older copy of the @ag-ui client tree nested under @ag-ui/mcp-middleware.
What a real install looks like
Installing the published @copilotkit/runtime@1.70.1 + @copilotkit/react-core@1.70.1 into an empty project:
node_modules/@ag-ui/core: 0.0.59 <- what react-core and runtime resolve
node_modules/@ag-ui/client: 0.0.59
node_modules/@ag-ui/mcp-middleware/node_modules/@ag-ui/client: 0.0.54
node_modules/@ag-ui/mcp-middleware/node_modules/@ag-ui/core: 0.0.54
node_modules/@ag-ui/mcp-middleware/node_modules/@ag-ui/proto: 0.0.54
The nested tree is 7.3 MB, out of 22 MB total for node_modules/@ag-ui.
Cause
@ag-ui/mcp-middleware@0.0.1 declares an exact pin:
{ "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "@ag-ui/client": "0.0.54" } }
0.0.1 is the only version ever published, so the pin cannot be satisfied by dedupe no matter what the host resolves. It is a hard dependency, not a peer.
The middleware needs @ag-ui/client for exactly one thing. Instrumenting the module load shows it reads a single property off the package:
exports of mcp-middleware: DEFAULT_MAX_ITERATIONS, MAX_TOOL_NAME_LENGTH, MCPMiddleware, MCP_TOOL_NAME_PREFIX
properties read off @ag-ui/client: Middleware
Middleware is the abstract base class it extends. Pulling that one class in as a hard exact dependency drags @ag-ui/client -> @ag-ui/core -> @ag-ui/proto along with it.
This is not a correctness bug today
Stating this explicitly so nobody escalates it. The nested copy is loaded at runtime, and MCPMiddleware is constructed from copy 0.0.54 before being attached in attachIntelligenceEnterpriseLearning (packages/runtime/src/v2/runtime/handlers/shared/agent-utils.ts) to an agent built from copy 0.0.59. That cross-copy attachment works, for two reasons I verified:
AbstractAgent.use()duck-types. It does noinstanceofcheck, it just pushes the object:use(...e){ let t = e.map(e => typeof e === "function" ? new B(e) : e); return this.middlewares.push(...t), this }- The
Middlewareabstract class declaration is byte-identical between@ag-ui/client0.0.54 and 0.0.59.
The nested copy's Zod event schemas are never used for validation either, so this does not reintroduce the null-parentMessageId class of failure from #2788.
Why it is still worth fixing
- 7.3 MB of duplicate install weight on every runtime consumer.
- The contract identity is a coincidence, not a guarantee. Point 2 above holds for the current pair of versions only. The pin drifts one release further behind every time ag-ui ships. Whenever
Middlewaredoes change, enterprise-learning MCP attachment breaks across the copy boundary, and it breaks silently, because nothing type-checks the boundary at runtime. - Duplicate-dependency and stale-transitive scanners flag it continuously.
Two fixes, in different repos
1. Upstream, ag-ui (the real fix). Republish @ag-ui/mcp-middleware with @ag-ui/client as a peerDependency (or at minimum a range rather than an exact pin), so it dedupes onto the host's copy. This is the same shape @ag-ui/mcp-apps-middleware@0.0.3 already uses, which is why that package produces no nested copy.
2. Here, the stale override. The root package.json carries:
"@ag-ui/mcp-middleware>@ag-ui/client": "0.0.53"
Added in c3f7961242 (2026-06-04) alongside adopting @ag-ui/mcp-middleware@0.0.1, when the repo itself was on 0.0.53 and the override collapsed the tree to one copy. The repo has since moved to 0.0.59 and the override never followed. It now pins our workspace copy to 0.0.53, which is older than even the upstream 0.0.54, and it dedupes nothing. Note that a pnpm override is workspace-only, so it has never affected published consumers at all.
Bump it in lockstep with the rest of the @ag-ui/* pins, or delete it once fix 1 lands.
Verification
Reproduce the copy list with:
mkdir /tmp/dupe && cd /tmp/dupe && npm init -y >/dev/null
npm install @copilotkit/runtime@1.70.1 @copilotkit/react-core@1.70.1
find node_modules -path "*@ag-ui/*/package.json" -maxdepth 5 \
-exec sh -c 'echo "$(dirname {}): $(node -p "require(\"./{}\").version")"' \;
du -sh node_modules/@ag-ui/mcp-middleware/node_modules
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the root package.json override for @ag-ui/mcp-middleware>@ag-ui/client and compare it with the other @ag-ui pins, then inspect the lockfile and the commit that introduced it. Reproduce the dependency tree with the provided npm install and find commands. Done means the workspace no longer retains the stale override, or it is aligned with the current @ag-ui version; the upstream peer-dependency fix is a separate repository task.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- build-system, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100