HarperFast / HarperFast/harper
MCP resource subscriptions: switch from async-iterator to listener delivery
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Problem
`components/mcp/resources.ts:421` consumes table subscriptions with `for await`, paying the full async-iterator machinery (~1.1 KB idle heap + generator resume + microtask hop per event, measured against the repo's `IterableEventQueue`) for a consumer that needs none of it: the loop body is `update?.acknowledge?.(); onUpdate();` — no payload use, no ordering requirement, no backpressure.
## Proposal
Switch MCP resource subscriptions to the `'data'`-listener delivery path. This is the one `subscribe()` consumer with no blocker:
- it already guards `typeof result[Symbol.asyncIterator] === 'function'` and degrades gracefully,
- teardown via `stream.end?.()` keeps working,
- it subscribes with `omitCurrent: true`, so the replay/listener backpressure interaction doesn't apply.
Note the MCP server-push channel (`components/mcp/sse.ts:19-24`) already deliberately uses the listener path for teardown reasons — this aligns resource subscriptions with it.
---
_Filed by an AI agent (Claude Code) from a subscription-path memory/CPU investigation._
Contributor guide
Research direction
Start at components/mcp/resources.ts:421, then compare the existing listener-based teardown path in components/mcp/sse.ts:19-24. Trace subscribe() with omitCurrent: true and confirm that data-listener delivery preserves acknowledge, onUpdate, and stream.end?.() behavior without requiring the async iterator; done means the resource subscription uses the listener path and still tears down correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- backend, performance
- Issue type
- Refactor
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100