Repository navigation
fix(mcp): preserve omitted blocks fields on content writes - #3824
khoinguyenpham04 wants to merge 2 commits into
Conversation
🦋 Changeset detectedLatest commit: 019859d The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 019859d | Oct 04 2026, 08:24 PM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-test
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-loader
@emdash-cms/registry-moderation
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This PR fixes a real, well-scoped bug: convertDataForWrite in packages/core/src/client/portable-text.ts unconditionally ran blocks-field conversion, so an omitted blocks field was explicitly set to undefined and later failed validation with "must be an array". The one-line Array.isArray guard is the right fix for both MCP content_create/content_update and the JS client create/update helpers, which share the same conversion function. The regression tests are solid: a focused unit test plus dialect-agnostic MCP integration tests covering create defaulting to [], update preserving stored blocks, and continued rejection of non-array values.
I have two small follow-ups in the same file:
convertDataForReadhas the same omitted-field mutation in itsblocksbranch. It should be guarded the same way so omitted fields stay omitted on read and the two conversion functions stay consistent.- The JSDoc for
convertDataForWriteandconvertDataForReadsays they only convertportableTextfields, but both also convert nested Portable Text insideblocksarrays. Update the docstrings to match the actual behavior.
Findings
-
[needs fixing]
packages/core/src/client/portable-text.ts:430The
blocksbranch inconvertDataForReadstill mutates omitted fields. BecauseconvertNestedBlockPortableTextreturns its argument when it is not an array, an omitted blocks field becomesresult[field.slug] = undefined, changing an absent property into an explicitundefined. This is the same bug class the PR just fixed on the write side and leavesconvertDataForReadinconsistent withconvertDataForWrite.Mirror the write-side guard so omitted fields stay omitted on read:
} else if (field.type === "blocks" && Array.isArray(result[field.slug])) { result[field.slug] = convertNestedBlockPortableText(result[field.slug], field, "read"); }While touching this, also update the
convertDataForReadJSDoc above it; it only mentionsportableTextfields but the function also converts nested Portable Text insideblocksarrays. -
[suggestion]
packages/core/src/client/portable-text.ts:438The
convertDataForWriteJSDoc says it "only converts fields with typeportableTextthat contain strings", but the function also converts nested markdown strings insideblocksarray fields. That is now the exact path this PR changed, so update the docstring to match the actual behavior:/** * Convert content data for writing: markdown strings -> Portable Text. * Converts top-level `portableText` string fields to arrays, and nested * markdown strings inside `blocks` array fields to Portable Text. */
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
7da21fd to
ec77ee9
Compare
ec77ee9 to
019859d
Compare
What does this PR do?
Fixes MCP content writes that omit a
blocksfield. Write conversion now leaves omitted fields absent, socontent_createuses the empty default (subject to the field's minimum) andcontent_updatepreserves the stored blocks, including their keys and versions. Supplied non-array values still fail validation.Read conversion also leaves omitted blocks fields absent. Both conversion docstrings now describe nested Portable Text conversion, and a read-side regression test fails before the guard and passes with it.
Both reported MCP failures were reproduced against
main(version 1.1.0) on SQLite and PostgreSQL before applying the fix. The same faulty conversion is present in theemdash@0.40.0source. Regression tests cover persisted create/update behavior and malformed values.This is the first layer of a two-PR blocks-write stack, based on
main. PR #3825 addresses missing_typein a single-type field and is based on this branch. Merge this PR first. Reported directly; no linked issue number.Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.Translation and screenshot items are not applicable: this changes no admin UI or user-visible UI strings. The changeset applies to the published
emdashpackage.AI-generated code disclosure
gpt-6.1-sol); independent adversarial review with GPT-5.6 Sol (gpt-5.6-sol,xhigh).Screenshots / test output
Not applicable: no UI changes.
pnpm format, rootpnpm build,pnpm lint:quick,pnpm lint, andpnpm typecheckpass.pnpm --silent lint:json | jq '.diagnostics | length':0.xhigh) review: clean on this layer and the combined stack, with no findings or remaining nits.