drupal-mcp-connector 2.18.0 → 2.19.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/.agents/commands/drupal-codegen-diff.md +2 -2
- package/.agents/commands/drupal-codegen-generate.md +2 -2
- package/.agents/commands/drupal-codegen-inspect.md +2 -2
- package/.agents/commands/drupal-drush-sql-query.md +2 -2
- package/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/tools/codegen.js +18 -4
- package/src/tools/drush.js +11 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`).
|
|
2
|
+
description: "Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:diff."
|
|
3
3
|
argument-hint: "[site] [bundles] [skipFields]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Call the MCP tool `drupal_codegen_diff`.
|
|
7
7
|
|
|
8
|
-
Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`).
|
|
8
|
+
Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:diff.
|
|
9
9
|
|
|
10
10
|
Parse the arguments supplied with this command into this tool's parameters:
|
|
11
11
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally.
|
|
2
|
+
description: "Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally. Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:generate."
|
|
3
3
|
argument-hint: "[site] [bundles] [skipFields]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Call the MCP tool `drupal_codegen_generate`.
|
|
7
7
|
|
|
8
|
-
Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally.
|
|
8
|
+
Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally. Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:generate.
|
|
9
9
|
|
|
10
10
|
Parse the arguments supplied with this command into this tool's parameters:
|
|
11
11
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`).
|
|
2
|
+
description: "List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:inspect. Does not write files."
|
|
3
3
|
argument-hint: "[site] [bundles] [skipFields]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Call the MCP tool `drupal_codegen_inspect`.
|
|
7
7
|
|
|
8
|
-
List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`).
|
|
8
|
+
List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:inspect. Does not write files.
|
|
9
9
|
|
|
10
10
|
Parse the arguments supplied with this command into this tool's parameters:
|
|
11
11
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Run a single read-only SELECT through
|
|
2
|
+
description: "Run a single read-only SELECT through the configured sqlQuery module binding, or the legacy governed Drush command on unbound sites. Requires the site to set drushSsh.rawSql=\"governed\" AND the site's policy profile to set allow_raw_sql; both are off by default. The server refuses statements touching a denied entity type, a non-entity table, or a redacted field, and records every attempt in the tamper-evident audit log. Use the site-context or entity-schema tools for schema introspection."
|
|
3
3
|
argument-hint: "<query> [site]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Call the MCP tool `drupal_drush_sql_query`.
|
|
7
7
|
|
|
8
|
-
Run a single read-only SELECT through
|
|
8
|
+
Run a single read-only SELECT through the configured sqlQuery module binding, or the legacy governed Drush command on unbound sites. Requires the site to set drushSsh.rawSql="governed" AND the site's policy profile to set allow_raw_sql; both are off by default. The server refuses statements touching a denied entity type, a non-entity table, or a redacted field, and records every attempt in the tamper-evident audit log. Use the site-context or entity-schema tools for schema introspection.
|
|
9
9
|
|
|
10
10
|
Parse the arguments supplied with this command into this tool's parameters:
|
|
11
11
|
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.19.0] - 2026-09-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Codegen and governed SQL compatibility commands can use module-owned Tool API
|
|
14
|
+
actions through explicit bindings (#317). Configured calls validate fresh
|
|
15
|
+
schemas and never fall back to SSH on failure. Core and third-party commands
|
|
16
|
+
remain available; unbound sites retain their existing migration path.
|
|
17
|
+
|
|
10
18
|
## [2.18.0] - 2026-09-16
|
|
11
19
|
|
|
12
20
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drupal-mcp-connector",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "Drupal MCP Connector — multi-site MCP server for Drupal with JSON:API and GraphQL, governed writes, draft translations, content tools, audit reports, and an SSH Drush bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/tools/codegen.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool group: GraphQL Compose Codegen (TypeScript / Next.js scaffolds).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Compatibility adapters through configured module bindings, or legacy Drush.
|
|
5
|
+
* Thin wrappers around `drupal/graphql_compose_codegen`. The generator
|
|
5
6
|
* lives on the Drupal site; this connector does not reimplement it and does
|
|
6
7
|
* not run GraphQL Code Generator against the SDL.
|
|
7
8
|
*
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
|
|
17
18
|
import { getSiteConfig } from "../lib/config.js";
|
|
18
19
|
import { sshDrush } from "./drush.js";
|
|
20
|
+
import { callBoundModuleTool, toolResultData } from "../lib/server-tools.js";
|
|
19
21
|
import { SecurityError } from "../lib/security.js";
|
|
20
22
|
import { validateMachineName } from "../lib/validate.js";
|
|
21
23
|
|
|
@@ -75,6 +77,18 @@ async function runGqcc(
|
|
|
75
77
|
const site = getSiteConfig(siteName);
|
|
76
78
|
const names = parseMachineNameList(bundles, "bundles");
|
|
77
79
|
const skip = parseMachineNameList(skipFields, "skipFields");
|
|
80
|
+
if (site.serverTools?.bindings !== undefined) {
|
|
81
|
+
const binding = new Map([
|
|
82
|
+
[INSPECT, "codegenInspect"], [DIFF, "codegenDiff"], [GENERATE, "codegenPreview"],
|
|
83
|
+
]).get(subcommand);
|
|
84
|
+
const result = toolResultData(await callBoundModuleTool(site, binding, {
|
|
85
|
+
bundles: names, skip_fields: skip,
|
|
86
|
+
}, { operation: "read", scope: "mcp_config", capabilities: ["configRead"] }));
|
|
87
|
+
if (result?.success !== true || !result.data || typeof result.data !== "object" || Array.isArray(result.data)) {
|
|
88
|
+
throw new SecurityError("Codegen module returned an invalid result. No SSH fallback was attempted.");
|
|
89
|
+
}
|
|
90
|
+
return { output: JSON.stringify(result.data), command: `module:${binding}`, wroteFiles: false };
|
|
91
|
+
}
|
|
78
92
|
const args = [subcommand];
|
|
79
93
|
if (names.length) args.push(`--bundles=${names.join(",")}`);
|
|
80
94
|
if (skip.length) args.push(`--skip-fields=${skip.join(",")}`);
|
|
@@ -126,19 +140,19 @@ export const definitions = [
|
|
|
126
140
|
{
|
|
127
141
|
name: "drupal_codegen_inspect",
|
|
128
142
|
description:
|
|
129
|
-
"List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`).
|
|
143
|
+
"List node and paragraph bundles and extra fields from graphql_compose_codegen (`drush graphql-compose-codegen:inspect`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:inspect. Does not write files.",
|
|
130
144
|
inputSchema: { type: "object", properties: LIST_PROPS },
|
|
131
145
|
},
|
|
132
146
|
{
|
|
133
147
|
name: "drupal_codegen_diff",
|
|
134
148
|
description:
|
|
135
|
-
"Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`).
|
|
149
|
+
"Compare the live graphql_compose schema to the last gqcc:generate snapshot (`drush graphql-compose-codegen:diff`). Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:diff.",
|
|
136
150
|
inputSchema: { type: "object", properties: LIST_PROPS },
|
|
137
151
|
},
|
|
138
152
|
{
|
|
139
153
|
name: "drupal_codegen_generate",
|
|
140
154
|
description:
|
|
141
|
-
"Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally.
|
|
155
|
+
"Return TypeScript/GraphQL scaffold artefacts from graphql_compose_codegen as text (`drush graphql-compose-codegen:generate --dry-run`). Never writes on the Drupal host (no --output-dir). Copy artefacts locally. Uses the configured module binding; unbound sites require the module and drushSsh. Missing command fails loud. If allowedCommands is set, include graphql-compose-codegen:generate.",
|
|
142
156
|
inputSchema: { type: "object", properties: LIST_PROPS },
|
|
143
157
|
},
|
|
144
158
|
];
|
package/src/tools/drush.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Requires per-site "drushSsh" config block — tools fail gracefully if absent.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { callBoundModuleTool, toolResultData } from "../lib/server-tools.js";
|
|
23
24
|
import { Client } from "ssh2";
|
|
24
25
|
import { readFileSync } from "fs";
|
|
25
26
|
import { homedir } from "os";
|
|
@@ -456,6 +457,15 @@ async function sqlQuery({ site: siteName, query }) {
|
|
|
456
457
|
assertGovernedRawSql(sshCfg, site._name);
|
|
457
458
|
// Fast local reject only; mcp_sentinel's guard is the authority.
|
|
458
459
|
validateSqlQuery(query);
|
|
460
|
+
if (site.serverTools?.bindings !== undefined) {
|
|
461
|
+
const result = toolResultData(await callBoundModuleTool(site, "sqlQuery", { query }, {
|
|
462
|
+
operation: "read", scope: "mcp_admin", capabilities: ["rawSql"],
|
|
463
|
+
}));
|
|
464
|
+
if (result?.success !== true || !result.data || !Array.isArray(result.data.rows)) {
|
|
465
|
+
throw new SecurityError("SQL module returned an invalid governed result. No SSH fallback was attempted.");
|
|
466
|
+
}
|
|
467
|
+
return result.data;
|
|
468
|
+
}
|
|
459
469
|
const out = await sshDrush(site, ["mcp-sentinel:sql-query", query]);
|
|
460
470
|
// The command emits a JSON object; a non-JSON reply means the command was
|
|
461
471
|
// not found (mcp_sentinel absent or too old), which must not be reported as
|
|
@@ -534,7 +544,7 @@ export const definitions = [
|
|
|
534
544
|
},
|
|
535
545
|
{
|
|
536
546
|
name: "drupal_drush_sql_query",
|
|
537
|
-
description: "Run a single read-only SELECT through
|
|
547
|
+
description: "Run a single read-only SELECT through the configured sqlQuery module binding, or the legacy governed Drush command on unbound sites. Requires the site to set drushSsh.rawSql=\"governed\" AND the site's policy profile to set allow_raw_sql; both are off by default. The server refuses statements touching a denied entity type, a non-entity table, or a redacted field, and records every attempt in the tamper-evident audit log. Use the site-context or entity-schema tools for schema introspection.",
|
|
538
548
|
inputSchema: { type: "object", required: ["query"], properties: { site: { type: "string" }, query: { type: "string" } } },
|
|
539
549
|
},
|
|
540
550
|
{
|