drupal-mcp-connector 1.1.0 → 1.2.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.0] - 2026-06-27
11
+
12
+ ### Changed
13
+ - Widened the content/developer security presets so the connector supports full content
14
+ building and management. `content-editor` and `write-plane` now allow `paragraph`,
15
+ `block_content`, `menu_link_content`, `redirect`, `path_alias`, and `file` in addition
16
+ to `node`/`taxonomy_term`/`media`. `config-editor` (developer tier) additionally allows
17
+ the site-building config entities (`node_type`, `paragraphs_type`, `block_content_type`,
18
+ `media_type`, `field_config`, `field_storage_config`, `entity_form_display`,
19
+ `entity_view_display`, `taxonomy_vocabulary`) for read/introspection — content-model
20
+ changes go through the governed config bridge / `drush config:import`, not JSON:API
21
+ entity create.
22
+ - Corrected the server-tool bridge tool names: `mcp_server_tool_bridge` exposes Tool-API
23
+ tools as `tool_api.<id>`, so the governed config tools are
24
+ `tool_api.mcp_sentinel_config_get` / `_list` / `_set` (previously documented as bare
25
+ `config_get` / `_list` / `_set`, which never resolved). Updated `SERVER_TOOLS` and
26
+ `docs/integration-contract.md` accordingly. These tools must be registered as enabled
27
+ `mcp_tool_config` entities on the Drupal site; they are not exposed by default.
28
+
29
+ ### Security
30
+ - Deny-hardened the content/developer presets: `oauth2_token`, `key`, `consumer`,
31
+ `encryption_profile`, `mcp_tool_config`, and `mcp_policy_profile` are now in
32
+ `deniedEntityTypes` alongside `user`, so secrets, the agent's own governance config,
33
+ and account data stay blocked even if an allowlist is later widened. PII-bearing
34
+ `webform_submission` and `profile` are intentionally left off the allowlists.
35
+
36
+ ## [1.1.1] - 2026-06-26
37
+
38
+ ### Fixed
39
+ - Docs: corrected stale tool/module counts (89→93, 20→21) and the example startup
40
+ banner version (v1.0.0→v1.1.0) in `architecture.md`, `getting-started.md`,
41
+ `whitepaper.md`, and `tools-reference.md` after the 1.1.0 release.
42
+
10
43
  ## [1.1.0] - 2026-06-26
11
44
 
12
45
  ### Security
@@ -100,11 +100,11 @@
100
100
 
101
101
  "_security_presets": {
102
102
  "development": "All operations allowed, incl. config read/write. Local dev / break-glass only.",
103
- "content-editor": "Create/edit nodes+media+terms. No deletes. No user entity access. Config read-only.",
104
- "config-editor": "content-editor + governed config read/write (Developer tier).",
103
+ "content-editor": "Create/edit the full content set (node, media, taxonomy_term, paragraph, block_content, menu_link_content, redirect, path_alias, file). No deletes. Config read-only. Denies user + secrets/governance types.",
104
+ "config-editor": "content-editor + site-building config entities (read/introspection) + governed config read/write (Developer tier). Model changes go via the config bridge, not JSON:API.",
105
105
  "auditor": "Read-only. All entity types. User PII fields redacted. Config read-only.",
106
106
  "production-strict": "Read-only. No user entities. Broad PII redaction. No config access.",
107
- "write-plane": "Governed writes (no delete/mutations) on node, taxonomy_term, media. No user. Redacts pass/mail. Config read-only."
107
+ "write-plane": "Governed writes (no delete/mutations) on the content set (node, taxonomy_term, media + structural content entities). Denies user + secrets/governance types. Redacts pass/mail. Config read-only."
108
108
  },
109
109
 
110
110
  "_server_tools": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drupal-mcp-connector",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A secure, multi-site Model Context Protocol (MCP) connector for Drupal — dual-protocol JSON:API and GraphQL.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -13,11 +13,17 @@ import { parse } from "graphql";
13
13
  * ─── Quick presets ────────────────────────────────────────────────────────
14
14
  *
15
15
  * "preset": "development" Everything allowed. Default if no security key.
16
- * "preset": "content-editor" Create/edit nodes+media. No user mgmt, no deletes. Config read-only.
17
- * "preset": "config-editor" content-editor + governed config read/write (Developer tier).
16
+ * "preset": "content-editor" Create/edit content (nodes, media, terms, paragraphs, blocks,
17
+ * menu links, redirects, aliases, files). No deletes. Config read-only.
18
+ * "preset": "config-editor" content-editor + site-building config READ + governed config
19
+ * read/write (Developer tier). Model changes go via the config bridge.
18
20
  * "preset": "auditor" Read-only. All entity types. User fields redacted.
19
21
  * "preset": "production-strict" Read-only. Explicit allowlist required. Redacts PII.
20
- * "preset": "write-plane" Governed writes (no delete/mutations) on node, term, media.
22
+ * "preset": "write-plane" Governed writes (no delete/mutations) on the content set
23
+ * (node, term, media + structural content entities).
24
+ *
25
+ * Secrets, the agent's own governance config, and account data (see SENSITIVE_DENY)
26
+ * are always denied on the content/developer tiers, regardless of the allowlist.
21
27
  *
22
28
  * Presets can be overridden by adding explicit keys alongside them.
23
29
  *
@@ -51,6 +57,57 @@ import { parse } from "graphql";
51
57
  * The connector never writes these fields either when redaction is active.
52
58
  */
53
59
 
60
+ // ---------------------------------------------------------------------------
61
+ // Shared entity-type groups
62
+ // ---------------------------------------------------------------------------
63
+ //
64
+ // The connector allowlist is deliberately safe-by-default: the Drupal site
65
+ // exposes secret-, governance-, and PII-bearing entity types over JSON:API
66
+ // (oauth2_token, key, consumer, mcp_tool_config, profile, webform_submission,
67
+ // …), so anything not explicitly listed stays denied. Widen these groups to
68
+ // grant capability; never flip a content/developer tier to allowedEntityTypes:
69
+ // null.
70
+
71
+ // Content (fieldable) entities used to build and manage page content. All are
72
+ // JSON:API-writable, so the standard entity tools create/update them directly.
73
+ const CONTENT_STRUCTURAL = [
74
+ "paragraph",
75
+ "block_content",
76
+ "menu_link_content",
77
+ "redirect",
78
+ "path_alias",
79
+ "file",
80
+ ];
81
+
82
+ // Content-model *config* entities. Allowlisted for READ / introspection only —
83
+ // they are config entities, so building/changing them goes through the governed
84
+ // config bridge (config_set → mcp_sentinel) or `drush config:import`, NOT
85
+ // drupal_entity_create. Granted to the developer tier only.
86
+ const SITE_BUILDER_CONFIG = [
87
+ "node_type",
88
+ "paragraphs_type",
89
+ "block_content_type",
90
+ "media_type",
91
+ "field_config",
92
+ "field_storage_config",
93
+ "entity_form_display",
94
+ "entity_view_display",
95
+ "taxonomy_vocabulary",
96
+ ];
97
+
98
+ // Always-blocked: secrets, the agent's own governance config, and account data.
99
+ // Belt-and-suspenders denylist — these stay blocked even if a future change
100
+ // widens an allowlist. (deniedEntityTypes takes priority over allowedEntityTypes.)
101
+ const SENSITIVE_DENY = [
102
+ "user",
103
+ "oauth2_token",
104
+ "key",
105
+ "consumer",
106
+ "encryption_profile",
107
+ "mcp_tool_config",
108
+ "mcp_policy_profile",
109
+ ];
110
+
54
111
  // ---------------------------------------------------------------------------
55
112
  // Preset definitions
56
113
  // ---------------------------------------------------------------------------
@@ -74,8 +131,10 @@ const PRESETS = {
74
131
  allowGraphqlMutations: false,
75
132
  allowConfigRead: true, // config read-only
76
133
  allowConfigWrite: false,
77
- allowedEntityTypes: ["node", "media", "file", "taxonomy_term", "menu_link_content"],
78
- deniedEntityTypes: ["user"],
134
+ // Full content building: base content types + structural content entities
135
+ // (paragraphs, custom blocks, menu links, redirects, aliases, files).
136
+ allowedEntityTypes: ["node", "media", "taxonomy_term", ...CONTENT_STRUCTURAL],
137
+ deniedEntityTypes: [...SENSITIVE_DENY],
79
138
  entityRules: {
80
139
  node: { allowedOperations: ["read", "create", "update"] },
81
140
  media: { allowedOperations: ["read", "create", "update"] },
@@ -93,8 +152,11 @@ const PRESETS = {
93
152
  allowGraphqlMutations: false,
94
153
  allowConfigRead: true,
95
154
  allowConfigWrite: true, // governed config writes via drupal_config_set
96
- allowedEntityTypes: ["node", "media", "file", "taxonomy_term", "menu_link_content"],
97
- deniedEntityTypes: ["user"],
155
+ // content-editor's content set PLUS site-building config entities, the
156
+ // latter for READ / introspection only — model changes go through the
157
+ // governed config bridge (drupal_config_set) / drush config:import.
158
+ allowedEntityTypes: ["node", "media", "taxonomy_term", ...CONTENT_STRUCTURAL, ...SITE_BUILDER_CONFIG],
159
+ deniedEntityTypes: [...SENSITIVE_DENY],
98
160
  entityRules: {
99
161
  node: { allowedOperations: ["read", "create", "update"] },
100
162
  media: { allowedOperations: ["read", "create", "update"] },
@@ -141,8 +203,10 @@ const PRESETS = {
141
203
  allowGraphqlMutations: false, // writes go through the JSON:API plane
142
204
  allowConfigRead: true, // config read-only
143
205
  allowConfigWrite: false,
144
- allowedEntityTypes: ["node", "taxonomy_term", "media"],
145
- deniedEntityTypes: ["user"],
206
+ // Full content building on the content tier: base content + structural
207
+ // content entities. No site-building config entities (developer tier only).
208
+ allowedEntityTypes: ["node", "taxonomy_term", "media", ...CONTENT_STRUCTURAL],
209
+ deniedEntityTypes: [...SENSITIVE_DENY],
146
210
  entityRules: {},
147
211
  globalRedactedFields: ["pass", "mail"],
148
212
  },
@@ -25,12 +25,17 @@ import { clearToken } from "./oauth.js";
25
25
 
26
26
  /**
27
27
  * Canonical server-side tool names for governed config operations.
28
- * Keep the mapping here so a server-side rename is a one-line change.
28
+ *
29
+ * Drupal's mcp_server_tool_bridge exposes every Tool-API tool through the MCP
30
+ * protocol under the derivative name `tool_api.<mcp_tool_config id>`, so the
31
+ * governed config tools registered against mcp_sentinel's McpConfigGet/List/Set
32
+ * plugins surface as `tool_api.mcp_sentinel_config_*`. Keep the mapping here so
33
+ * a server-side rename is a one-line change.
29
34
  */
30
35
  export const SERVER_TOOLS = {
31
- configGet: "config_get",
32
- configList: "config_list",
33
- configSet: "config_set",
36
+ configGet: "tool_api.mcp_sentinel_config_get",
37
+ configList: "tool_api.mcp_sentinel_config_list",
38
+ configSet: "tool_api.mcp_sentinel_config_set",
34
39
  };
35
40
 
36
41
  // Monotonic JSON-RPC request id. A simple counter keeps ids unique per process