Skip to content

feat(mcp): cut GitHub API calls per write (blob inlining, read memoization, stats injection)#63

Merged
ABB65 merged 3 commits into
mainfrom
feat/mcp-api-optimizations
Jul 9, 2026
Merged

feat(mcp): cut GitHub API calls per write (blob inlining, read memoization, stats injection)#63
ABB65 merged 3 commits into
mainfrom
feat/mcp-api-optimizations

Conversation

@ABB65

@ABB65 ABB65 commented Jul 9, 2026

Copy link
Copy Markdown
Member

Three additive, independently-shippable optimizations that cut GitHub API calls per write — the spec Ahmet derived from the 1.6.0 dist bundle, verified against source and adjusted where the source diverged from the bundle. No breaking changes; one minor bump.

M1 — applyPlan blob inlining feat(mcp): inline blob content in GitHub tree entries

applyPlanToGitHub created a blob per changed file (createBlob) then referenced its SHA in the tree. GitHub's Trees API accepts content inline on a tree entry, so the per-file blob POST is unnecessary.

  • Writes carry content directly; deletions keep sha: null. buildTreeEntry becomes synchronous.
  • A write drops from N+3 GitHub mutations to a fixed 3 (createTree + createCommit + updateRef) regardless of file count — directly easing the mutation-rate secondary limit that the high-call-count scenario hits.
  • Verified symmetry the bundle-derived spec missed: the GitLab provider (gitlab/apply-plan.ts) already inlines content in its commit actions — M1 brings GitHub to that parity.
  • Side benefit: no orphan blobs when tree creation fails.

Tests: assert content-in-tree + createBlob never called + a byte-fidelity round-trip (unicode/emoji/newlines). http.test.ts GitHub write path stays green.

M3 — GitHubReader opt-in read memoization feat(mcp): opt-in read memoization for GitHubReader

new GitHubReader(client, repo, { memoize: true }) dedupes repeated (path, ref) reads within one operation across readFile / listDirectory / fileExists.

  • Opt-in, OFF by default — byte-identical behavior without the flag.
  • A rejected read is evicted so a transient error is retried, not cached forever.
  • Load-bearing safety: the provider's own reader (github/provider.ts:42) is constructed once and long-lived, so it does not enable memoization — a reader that outlives a write would serve stale results. Only short-lived read-only consumers opt in (Studio-side; in-repo wiring is a follow-up, since remote validate currently delegates to the provider's long-lived reader).

Tests: off → N getContent (unchanged); on → 1 getContent per (path, ref), keyed by ref, per-method; rejected not cached.

M2 — buildContextChange stats injection feat(mcp): allow injected stats in buildContextChange

buildContextChange(reader, operation, source, { stats }) lets a caller that already knows the model/entry counts skip the O(models·locales) reader walk; only readConfig remains.

  • Emitted context.json is byte-identical to the scanned variant. Parameterless callers unchanged.
  • Verified scope the spec got right, with a correction: buildContextChange has no caller in this repo (Studio consumes it), so this is an additive API — it does not speed up anything local. ContextStats intentionally omits locales (it already comes from readConfig, which stays) to avoid an injected/config mismatch. And writeContext (the local path) is deliberately not changed — it reads local disk (cheap); only the remote reader's HTTP round-trips were worth cutting.
  • Adds the first tests for buildContextChange.

Verification

Targeted (the full blast radius of these surgical, GitHub-provider-scoped changes):

  • apply-plan.test.ts 6/6, reader.test.ts 16/16, context.test.ts 4/4 (new), http.test.ts 16/16.
  • All GitHub + GitLab provider tests + context core/tool tests: 80/80 green.
  • oxlint 0/0, tsc --noEmit clean.

The local / git-transaction / write-path suites are untouched by these changes (LocalProvider and the worktree flow are not on any of these code paths), so they were not re-run.

🤖 Generated with Claude Code

ABB65 added 3 commits July 9, 2026 12:18
applyPlanToGitHub created a blob per changed file (client.rest.git.createBlob)
then referenced its SHA in the tree. GitHub's Trees API accepts file content
inline on a tree entry, so the per-file blob POST is unnecessary: writes now
carry content directly and deletions keep sha: null. A write drops from N+3
GitHub mutations to a fixed 3 (createTree + createCommit + updateRef)
regardless of file count, which directly eases the mutation-rate secondary
limit. buildTreeEntry becomes synchronous (no client needed). Brings GitHub to
parity with the GitLab provider, which already inlines content in its commit
actions.

Tests updated to assert content-in-tree + no createBlob, plus a byte-fidelity
round-trip (unicode/emoji/newlines). http integration path green.
new GitHubReader(client, repo, { memoize: true }) dedupes repeated (path, ref)
reads within one operation across readFile/listDirectory/fileExists, so flows
that re-read the same files (context build, validate) pay one getContent
instead of N. Opt-in and OFF by default — behavior is byte-identical without
the flag. A rejected read is evicted from the memo so a transient error is
retried, not cached forever. The provider's own reader (github/provider.ts) is
long-lived and does NOT enable memoization: a reader that outlives a write
would serve stale results; short-lived read-only consumers opt in explicitly.
buildContextChange walked listModels + readModel + countEntries over the reader
(O(models·locales) round trips on a remote provider) purely to fill
stats.models / stats.entries. A new optional opts.stats lets a caller that
already knows those counts (e.g. Studio's index) skip the walk entirely; only
readConfig remains, for the locale list and lastOperation.locale default. The
emitted context.json is byte-identical to the scanned variant. Parameterless
callers are unchanged. Adds the first tests for buildContextChange (byte-equal
injected vs scanned, no-scan assertion, null-entries dropped).
@netlify

netlify Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploy Preview for contentrain-ai ready!

Name Link
🔨 Latest commit f1a2dce
🔍 Latest deploy log https://app.netlify.com/projects/contentrain-ai/deploys/6a4f67b1cde6a50008f33d17
😎 Deploy Preview https://deploy-preview-63--contentrain-ai.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@ABB65
ABB65 merged commit 4fff229 into main Jul 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant