drupal-mcp-connector 2.7.4 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/{.claude → .agents}/commands/drupal-audit-config-best-practices.md +3 -4
  2. package/{.claude → .agents}/commands/drupal-audit-site-health.md +3 -4
  3. package/{.claude → .agents}/commands/drupal-block-user.md +3 -4
  4. package/{.claude → .agents}/commands/drupal-bulk-create.md +3 -4
  5. package/{.claude → .agents}/commands/drupal-bulk-update.md +3 -4
  6. package/{.claude → .agents}/commands/drupal-config-get.md +3 -4
  7. package/{.claude → .agents}/commands/drupal-config-list.md +3 -4
  8. package/{.claude → .agents}/commands/drupal-config-set.md +3 -4
  9. package/{.claude → .agents}/commands/drupal-content-by-moderation-state.md +3 -4
  10. package/{.claude → .agents}/commands/drupal-create-block.md +3 -4
  11. package/{.claude → .agents}/commands/drupal-create-media.md +3 -4
  12. package/{.claude → .agents}/commands/drupal-create-menu-link.md +3 -4
  13. package/{.claude → .agents}/commands/drupal-create-node.md +6 -7
  14. package/{.claude → .agents}/commands/drupal-create-paragraph.md +3 -4
  15. package/{.claude → .agents}/commands/drupal-create-redirect.md +3 -4
  16. package/{.claude → .agents}/commands/drupal-create-taxonomy-term.md +3 -4
  17. package/{.claude → .agents}/commands/drupal-create-translation.md +3 -4
  18. package/{.claude → .agents}/commands/drupal-create-user.md +3 -4
  19. package/{.claude → .agents}/commands/drupal-delete-media.md +3 -4
  20. package/{.claude → .agents}/commands/drupal-delete-node.md +3 -4
  21. package/{.claude → .agents}/commands/drupal-delete-taxonomy-term.md +3 -4
  22. package/{.claude → .agents}/commands/drupal-describe-fields.md +3 -4
  23. package/{.claude → .agents}/commands/drupal-drush-cache-rebuild.md +3 -4
  24. package/{.claude → .agents}/commands/drupal-drush-config-export.md +3 -4
  25. package/{.claude → .agents}/commands/drupal-drush-config-import.md +3 -4
  26. package/{.claude → .agents}/commands/drupal-drush-config-status.md +3 -4
  27. package/{.claude → .agents}/commands/drupal-drush-cron.md +3 -4
  28. package/{.claude → .agents}/commands/drupal-drush-module-disable.md +3 -4
  29. package/{.claude → .agents}/commands/drupal-drush-module-enable.md +3 -4
  30. package/{.claude → .agents}/commands/drupal-drush-module-list.md +3 -4
  31. package/{.claude → .agents}/commands/drupal-drush-security-updates.md +3 -4
  32. package/{.claude → .agents}/commands/drupal-drush-sql-query.md +3 -4
  33. package/{.claude → .agents}/commands/drupal-drush-status.md +3 -4
  34. package/{.claude → .agents}/commands/drupal-drush-updatedb.md +3 -4
  35. package/{.claude → .agents}/commands/drupal-drush-user-create.md +3 -4
  36. package/{.claude → .agents}/commands/drupal-drush-user-list.md +3 -4
  37. package/{.claude → .agents}/commands/drupal-drush-watchdog.md +3 -4
  38. package/{.claude → .agents}/commands/drupal-entity-create.md +3 -4
  39. package/{.claude → .agents}/commands/drupal-entity-delete.md +3 -4
  40. package/{.claude → .agents}/commands/drupal-entity-get.md +3 -4
  41. package/{.claude → .agents}/commands/drupal-entity-list.md +3 -4
  42. package/{.claude → .agents}/commands/drupal-entity-update.md +6 -7
  43. package/{.claude → .agents}/commands/drupal-find-orphaned-media.md +3 -4
  44. package/{.claude → .agents}/commands/drupal-get-entity-schema.md +3 -4
  45. package/{.claude → .agents}/commands/drupal-get-media.md +3 -4
  46. package/{.claude → .agents}/commands/drupal-get-node.md +3 -4
  47. package/{.claude → .agents}/commands/drupal-get-paragraph.md +3 -4
  48. package/{.claude → .agents}/commands/drupal-get-revision.md +3 -4
  49. package/{.claude → .agents}/commands/drupal-get-taxonomy-term.md +3 -4
  50. package/{.claude → .agents}/commands/drupal-get-taxonomy-terms.md +3 -4
  51. package/{.claude → .agents}/commands/drupal-get-user-by-name.md +3 -4
  52. package/{.claude → .agents}/commands/drupal-get-user.md +3 -4
  53. package/{.claude → .agents}/commands/drupal-governance-status.md +3 -4
  54. package/{.claude → .agents}/commands/drupal-graphql-introspect.md +3 -4
  55. package/{.claude → .agents}/commands/drupal-graphql.md +3 -4
  56. package/{.claude → .agents}/commands/drupal-list-blocks.md +3 -4
  57. package/{.claude → .agents}/commands/drupal-list-content-types.md +3 -4
  58. package/{.claude → .agents}/commands/drupal-list-entity-types.md +3 -4
  59. package/{.claude → .agents}/commands/drupal-list-media-types.md +3 -4
  60. package/{.claude → .agents}/commands/drupal-list-media.md +3 -4
  61. package/{.claude → .agents}/commands/drupal-list-menu-links.md +3 -4
  62. package/{.claude → .agents}/commands/drupal-list-moderation-states.md +3 -4
  63. package/{.claude → .agents}/commands/drupal-list-nodes.md +3 -4
  64. package/{.claude → .agents}/commands/drupal-list-revisions.md +3 -4
  65. package/{.claude → .agents}/commands/drupal-list-roles.md +3 -4
  66. package/{.claude → .agents}/commands/drupal-list-sites.md +2 -3
  67. package/{.claude → .agents}/commands/drupal-list-translations.md +3 -4
  68. package/{.claude → .agents}/commands/drupal-list-users.md +3 -4
  69. package/{.claude → .agents}/commands/drupal-list-vocabularies.md +3 -4
  70. package/{.claude → .agents}/commands/drupal-mcp-whoami.md +3 -4
  71. package/{.claude → .agents}/commands/drupal-report-404-log.md +3 -4
  72. package/{.claude → .agents}/commands/drupal-report-accessibility-audit.md +3 -4
  73. package/{.claude → .agents}/commands/drupal-report-alias-coverage.md +3 -4
  74. package/{.claude → .agents}/commands/drupal-report-broken-embeds.md +3 -4
  75. package/{.claude → .agents}/commands/drupal-report-broken-links.md +3 -4
  76. package/{.claude → .agents}/commands/drupal-report-cache-config.md +3 -4
  77. package/{.claude → .agents}/commands/drupal-report-config-drift.md +3 -4
  78. package/{.claude → .agents}/commands/drupal-report-content-by-author.md +3 -4
  79. package/{.claude → .agents}/commands/drupal-report-content-summary.md +3 -4
  80. package/{.claude → .agents}/commands/drupal-report-duplicate-content.md +3 -4
  81. package/{.claude → .agents}/commands/drupal-report-field-completeness.md +3 -4
  82. package/{.claude → .agents}/commands/drupal-report-menu-integrity.md +3 -4
  83. package/{.claude → .agents}/commands/drupal-report-missing-field.md +3 -4
  84. package/{.claude → .agents}/commands/drupal-report-module-audit.md +3 -4
  85. package/{.claude → .agents}/commands/drupal-report-orphan-pages.md +3 -4
  86. package/{.claude → .agents}/commands/drupal-report-orphaned-references.md +3 -4
  87. package/{.claude → .agents}/commands/drupal-report-permission-audit.md +3 -4
  88. package/{.claude → .agents}/commands/drupal-report-pii-exposure.md +3 -4
  89. package/{.claude → .agents}/commands/drupal-report-readability.md +3 -4
  90. package/{.claude → .agents}/commands/drupal-report-recently-published.md +3 -4
  91. package/{.claude → .agents}/commands/drupal-report-redirect-health.md +3 -4
  92. package/{.claude → .agents}/commands/drupal-report-revision-hotspots.md +3 -4
  93. package/{.claude → .agents}/commands/drupal-report-scheduled-content.md +3 -4
  94. package/{.claude → .agents}/commands/drupal-report-seo-audit.md +3 -4
  95. package/{.claude → .agents}/commands/drupal-report-seo-meta-coverage.md +3 -4
  96. package/{.claude → .agents}/commands/drupal-report-stale-content.md +3 -4
  97. package/{.claude → .agents}/commands/drupal-report-status-report.md +3 -4
  98. package/{.claude → .agents}/commands/drupal-report-taxonomy-usage.md +3 -4
  99. package/{.claude → .agents}/commands/drupal-report-text-format-audit.md +3 -4
  100. package/{.claude → .agents}/commands/drupal-report-translation-coverage.md +3 -4
  101. package/{.claude → .agents}/commands/drupal-report-unpublished.md +3 -4
  102. package/{.claude → .agents}/commands/drupal-report-user-activity.md +3 -4
  103. package/{.claude → .agents}/commands/drupal-report-workflow-bottlenecks.md +3 -4
  104. package/{.claude → .agents}/commands/drupal-resolve-reference.md +3 -4
  105. package/{.claude → .agents}/commands/drupal-revert-revision.md +3 -4
  106. package/{.claude → .agents}/commands/drupal-schedule-publish.md +3 -4
  107. package/{.claude → .agents}/commands/drupal-search-content.md +3 -4
  108. package/{.claude → .agents}/commands/drupal-search.md +3 -4
  109. package/{.claude → .agents}/commands/drupal-security-info.md +3 -4
  110. package/{.claude → .agents}/commands/drupal-set-moderation-state.md +3 -4
  111. package/{.claude → .agents}/commands/drupal-site-info.md +3 -4
  112. package/{.claude → .agents}/commands/drupal-update-media.md +3 -4
  113. package/{.claude → .agents}/commands/drupal-update-menu-link.md +3 -4
  114. package/{.claude → .agents}/commands/drupal-update-node.md +9 -10
  115. package/{.claude → .agents}/commands/drupal-update-paragraph.md +3 -4
  116. package/{.claude → .agents}/commands/drupal-update-redirect.md +3 -4
  117. package/{.claude → .agents}/commands/drupal-update-taxonomy-term.md +3 -4
  118. package/{.claude → .agents}/commands/drupal-update-user.md +3 -4
  119. package/{.claude → .agents}/commands/drupal-upload-file-and-create-media.md +3 -4
  120. package/{.claude → .agents}/commands/drupal-upload-file.md +3 -4
  121. package/CHANGELOG.md +82 -0
  122. package/README.md +23 -12
  123. package/config/config.example.json +1 -1
  124. package/package.json +4 -2
  125. package/scripts/generate-commands.js +42 -21
  126. package/scripts/install-commands.js +157 -0
  127. package/src/lib/backends/backend-interface.js +20 -1
  128. package/src/lib/backends/jsonapi.js +47 -4
  129. package/src/lib/body-summary.js +60 -0
  130. package/src/lib/contracts/approval.js +72 -0
  131. package/src/lib/contracts/decisions.js +139 -0
  132. package/src/lib/contracts/drupal.js +525 -0
  133. package/src/lib/contracts/evaluator.js +28 -0
  134. package/src/lib/contracts/evidence-sink.js +67 -0
  135. package/src/lib/contracts/fixtures.js +117 -0
  136. package/src/lib/contracts/index.js +46 -0
  137. package/src/lib/contracts/relay.js +83 -0
  138. package/src/lib/contracts/system-of-record.js +61 -0
  139. package/src/lib/contracts/types.js +242 -0
  140. package/src/lib/contracts/version.js +52 -0
  141. package/src/lib/data-flow.js +437 -0
  142. package/src/lib/dispatch.js +36 -15
  143. package/src/lib/drupal-fetch.js +52 -6
  144. package/src/lib/field-definition.js +285 -0
  145. package/src/lib/patch-preflight.js +157 -66
  146. package/src/lib/security.js +14 -0
  147. package/src/lib/server-tools.js +9 -0
  148. package/src/lib/write-revision.js +82 -2
  149. package/src/tools/bulk.js +4 -3
  150. package/src/tools/entities.js +11 -7
  151. package/src/tools/index.js +3 -2
  152. package/src/tools/nodes.js +55 -43
@@ -1,18 +1,17 @@
1
1
  ---
2
2
  description: "User activity summary: active vs blocked accounts, never-logged-in users, and users inactive beyond a threshold. Useful for security audits and account hygiene."
3
3
  argument-hint: "[site] [inactiveDays] [limit]"
4
- allowed-tools: mcp__drupal__drupal_report_user_activity
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_report_user_activity` MCP tool.
6
+ Call the MCP tool `drupal_report_user_activity`.
8
7
 
9
8
  User activity summary: active vs blocked accounts, never-logged-in users, and users inactive beyond a threshold. Useful for security audits and account hygiene.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Optional:**
14
13
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
15
14
  - `inactiveDays` (number): Days without login to flag as inactive
16
15
  - `limit` (number)
17
16
 
18
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
17
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Find content stuck in a non-published moderation state (draft/needs_review) beyond N days — editorial bottlenecks. Reads moderation_state; gated when content_moderation isn't exposed."
3
3
  argument-hint: "[site] [type] [days] [states] [sampleSize]"
4
- allowed-tools: mcp__drupal__drupal_report_workflow_bottlenecks
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_report_workflow_bottlenecks` MCP tool.
6
+ Call the MCP tool `drupal_report_workflow_bottlenecks`.
8
7
 
9
8
  Find content stuck in a non-published moderation state (draft/needs_review) beyond N days — editorial bottlenecks. Reads moderation_state; gated when content_moderation isn't exposed.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Optional:**
14
13
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
@@ -17,4 +16,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
17
16
  - `states` (array (pass as JSON)): Moderation states to treat as bottlenecks
18
17
  - `sampleSize` (number)
19
18
 
20
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
19
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Resolve a human name or title to a Drupal entity UUID. Use this before creating or updating an entity reference when you only know the label (e.g. a taxonomy term name, a user name, or a node title) and not its UUID. Read-only: returns the best match { id, title } plus any ambiguous candidates. Filters on 'title' for nodes and 'name' for taxonomy_term / user."
3
3
  argument-hint: "<entityType> <bundle> <name> [site] [limit]"
4
- allowed-tools: mcp__drupal__drupal_resolve_reference
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_resolve_reference` MCP tool.
6
+ Call the MCP tool `drupal_resolve_reference`.
8
7
 
9
8
  Resolve a human name or title to a Drupal entity UUID. Use this before creating or updating an entity reference when you only know the label (e.g. a taxonomy term name, a user name, or a node title) and not its UUID. Read-only: returns the best match { id, title } plus any ambiguous candidates. Filters on 'title' for nodes and 'name' for taxonomy_term / user.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `entityType` (string): Entity type machine name, e.g. 'node', 'taxonomy_term', 'user'
@@ -19,4 +18,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
19
18
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
20
19
  - `limit` (number): Maximum candidates to consider
21
20
 
22
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
21
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Revert a content node to a prior revision (GOVERNED WRITE). Reads the target revision and replays its editable content as a NEW current revision (history is preserved, nothing is deleted). Internal ids, revision metadata, and computed paths are not written back. Subject to the site's write security policy. Confirm with the user before calling."
3
3
  argument-hint: "<type> <id> <version> [site]"
4
- allowed-tools: mcp__drupal__drupal_revert_revision
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_revert_revision` MCP tool.
6
+ Call the MCP tool `drupal_revert_revision`.
8
7
 
9
8
  Revert a content node to a prior revision (GOVERNED WRITE). Reads the target revision and replays its editable content as a NEW current revision (history is preserved, nothing is deleted). Internal ids, revision metadata, and computed paths are not written back. Subject to the site's write security policy. Confirm with the user before calling.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `type` (string): Content type machine name
@@ -18,4 +17,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
18
17
  **Optional:**
19
18
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
20
19
 
21
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
20
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Schedule a content node to publish and/or unpublish at a future time using the Drupal Scheduler module. Sets the publish_on and unpublish_on fields on the node. Requires the Scheduler module to be installed and enabled for the content type, with the publish_on / unpublish_on fields present on the bundle — otherwise the call fails with a clear capability error. Timestamps accept ISO 8601 (e.g. '2026-07-01T12:00:00Z') or a Unix epoch and are passed through unchanged. Provide at least one of publishOn or unpublishOn."
3
3
  argument-hint: "<type> <id> [site] [publishOn] [unpublishOn]"
4
- allowed-tools: mcp__drupal__drupal_schedule_publish
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_schedule_publish` MCP tool.
6
+ Call the MCP tool `drupal_schedule_publish`.
8
7
 
9
8
  Schedule a content node to publish and/or unpublish at a future time using the Drupal Scheduler module. Sets the publish_on and unpublish_on fields on the node. Requires the Scheduler module to be installed and enabled for the content type, with the publish_on / unpublish_on fields present on the bundle — otherwise the call fails with a clear capability error. Timestamps accept ISO 8601 (e.g. '2026-07-01T12:00:00Z') or a Unix epoch and are passed through unchanged. Provide at least one of publishOn or unpublishOn.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `type` (string): Content type machine name, e.g. 'article'
@@ -19,4 +18,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
19
18
  - `publishOn` (string): When to publish — ISO 8601 datetime or Unix epoch. Sets the Scheduler publish_on field.
20
19
  - `unpublishOn` (string): When to unpublish — ISO 8601 datetime or Unix epoch. Sets the Scheduler unpublish_on field.
21
20
 
22
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
21
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Search nodes by title substring. Returns title, path alias, and body summary."
3
3
  argument-hint: "<query> [site] [type] [status] [limit]"
4
- allowed-tools: mcp__drupal__drupal_search_content
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_search_content` MCP tool.
6
+ Call the MCP tool `drupal_search_content`.
8
7
 
9
8
  Search nodes by title substring. Returns title, path alias, and body summary.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `query` (string): Search term to match against node titles
@@ -19,4 +18,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
19
18
  - `status` (boolean (true/false)): Filter by publish status
20
19
  - `limit` (number)
21
20
 
22
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
21
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Search content by a query string. Best-effort title match over a content type (mode:'fallback'); relevance-ranked search requires a Search API/Solr endpoint."
3
3
  argument-hint: "<query> [site] [type] [limit]"
4
- allowed-tools: mcp__drupal__drupal_search
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_search` MCP tool.
6
+ Call the MCP tool `drupal_search`.
8
7
 
9
8
  Search content by a query string. Best-effort title match over a content type (mode:'fallback'); relevance-ranked search requires a Search API/Solr endpoint.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `query` (string): Search term
@@ -18,4 +17,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
18
17
  - `type` (string): Content type machine name (default: article)
19
18
  - `limit` (number)
20
19
 
21
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
20
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,16 +1,15 @@
1
1
  ---
2
2
  description: "Show the active security configuration for a site — what's allowed, what's blocked, what fields are redacted. Run this to understand the current access policy."
3
3
  argument-hint: "[site]"
4
- allowed-tools: mcp__drupal__drupal_security_info
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_security_info` MCP tool.
6
+ Call the MCP tool `drupal_security_info`.
8
7
 
9
8
  Show the active security configuration for a site — what's allowed, what's blocked, what fields are redacted. Run this to understand the current access policy.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Optional:**
14
13
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
15
14
 
16
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
15
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Transition a content node to a moderation state (content_moderation), e.g. 'draft', 'needs_review', 'published', 'archived'. Governed write."
3
3
  argument-hint: "<type> <id> <state> [site]"
4
- allowed-tools: mcp__drupal__drupal_set_moderation_state
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_set_moderation_state` MCP tool.
6
+ Call the MCP tool `drupal_set_moderation_state`.
8
7
 
9
8
  Transition a content node to a moderation state (content_moderation), e.g. 'draft', 'needs_review', 'published', 'archived'. Governed write.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `type` (string): Content type machine name
@@ -18,4 +17,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
18
17
  **Optional:**
19
18
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
20
19
 
21
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
20
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,16 +1,15 @@
1
1
  ---
2
2
  description: "Get the base URL and the list of available resource/query types for a configured site (works for JSON:API and GraphQL backends)."
3
3
  argument-hint: "[site]"
4
- allowed-tools: mcp__drupal__drupal_site_info
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_site_info` MCP tool.
6
+ Call the MCP tool `drupal_site_info`.
8
7
 
9
8
  Get the base URL and the list of available resource/query types for a configured site (works for JSON:API and GraphQL backends).
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Optional:**
14
13
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
15
14
 
16
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
15
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update a media entity's name, status, or field values. Partial: omitted fields (status included) are left untouched."
3
3
  argument-hint: "<type> <id> [site] [name] [status] [fields]"
4
- allowed-tools: mcp__drupal__drupal_update_media
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_media` MCP tool.
6
+ Call the MCP tool `drupal_update_media`.
8
7
 
9
8
  Update a media entity's name, status, or field values. Partial: omitted fields (status included) are left untouched.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `type` (string)
@@ -20,4 +19,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
20
19
  - `status` (boolean (true/false)): Published flag. Only sent when provided; requires allowPublish when true.
21
20
  - `fields` (object (pass as JSON)): Field values. Entity-reference values in JSON:API linkage shape ({ data: { type, id } }) are sent as relationships automatically.
22
21
 
23
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
22
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update a custom menu link by UUID (rename, re-weight, re-target, re-parent, enable/disable). Only the fields you pass change. The link's enabled state is preserved across edits — an unrelated change will not disable a live link — unless you pass 'enabled' explicitly. Checked against the site security config."
3
3
  argument-hint: "<id> [site] [title] [link] [menu] [weight] [parent] [enabled]"
4
- allowed-tools: mcp__drupal__drupal_update_menu_link
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_menu_link` MCP tool.
6
+ Call the MCP tool `drupal_update_menu_link`.
8
7
 
9
8
  Update a custom menu link by UUID (rename, re-weight, re-target, re-parent, enable/disable). Only the fields you pass change. The link's enabled state is preserved across edits — an unrelated change will not disable a live link — unless you pass 'enabled' explicitly. Checked against the site security config.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `id` (string): Menu link UUID
@@ -22,4 +21,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
22
21
  - `parent` (string): New parent link plugin id (e.g. 'menu_link_content:<uuid>'), or '' for top level. Omit to leave unchanged.
23
22
  - `enabled` (boolean (true/false)): Enable/disable the link. Omit to preserve the current state.
24
23
 
25
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
24
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
- description: "Update an existing node. Only include fields you want to change. For moderated content types, use moderationState (e.g. 'published') rather than status. When the target is published and moderated and you omit moderationState, the connector defaults the write to moderation_state 'draft' (forward revision) so live default revisions are not mutated by accident. Entity-reference fields go in `relationships`, not `fields`. Paragraph / ERR identifiers are resolved to include meta.target_revision_id before PATCH; the write fails if any ref cannot be resolved (an unresolved identifier persists as an empty field). On moderated targets an id-mismatch PATCH preflight runs first — including on dryRun — so a core working-copy guard failure is reported before the real write and no revision is saved by the probe. workingCopy:null from drupal_list_revisions is not proof the node is writable (possiblyPatchBlocked / #201). Preflight here does not un-orphan paragraphs already created; probe the host before creating dependents."
2
+ description: "Update an existing node. Only include fields you want to change. For moderated content types, use moderationState (e.g. 'published') rather than status. When the target is published and moderated and you omit moderationState, the connector defaults the write to moderation_state 'draft' (forward revision) so live default revisions are not mutated by accident. Entity-reference fields go in `relationships`, not `fields`. Paragraph / ERR identifiers are resolved to include meta.target_revision_id before PATCH; the write fails if any ref cannot be resolved (an unresolved identifier persists as an empty field). On moderated targets an id-mismatch PATCH preflight runs first — including on dryRun — against the same URL the write will hit. An addressable working copy is PATCHed via ?resourceVersion=rel:working-copy (#166); dryRun uses that same target. workingCopy:null from drupal_list_revisions is not proof the node is writable (possiblyPatchBlocked / #201). Preflight here does not un-orphan paragraphs already created; probe the host before creating dependents."
3
3
  argument-hint: "<type> <id> [site] [title] [body] [summary] [format] [status] [moderationState] [fields] [relationships] [dryRun] [returning]"
4
- allowed-tools: mcp__drupal__drupal_update_node
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_node` MCP tool.
6
+ Call the MCP tool `drupal_update_node`.
8
7
 
9
- Update an existing node. Only include fields you want to change. For moderated content types, use moderationState (e.g. 'published') rather than status. When the target is published and moderated and you omit moderationState, the connector defaults the write to moderation_state 'draft' (forward revision) so live default revisions are not mutated by accident. Entity-reference fields go in `relationships`, not `fields`. Paragraph / ERR identifiers are resolved to include meta.target_revision_id before PATCH; the write fails if any ref cannot be resolved (an unresolved identifier persists as an empty field). On moderated targets an id-mismatch PATCH preflight runs first — including on dryRun — so a core working-copy guard failure is reported before the real write and no revision is saved by the probe. workingCopy:null from drupal_list_revisions is not proof the node is writable (possiblyPatchBlocked / #201). Preflight here does not un-orphan paragraphs already created; probe the host before creating dependents.
8
+ Update an existing node. Only include fields you want to change. For moderated content types, use moderationState (e.g. 'published') rather than status. When the target is published and moderated and you omit moderationState, the connector defaults the write to moderation_state 'draft' (forward revision) so live default revisions are not mutated by accident. Entity-reference fields go in `relationships`, not `fields`. Paragraph / ERR identifiers are resolved to include meta.target_revision_id before PATCH; the write fails if any ref cannot be resolved (an unresolved identifier persists as an empty field). On moderated targets an id-mismatch PATCH preflight runs first — including on dryRun — against the same URL the write will hit. An addressable working copy is PATCHed via ?resourceVersion=rel:working-copy (#166); dryRun uses that same target. workingCopy:null from drupal_list_revisions is not proof the node is writable (possiblyPatchBlocked / #201). Preflight here does not un-orphan paragraphs already created; probe the host before creating dependents.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `type` (string)
@@ -18,13 +17,13 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
18
17
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
19
18
  - `title` (string)
20
19
  - `body` (string)
21
- - `summary` (string): Body summary/teaser — writes the `summary` property of the body field (core `text_with_summary`). Many headless sites instead use a dedicated summary/deck field for teasers and meta descriptions; on those, set that field in `fields` a value written here will be stored but may never be rendered.
22
- - `format` (string): Text format machine name for the body, e.g. 'basic_html'. Defaults to the site config's `defaultTextFormat`, then 'full_html'. Set this when the site's formats do not include full_html, or to avoid writing content into a more permissive format than intended.
20
+ - `summary` (string): Body summary/teaser — writes body.summary on core text_with_summary only. Refused when the sampled body field has no summary property (text_long / text_formatted) or the schema cannot be determined. Prefer the site's dedicated deck/summary field via `fields`.
21
+ - `format` (string): Text format machine name for the body, e.g. 'basic_html'. When the body field's allowed_formats lists exactly one format, that is the default. A caller format outside that list is refused before write. When allowed_formats cannot be resolved, defaults to the site config's `defaultTextFormat`, then 'full_html'.
23
22
  - `status` (boolean (true/false)): Published flag for NON-moderated types: true = publish, false = unpublish. Ignored if moderationState is set.
24
23
  - `moderationState` (string): Moderation state transition for content_moderation types, e.g. 'draft', 'published', 'archived'. Takes precedence over status. Required to keep or re-publish a live node — omitting it on a published moderated node defaults the write to 'draft'.
25
- - `fields` (object (pass as JSON)): Scalar/attribute field values keyed by machine name. Entity-reference fields go in `relationships`, not here.
24
+ - `fields` (object (pass as JSON)): Scalar/attribute field values keyed by machine name. Formatted text: a string or { value, format?, summary? }. format must be in the field's allowed_formats; a single allowed format is used when omitted. Entity-reference fields go in `relationships`, not here.
26
25
  - `relationships` (object (pass as JSON)): Entity-reference fields as JSON:API relationships, keyed by field machine name. Single-value uses { data: { type, id } }; multi-value uses { data: [{ type, id }, …] }. Paragraph / ERR items must carry meta.target_revision_id — the connector injects it when missing, and fails the write if it cannot.
27
- - `dryRun` (boolean (true/false)): Validate, resolve ERR identifiers, and (on moderated targets) run the core PATCH-guard probe against Drupal, then return a preview without the real write. The probe uses a non-matching data.id so Drupal does not save. A working-copy 400 fails the dryRun.
26
+ - `dryRun` (boolean (true/false)): Validate, resolve ERR identifiers, and (on moderated targets) run the core PATCH-guard probe against Drupal, then return a preview without the real write. The probe uses a non-matching data.id so Drupal does not save, and hits the same URL as the real write (canonical, or ?resourceVersion=rel:working-copy when a draft is addressable). A working-copy 400 fails the dryRun.
28
27
  - `returning` (string): Response verbosity. "full" (default) returns the complete saved entity; "minimal" returns just identity + state (id, type, bundle, title, status, changed, url) — much smaller, recommended for bulk writes where the echoed body would dominate the response.
29
28
 
30
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
29
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update an existing Paragraph entity's field values by paragraph type (bundle) and UUID. Only the attributes you pass are changed (partial update); the host entity's reference to the paragraph is unchanged (same UUID), so this maintains a component paragraph in place without re-embedding. Returns relationshipData including meta.target_revision_id for a later host attach. Use drupal_get_entity_schema (entityType 'paragraph', the bundle) to discover fields. Governed by the site security policy."
3
3
  argument-hint: "<paragraphType> <id> [site] [attributes]"
4
- allowed-tools: mcp__drupal__drupal_update_paragraph
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_paragraph` MCP tool.
6
+ Call the MCP tool `drupal_update_paragraph`.
8
7
 
9
8
  Update an existing Paragraph entity's field values by paragraph type (bundle) and UUID. Only the attributes you pass are changed (partial update); the host entity's reference to the paragraph is unchanged (same UUID), so this maintains a component paragraph in place without re-embedding. Returns relationshipData including meta.target_revision_id for a later host attach. Use drupal_get_entity_schema (entityType 'paragraph', the bundle) to discover fields. Governed by the site security policy.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `paragraphType` (string): Paragraph type / bundle machine name, e.g. 'text', 'image', 'cta'
@@ -18,4 +17,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
18
17
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
19
18
  - `attributes` (object (pass as JSON)): Paragraph field values to change, keyed by Drupal machine name, e.g. { field_body: { value: '<p>..</p>', format: 'full_html' } }
20
19
 
21
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
20
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update an existing redirect by UUID: repoint its source or target, or change its status code (e.g. 301↔302). Only the fields you pass are changed (partial update). Use this to activate/fix a redirect that isn't firing (e.g. one created with a stale source). Governed by the site security policy."
3
3
  argument-hint: "<id> [site] [source] [target] [statusCode]"
4
- allowed-tools: mcp__drupal__drupal_update_redirect
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_redirect` MCP tool.
6
+ Call the MCP tool `drupal_update_redirect`.
8
7
 
9
8
  Update an existing redirect by UUID: repoint its source or target, or change its status code (e.g. 301↔302). Only the fields you pass are changed (partial update). Use this to activate/fix a redirect that isn't firing (e.g. one created with a stale source). Governed by the site security policy.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `id` (string): Redirect entity UUID
@@ -19,4 +18,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
19
18
  - `target` (string): New destination path/URI. Omit to leave unchanged.
20
19
  - `statusCode` (number): New HTTP redirect status code (301/302/303/307/308). Omit to leave unchanged.
21
20
 
22
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
21
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update an existing taxonomy term's name, description, or weight."
3
3
  argument-hint: "<vocabulary> <id> [site] [name] [description] [weight]"
4
- allowed-tools: mcp__drupal__drupal_update_taxonomy_term
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_taxonomy_term` MCP tool.
6
+ Call the MCP tool `drupal_update_taxonomy_term`.
8
7
 
9
8
  Update an existing taxonomy term's name, description, or weight.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `vocabulary` (string)
@@ -20,4 +19,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
20
19
  - `description` (string)
21
20
  - `weight` (number)
22
21
 
23
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
22
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Update a Drupal user account. Only include fields you want to change. Can reassign roles by providing a full replacement role list."
3
3
  argument-hint: "<id> [site] [name] [mail] [password] [status] [roles] [timezone]"
4
- allowed-tools: mcp__drupal__drupal_update_user
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_update_user` MCP tool.
6
+ Call the MCP tool `drupal_update_user`.
8
7
 
9
8
  Update a Drupal user account. Only include fields you want to change. Can reassign roles by providing a full replacement role list.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `id` (string): User UUID
@@ -22,4 +21,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
22
21
  - `roles` (array (pass as JSON)): Full replacement role UUID list
23
22
  - `timezone` (string)
24
23
 
25
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
24
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Convenience tool: upload a local file and immediately create a Media entity in one step. Best for the common 'add an image' workflow. Media defaults to unpublished."
3
3
  argument-hint: "<filePath> <mediaType> <fieldName> [site] [mediaName] [altText] [status]"
4
- allowed-tools: mcp__drupal__drupal_upload_file_and_create_media
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_upload_file_and_create_media` MCP tool.
6
+ Call the MCP tool `drupal_upload_file_and_create_media`.
8
7
 
9
8
  Convenience tool: upload a local file and immediately create a Media entity in one step. Best for the common 'add an image' workflow. Media defaults to unpublished.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `filePath` (string): Local path to the file (must resolve under MCP_UPLOAD_ROOT or the connector working directory)
@@ -21,4 +20,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
21
20
  - `altText` (string): Alt text for image media
22
21
  - `status` (boolean (true/false)): Published flag. Defaults to false. Requires allowPublish when true.
23
22
 
24
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
23
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  description: "Upload a local file to Drupal and create a File entity. Returns the file UUID to use when creating a Media entity. For images, the typical flow is: drupal_upload_file → drupal_create_media."
3
3
  argument-hint: "<filePath> <bundle> <fieldName> [site] [entityType]"
4
- allowed-tools: mcp__drupal__drupal_upload_file
5
4
  ---
6
5
 
7
- Call the `mcp__drupal__drupal_upload_file` MCP tool.
6
+ Call the MCP tool `drupal_upload_file`.
8
7
 
9
8
  Upload a local file to Drupal and create a File entity. Returns the file UUID to use when creating a Media entity. For images, the typical flow is: drupal_upload_file → drupal_create_media.
10
9
 
11
- Parse the request in `$ARGUMENTS` into this tool's parameters:
10
+ Parse the arguments supplied with this command into this tool's parameters:
12
11
 
13
12
  **Required:**
14
13
  - `filePath` (string): Local path to the file (must resolve under MCP_UPLOAD_ROOT or the connector working directory)
@@ -19,4 +18,4 @@ Parse the request in `$ARGUMENTS` into this tool's parameters:
19
18
  - `site` (string): Named site from connector config. Omit only on reads: multi-site configs fall back to defaultSite (often local/dev, not production). Writes require an explicit site when more than one site is configured. Every response includes `_target` { name, baseUrl, source } (`hint` when you passed site, `default` when you did not).
20
19
  - `entityType` (string): Drupal entity type (usually 'media' or 'node')
21
20
 
22
- If a required parameter is missing from `$ARGUMENTS`, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
21
+ If a required parameter is missing, ask before calling — do not invent values. Coerce each value to its JSON type (booleans → true/false, numbers → numeric, object/array → parse JSON), then make the single tool call and summarize the result.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,88 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.9.0] - 2026-08-26
11
+
12
+ ### Fixed
13
+ - **Adapter-contract execute trusts a fresh evaluation (#181).**
14
+ Manifest digests are always hashed (caller-supplied digests are ignored).
15
+ `execute` re-evaluates and will not honor a forged allow. Actor-bound
16
+ approvals cannot be consumed without that actor. Vendor keys are rejected
17
+ on `hints`. `propose` and `policyDigest` use the same relay hint keys as
18
+ evaluate. A required-evidence failure after a backend write rolls the
19
+ mutation back. `publish` with an id updates that entity instead of
20
+ creating a duplicate.
21
+
22
+ ### Added
23
+ - **Provider-neutral adapter contracts and a Drupal conformance kit (#181).**
24
+ Versioned evaluator, relay, approval, evidence-sink, and system-of-record
25
+ contracts live at `src/lib/contracts/` (contract 1.0). Typed decisions
26
+ (`deny` / `allow` / `allow_with_obligations` / `require_approval`), stable
27
+ reason codes, obligations, and execution receipts are verified at that
28
+ seam. Final target-side denial stays authoritative: an upstream allow
29
+ cannot widen local policy. Model and agent vendors are outside the
30
+ contract. The Drupal adapter is the only system-of-record implementation;
31
+ JSON:API and GraphQL remain transport adapters. The offline conformance
32
+ kit covers allowed and denied actions, hostile input, tenant escape,
33
+ required-evidence write failure, replay, and post-condition discrepancy.
34
+ See [docs/adapter-contracts.md](docs/adapter-contracts.md).
35
+
36
+ ## [2.8.0] - 2026-08-25
37
+
38
+ ### Fixed
39
+ - **Iterative updates PATCH an existing working copy (#166).**
40
+ `drupal_update_node`, `drupal_entity_update`, and `drupal_bulk_update`
41
+ resolve `rel:working-copy` before the write. When that alias is
42
+ addressable, both the dryRun probe and the real PATCH use
43
+ `?resourceVersion=rel:working-copy` instead of the canonical URL, so a
44
+ second edit lands on the same forward revision. dryRun can no longer
45
+ succeed when that write would 400. An addressable draft is edited in
46
+ place — the connector does not discard it or tell the caller to publish
47
+ first. The stray-revision case (alias does not resolve, core still
48
+ blocks) still refuses with revision-surgery language (#201). A stale or
49
+ concurrent working-copy 400 is refused without retrying the canonical
50
+ URL. Successful writes include `_revisions: { live, working }` when both
51
+ vids can be read.
52
+ - **`summary` is refused when body has no summary property (#163).**
53
+ `drupal_create_node` and `drupal_update_node` introspect the sampled body
54
+ field before writing `summary`. A `text_long` / `text_formatted` body (or
55
+ an undetermined schema) fails closed with an actionable message to set the
56
+ site's deck field via `fields`. Core `text_with_summary` still accepts
57
+ `summary` and returns `_warnings` with `summary_parameter_deprecated`.
58
+ dryRun uses the same check.
59
+ - **Node writes honor field `allowed_formats` (#168).** Create/update (including
60
+ `dryRun`) resolve Field API `allowed_formats` from JSON:API `field_config`
61
+ and, when that is unavailable, Drush `config:get`. A single allowed format
62
+ is the default when the caller omits `format`. A caller format outside the
63
+ list is refused before mutation. The historical `defaultTextFormat` /
64
+ `full_html` fallback applies only while the list cannot be resolved — never
65
+ when `full_html` is excluded by field config.
66
+
67
+ ### Added
68
+ - **Northbound data-flow budgets bind to principal and target (#179).** Every
69
+ governed tool call that resolves a site now carries request-scoped principal
70
+ and authoritative-target context. Row, byte, page, request, and chained-action
71
+ counters use the same finite defaults as mcp_sentinel (500 results / 8 MiB /
72
+ 600 req/60s / 120 pages/60s) and are keyed by inbound principal + target —
73
+ not by MCP session — so pagination, retries, batching, and a new chain id
74
+ cannot reset them. JSON:API, GraphQL, and the server-tool bridge send the
75
+ source wire contract (`X-MCP-Declared-Ceiling`, narrow-only;
76
+ `X-MCP-Declared-Destination` from the entitlement pair). Denials name a
77
+ stable reason plus a correlation id and do not echo restricted payload.
78
+ Optional `security.declaredCeiling` and `security.readBudgets` override the
79
+ defaults. Stdio / local-operator traffic still sends the declared headers;
80
+ connector-side counters enforce when an inbound OAuth principal is present.
81
+
82
+ ### Changed
83
+ - **Slash-command stubs moved to `.agents/commands/` (#218).** Generated
84
+ `/drupal-*` files are harness-agnostic (protocol tool names, no
85
+ `mcp__drupal__*` `allowed-tools`). `.claude/` is no longer tracked or
86
+ published. `npm run install:commands` copies stubs into operator home
87
+ directories (`~/.claude/commands` with the Claude Code adapter,
88
+ `~/.grok/commands` as-is) so the bare `/drupal-*` form still works
89
+ without a vendor folder in this repo or in a consuming project. The npm
90
+ `files` list now ships `.agents/commands/` instead of `.claude/commands/`.
91
+
10
92
  ## [2.7.4] - 2026-08-18
11
93
 
12
94
  ### Fixed