Skip to content

ACF (Advanced Custom Fields)

When Advanced Custom Fields (Free or Pro) is active, EMCP exposes ACF as a first-class integration. An agent can discover the active field registry, build a content model, validate values, and write fields without bypassing ACF’s own APIs.

The integration arrived in v3.2.1 and received broad Free/Pro field validation plus structured batch imports in v3.16.0. The v3.16.0 coverage was verified through the real MCP transport against ACF Pro 6.8.9, including all 36 public field types registered by that build.

To keep the MCP tool-list small, the whole domain is exposed as two dispatcher tools rather than one tool per operation:

  • acf-read: all read operations (enabled by default)
  • acf-write: all write operations (ships disabled by default)

Each takes an operation and an arguments object. Call a tool with no operation to get its catalog of operations, then call it again to run one:

// discover
acf-read({})
// → { mode: "read", operations: [ { operation: "list-field-groups", … }, … ] }
// act
acf-read({ operation: "get-fields", arguments: { post_id: 123 } })

This is the same discover → act pattern as the widget catalog. The two dispatchers only register when ACF is active, and each operation still enforces its own WordPress capability, checked per call.

OperationArgumentsReturns
list-field-typesNoneEvery field type registered by the active ACF build, its Pro status, and supported settings.
list-field-groupsNoneField groups: key, title, active, field count.
get-field-group{ key }One group’s location rules + recursive field tree. Read this before writing values.
list-options-pagesNoneACF PRO options pages (empty on free ACF).
get-fields{ post_id } or { options_page }Current field values, formatted.
list-post-typesNoneACF-managed custom post types (ACF 6.1+).
get-post-type{ key }One CPT’s definition (6.1+).
list-taxonomiesNoneACF-managed taxonomies (6.1+).
get-taxonomy{ key }One taxonomy’s definition (6.1+).
OperationArgumentsNotes
update-fields{ post_id|options_page, fields: { name: value } }Writes values by field name (resolved to keys).
validate-fields{ items: [{ client_ref, source?, data }] }Validates a structured import without writing and returns a deterministic plan_hash.
batch-update-fields{ items, plan_hash, confirm: true }Applies the exact validated batch, then reads every item back.
create-field-group{ title, fields: […], location: [[…]] }Creates a group with fields + location rules.
update-field-group{ key, … }Edit settings / add fields. No deletes or renames.
create-post-type{ post_type, title, … }Registers a CPT as data through ACF (6.1+).
update-post-type{ key, … }Edit a CPT. Slug is immutable. (6.1+)
create-taxonomy{ taxonomy, title, object_type: […] }Registers a taxonomy as data (6.1+).
update-taxonomy{ key, … }Edit a taxonomy. Slug is immutable. (6.1+)

The Custom Post Type / Taxonomy operations require ACF 6.1+; they’re omitted from the catalog on older ACF.

list-field-types reads ACF’s active runtime registry instead of a hard-coded catalog. This means the agent sees the edition and field types actually available on the connected site.

EditionField types verified in v3.16.0
ACF Freetext, textarea, number, range, email, url, password, image, file, wysiwyg, oembed, select, checkbox, radio, button group, true/false, link, post object, page link, relationship, taxonomy, user, Google Map, date picker, date-time picker, time picker, color picker, icon picker, message, accordion, tab, group
ACF Prorepeater, flexible content, gallery, clone

Thirty-three of those types store values. message, accordion, and tab are presentation controls, so value operations intentionally reject writes to them. Group, repeater, flexible-content, and clone values use nested structured JSON; galleries and relationship fields use validated collections of object IDs.

Built-in validation covers required values, scalar and collection shapes, text length, email, HTTP(S) URLs, numeric min/max/step, configured choices, booleans, links, attachment and media constraints, related object existence and type, taxonomy and user restrictions, map coordinates, stored date/time formats, colors, icons, nested subfields, and collection limits. ACF Pro bidirectional relationship add and remove behavior is also supported.

The integration is broad, but it does not claim complete parity with every ACF administration screen.

ACF featureCoverageCurrent boundary
Field discoveryCoveredReads the active runtime, including registered third-party types and their setting keys.
Field valuesCovered for posts and existing options pagesRead, validated write, dry-run planning, hash-bound batch apply, provenance, and read-back.
Field groupsPartialList/get/create/update, append fields, and update field settings. No delete, duplicate, move, reorder, rename, or field-type mutation.
Built-in field settingsBroadBuilt-in settings are preserved. Some field-group presentation settings are not authorable yet.
Location rulesPartialRule groups are stored, but extension-defined location types and values are not exhaustively validated.
Options pages (Pro)PartialExisting pages can be listed and used for field reads/writes. Options-page create/update/delete/reorder is not exposed.
Bidirectional relationshipsCoveredRelationship target settings, reverse writes, and reverse cleanup are supported.
ACF-managed post types and taxonomiesPartialCore labels, visibility, REST, hierarchy, supports/archive, taxonomies, and object types are covered; the complete ACF UI schema is not.
ACF Blocks (Pro)Not coveredEMCP’s Gutenberg tools do not create or manage ACF block definitions.
Local JSON and PHP-registered groupsRead onlyLocal groups are discoverable, but EMCP refuses to create a database copy that would shadow code. JSON sync/import/export is not exposed.
Other ACF object targetsNot coveredValue operations accept numeric post IDs or options-page names, not term, user, comment, widget, or menu-item targets.
Third-party field typesPartialDiscovery and basic schema creation work; custom validation and settings are not guaranteed.

PDFs, spreadsheets, CSV files, DOCX files, and OCR output are handled by the connected agent, not uploaded to a parser inside WordPress. The agent extracts the source into bounded structured JSON and sends that JSON to ACF over MCP.

The safe batch flow is:

  1. The agent inspects the field group and parses the source document locally.
  2. validate-fields validates every item and returns a deterministic plan_hash. It writes nothing.
  3. The human reviews the plan.
  4. batch-update-fields receives the same items, the matching hash, and confirm: true.
  5. WordPress rejects the whole batch before mutation if any item is invalid, and returns per-item read-back after a successful apply.
// 1. Validate the agent-structured payload. No write occurs.
acf-write({
operation: "validate-fields",
arguments: {
items: [
{
client_ref: "catalog-row-42",
source: { file: "catalog.pdf", page: 7 },
data: {
post_id: 123,
fields: { subtitle: "The Spice Must Flow", rating: 5 }
}
}
]
}
})
// 2. Apply only the exact payload that produced the returned hash.
acf-write({
operation: "batch-update-fields",
arguments: {
items: [/* the unchanged validated items */],
plan_hash: "<hash returned by validate-fields>",
confirm: true
}
})

WordPress never needs to parse the PDF or spreadsheet itself. It receives only the structured field targets and values it is responsible for validating and storing.

  • Data, not code. Custom post types and taxonomies are registered through ACF’s own acf_import_post_type / acf_import_taxonomy: nothing executable is written, and ACF registers them itself.
  • No deletes. There is no delete operation for anything.
  • Immutable identifiers. A field’s name/key/type, and a post type / taxonomy slug, can never change: renaming would orphan stored content.
  • PRO fields. Repeaters, flexible content (rows validated against the field’s layouts), galleries, groups and clones round-trip as nested JSON; on free ACF those field types are rejected with acf_pro_required.
  • Atomic batch validation. An invalid item rejects the complete batch before any write, and a changed payload cannot reuse an earlier plan_hash.
  • Per-operation capabilities. Field reads need edit_posts; field-value writes need edit_post on the target; field-group / CPT / taxonomy writes need manage_options.
// 1. a custom post type
acf-write({ operation: "create-post-type",
arguments: { post_type: "book", title: "Books", singular: "Book",
supports: ["title","editor","thumbnail"] } })
// 2. a taxonomy on it
acf-write({ operation: "create-taxonomy",
arguments: { taxonomy: "genre", title: "Genres", object_type: ["book"] } })
// 3. a field group on that post type
acf-write({ operation: "create-field-group",
arguments: { title: "Book Details",
fields: [ { label: "Subtitle", name: "subtitle", type: "text" },
{ label: "Rating", name: "rating", type: "number", min: 0, max: 5 } ],
location: [[ { param: "post_type", operator: "==", value: "book" } ]] } })
// 4. create a book (with the content tools), then write its values
acf-write({ operation: "update-fields",
arguments: { post_id: 123, fields: { subtitle: "The Spice Must Flow", rating: 5 } } })
// 5. read it back
acf-read({ operation: "get-fields", arguments: { post_id: 123 } })

The dispatchers appear under EMCP Tools → Tools → Plugins → ACF as two toggles, acf-read (on) and acf-write (off by default), each card listing the operations it covers. Toggle a tool to allow or block all of its operations at once.

Pro ships an emcp-plugins Agent Skill that teaches a connected agent the dispatcher pattern, discovery flow, ACF operation reference, and agent-structured document import boundary, so it drives the integration correctly without sending source documents to WordPress for parsing.