Skip to content

fix(mcp): preserve omitted blocks fields on content writes - #3824

Open
khoinguyenpham04 wants to merge 2 commits into
mainfrom
noah/mcp-blocks/omitted-fields
Open

khoinguyenpham04 wants to merge 2 commits into
mainfrom
noah/mcp-blocks/omitted-fields

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes MCP content writes that omit a blocks field. Write conversion now leaves omitted fields absent, so content_create uses the empty default (subject to the field's minimum) and content_update preserves 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 the emdash@0.40.0 source. 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 _type in a single-type field and is based on this branch. Merge this PR first. Reported directly; no linked issue number.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added and reviewed the user-facing changeset (if this PR changes a published package)
  • New features link to an approved Discussion: not applicable to this bug fix.
  • I have included screenshots below if this PR changes the UI

Translation and screenshot items are not applicable: this changes no admin UI or user-visible UI strings. The changeset applies to the published emdash package.

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Codex with GPT-6.1 Sol (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, root pnpm build, pnpm lint:quick, pnpm lint, and pnpm typecheck pass.
  • pnpm --silent lint:json | jq '.diagnostics | length': 0.
  • Lower-layer converter/client/MCP checks after the review follow-up: 96 passing tests, including the real MCP transport and SQLite/PostgreSQL handlers.
  • Initial combined-stack validation, before the read-side follow-up: complete core suite with SQLite and PostgreSQL, 10,992 passed, 8 skipped across 769 files.
  • Persistent GPT-5.6 Sol (xhigh) review: clean on this layer and the combined stack, with no findings or remaining nits.

@changeset-bot

changeset-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 019859d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

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

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 019859d Oct 04 2026, 08:24 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://noah-mcp-blocks-omitted-fields.try.emdashcms.com, https://noah-mcp-blocks-omitted-fields-emdash-playground.emdash-cms.workers.dev (commit 019859d)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://054f9421.try.emdashcms.com, https://054f9421-emdash-playground.emdash-cms.workers.dev 019859d 2026-10-04T20:25:25.849Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://0fad6335.try.emdashcms.com, https://0fad6335-emdash-playground.emdash-cms.workers.dev ec77ee9 2026-10-04T10:12:58.339Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://3e98a6ce.try.emdashcms.com, https://3e98a6ce-emdash-playground.emdash-cms.workers.dev 7da21fd 2026-10-03T19:28:11.753Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://847211aa.try.emdashcms.com, https://847211aa-emdash-playground.emdash-cms.workers.dev d7b88b6 2026-10-03T17:44:32.569Z Visit the dashboard ↗

@pkg-pr-new

pkg-pr-new Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@3824

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@3824

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@3824

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@3824

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@3824

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@3824

emdash

npm i https://pkg.pr.new/emdash@3824

create-emdash

npm i https://pkg.pr.new/create-emdash@3824

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@3824

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@3824

@emdash-cms/plugin-test

npm i https://pkg.pr.new/@emdash-cms/plugin-test@3824

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@3824

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@3824

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@3824

@emdash-cms/registry-loader

npm i https://pkg.pr.new/@emdash-cms/registry-loader@3824

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@3824

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@3824

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@3824

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@3824

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@3824

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@3824

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@3824

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@3824

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@3824

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@3824

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@3824

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@3824

commit: 019859d

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. convertDataForRead has the same omitted-field mutation in its blocks branch. It should be guarded the same way so omitted fields stay omitted on read and the two conversion functions stay consistent.
  2. The JSDoc for convertDataForWrite and convertDataForRead says they only convert portableText fields, but both also convert nested Portable Text inside blocks arrays. Update the docstrings to match the actual behavior.

Findings

  • [needs fixing] packages/core/src/client/portable-text.ts:430

    The blocks branch in convertDataForRead still mutates omitted fields. Because convertNestedBlockPortableText returns its argument when it is not an array, an omitted blocks field becomes result[field.slug] = undefined, changing an absent property into an explicit undefined. This is the same bug class the PR just fixed on the write side and leaves convertDataForRead inconsistent with convertDataForWrite.

    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 convertDataForRead JSDoc above it; it only mentions portableText fields but the function also converts nested Portable Text inside blocks arrays.

  • [suggestion] packages/core/src/client/portable-text.ts:438

    The convertDataForWrite JSDoc says it "only converts fields with type portableText that contain strings", but the function also converts nested markdown strings inside blocks array 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.
     */
    

@khoinguyenpham04
khoinguyenpham04 added this pull request to stack #3826 October 3, 2026 17:49
@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond overlap and removed review/needs-review No maintainer or bot review yet labels Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/awaiting-author Reviewed; waiting on the author to respond labels Oct 3, 2026
@khoinguyenpham04 khoinguyenpham04 added the bot:review Trigger an emdashbot code review on this PR label Oct 4, 2026
@khoinguyenpham04
khoinguyenpham04 force-pushed the noah/mcp-blocks/omitted-fields branch from 7da21fd to ec77ee9 Compare October 4, 2026 10:08
@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Oct 4, 2026
@khoinguyenpham04
khoinguyenpham04 force-pushed the noah/mcp-blocks/omitted-fields branch from ec77ee9 to 019859d Compare October 4, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant