Skip to content

Custom fields are not persisted on write through the internal MCP dispatch #36

Description

@tecpromotion

What happened?

Custom field values are not persisted when an article is written through the generated MCP tools, even though the same values are read back correctly.

Steps to reproduce:

  1. Define a custom field for com_content.article (e.g. a text field named text-field).
  2. Create or update an article through the content.articles.create / content.articles.update MCP tool and supply the custom field, either at the top level ("text-field": "value") or nested ("com_fields": {"text-field": "value"}).
  3. The article is created/updated successfully (HTTP 2xx).
  4. Inspect #__fields_values for the article: the value is missing/empty.

Reading works: an article that already has custom field values returns them as top-level attributes through content.articles.get / content.articles.list.

Version

contract-projection-chain branch (MCP contract work, __DEPLOY_VERSION__) — not a released version; the version selector above does not apply.

Expected result

A custom field supplied on create/update is stored the way the established web services REST API stores it (routed to com_fields and saved by the fields plugin), and reads back on the next request.

Actual result

The article is saved but the custom field value is dropped; #__fields_values has no row for it. Only the built-in fields persist.

System Information

Local development environment. Branch contract-projection-chain, endpoint /api/index.php/v1/mcp, internal dispatch path (ComponentApiDispatcher → existing com_content API controller).

Additional Comments

Root cause, verified in the plugin code:

The argument mapper already forwards undeclared custom fields into the request body, and the resource declares additionalProperties, so the values reach the controller. However, the system/fields plugin's onContentPrepareForm reads jform via $this->getApplication()->getInput(). During an internal dispatch that is the outer MCP application, not the internal request where ApiController::save() set jform. The custom fields are therefore not prepared into the form, $model->validate() drops the com_fields values, and onContentAfterSave has nothing to store.

This is the documented transitional limitation that third-party code reading the top-level ApiApplication observes the outer MCP request. Forwarding the values is necessary but not sufficient; the fix belongs with propagating the internal application (and its input) to plugins during dispatch, not with the argument mapper.

Related (separate, and per the templates a Discussion rather than an issue): the article options registry (attribs, the "Options" tab) is not modelled in the create/update schema either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions