@ductape/mcp 0.2.1 → 0.2.3
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/dist/index.js +89 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { createRequire } from 'module';
|
|
13
13
|
import { execSync } from 'child_process';
|
|
14
|
+
import { homedir } from 'os';
|
|
15
|
+
import { delimiter, join } from 'path';
|
|
14
16
|
import { z } from 'zod';
|
|
15
17
|
import { executeViaProxy, generateExecutablePayload, getAssetSchemas, } from './proxy-client.js';
|
|
16
18
|
const MODULES = [
|
|
@@ -35,7 +37,24 @@ There are THREE categories of operations. Use the right tool for each:
|
|
|
35
37
|
ductape_cli("cloud connections list")
|
|
36
38
|
ductape_cli("link --product my-product --env dev")
|
|
37
39
|
If the CLI is not installed, ductape_cli will return install instructions automatically.
|
|
38
|
-
NOTE:
|
|
40
|
+
NOTE: App actions are configured in the Workbench UI — there is no CLI command for them.
|
|
41
|
+
Environments DO have CLI commands: ductape_cli("products environments list/get/create/update ...").
|
|
42
|
+
|
|
43
|
+
RESOLVING "No linked project" ERRORS:
|
|
44
|
+
Some commands (declarative sync below, db migrate/schema, products environments *) need a
|
|
45
|
+
linked project — a local .ductape/config.json with a product tag and env slug. The "link"
|
|
46
|
+
command does NOT validate against the server: it just writes that local file. This means you
|
|
47
|
+
can run ductape_cli("link --product <tag> --env <slug>") even before that environment exists on
|
|
48
|
+
the product yet — do not treat "no linked environment exists server-side" as a reason to avoid
|
|
49
|
+
linking first. If the failing command already takes the product tag as an explicit argument
|
|
50
|
+
(e.g. products environments create/update/list/get), linking is not even required for it —
|
|
51
|
+
only commands that need to *infer* the product/env from local project state require a link.
|
|
52
|
+
Also: this MCP server runs the CLI subprocess in the directory named by the DUCTAPE_PROJECT_DIR
|
|
53
|
+
env var (falls back to this server process's own cwd if unset). If a command inexplicably
|
|
54
|
+
reports "no linked project" right after a successful "link" call, the project directory the
|
|
55
|
+
link was written to and the directory this server is running the CLI from may not match — set
|
|
56
|
+
DUCTAPE_PROJECT_DIR explicitly in this server's env (e.g. in the consuming project's .mcp.json)
|
|
57
|
+
to the target project's absolute path.
|
|
39
58
|
|
|
40
59
|
DECLARATIVE SYNC (apply sessions, notifications, events from code; run DB migrations)
|
|
41
60
|
→ Also use ductape_cli. The project must be linked first (ductape init --link).
|
|
@@ -123,9 +142,11 @@ There are THREE categories of operations. Use the right tool for each:
|
|
|
123
142
|
ductape_cli("resources storage list")
|
|
124
143
|
ductape_cli("resources database create -f db-config.json")
|
|
125
144
|
This applies to: products, apps, and resources (databases, storage, caches, etc.),
|
|
126
|
-
cloud connections, and secrets. Environments
|
|
127
|
-
|
|
128
|
-
|
|
145
|
+
cloud connections, and secrets. Environments have their own CLI commands (see below);
|
|
146
|
+
App actions and auths are configured in the Workbench UI. Quotas, fallbacks, jobs, and
|
|
147
|
+
healthchecks are administrative resources managed with ductape_cli("resources <type> ...").
|
|
148
|
+
Features have no CLI create command because their definitions are code-first through
|
|
149
|
+
features.define.
|
|
129
150
|
|
|
130
151
|
⚠ MULTI-ENV REQUIREMENT — applies to ALL product assets (storage, database, cache,
|
|
131
152
|
messageBroker, graph, vector, and any other resource with an envs array):
|
|
@@ -324,9 +345,9 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
|
|
|
324
345
|
IMPORTANT: ALL product.* methods require the access key and will return 403 with a publishable key.
|
|
325
346
|
Use ductape_cli for ALL product operations — never ductape_execute:
|
|
326
347
|
ductape_cli("products get --tag <tag> --json") ← fetch product + full inventory
|
|
327
|
-
ductape_cli("products components list --tag <tag> --json") ← compact non-secret inventory
|
|
328
|
-
ductape_cli("products components get --tag <tag> --type notifications --json")
|
|
329
|
-
ductape_cli("products components get --tag <tag> --type events --json")
|
|
348
|
+
ductape_cli("products components list --product-tag <tag> --json") ← compact non-secret inventory
|
|
349
|
+
ductape_cli("products components get --product-tag <tag> --type notifications --json")
|
|
350
|
+
ductape_cli("products components get --product-tag <tag> --type events --json")
|
|
330
351
|
ductape_cli("products create --name <name> --tag <tag>")
|
|
331
352
|
ductape_cli("products environments list <tag> --json")
|
|
332
353
|
ductape_cli("products environments get <tag> <slug> --json")
|
|
@@ -1157,14 +1178,19 @@ function checkCli() {
|
|
|
1157
1178
|
try {
|
|
1158
1179
|
const out = execSync('ductape --version', {
|
|
1159
1180
|
encoding: 'utf8',
|
|
1160
|
-
timeout:
|
|
1181
|
+
timeout: 15000,
|
|
1161
1182
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1162
1183
|
env: cliEnvironment(),
|
|
1184
|
+
cwd: cliCwd(),
|
|
1163
1185
|
}).trim();
|
|
1164
1186
|
return { available: true, version: out || 'unknown' };
|
|
1165
1187
|
}
|
|
1166
|
-
catch {
|
|
1167
|
-
|
|
1188
|
+
catch (error) {
|
|
1189
|
+
const message = String(error?.stderr || error?.message || error);
|
|
1190
|
+
const commandMissing = error?.code === 'ENOENT' ||
|
|
1191
|
+
error?.status === 127 ||
|
|
1192
|
+
/\b(command not found|not recognized as an internal|no such file or directory)\b/i.test(message);
|
|
1193
|
+
return { available: !commandMissing };
|
|
1168
1194
|
}
|
|
1169
1195
|
}
|
|
1170
1196
|
function checkLoginState() {
|
|
@@ -1177,6 +1203,7 @@ function checkLoginState() {
|
|
|
1177
1203
|
timeout: 10000,
|
|
1178
1204
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1179
1205
|
env: cliEnvironment(),
|
|
1206
|
+
cwd: cliCwd(),
|
|
1180
1207
|
});
|
|
1181
1208
|
authState = 'ok';
|
|
1182
1209
|
return 'ok';
|
|
@@ -1197,6 +1224,7 @@ function syncWorkspace() {
|
|
|
1197
1224
|
timeout: 10000,
|
|
1198
1225
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1199
1226
|
env: cliEnvironment(),
|
|
1227
|
+
cwd: cliCwd(),
|
|
1200
1228
|
});
|
|
1201
1229
|
}
|
|
1202
1230
|
catch {
|
|
@@ -1225,6 +1253,7 @@ function runCli(command) {
|
|
|
1225
1253
|
timeout: 90000,
|
|
1226
1254
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1227
1255
|
env: cliEnvironment(),
|
|
1256
|
+
cwd: cliCwd(),
|
|
1228
1257
|
});
|
|
1229
1258
|
return { success: true, output: output.trim() };
|
|
1230
1259
|
}
|
|
@@ -1276,8 +1305,33 @@ function runCli(command) {
|
|
|
1276
1305
|
function cliEnvironment() {
|
|
1277
1306
|
const environment = { ...process.env };
|
|
1278
1307
|
delete environment.DUCTAPE_ACCESS_KEY;
|
|
1308
|
+
const pathKey = Object.keys(environment).find((key) => key.toLowerCase() === 'path') ?? 'PATH';
|
|
1309
|
+
const configuredPath = environment[pathKey] ?? '';
|
|
1310
|
+
const fallbackBins = [
|
|
1311
|
+
join(homedir(), '.npm-global', 'bin'),
|
|
1312
|
+
join(homedir(), '.local', 'bin'),
|
|
1313
|
+
'/opt/homebrew/bin',
|
|
1314
|
+
'/usr/local/bin',
|
|
1315
|
+
];
|
|
1316
|
+
environment[pathKey] = [...new Set([
|
|
1317
|
+
...configuredPath.split(delimiter).filter(Boolean),
|
|
1318
|
+
...fallbackBins,
|
|
1319
|
+
])].join(delimiter);
|
|
1279
1320
|
return environment;
|
|
1280
1321
|
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Directory the `ductape` CLI subprocess runs in. Commands that resolve a linked project
|
|
1324
|
+
* (findProjectConfig walking up from cwd — e.g. `products environments *`, `apply`, `db migrate`)
|
|
1325
|
+
* depend on this being the user's actual project directory, not wherever this MCP server process
|
|
1326
|
+
* itself happened to be spawned from. execSync inherits process.cwd() when no cwd is given, which
|
|
1327
|
+
* is only correct if this server was started from inside the target project — that doesn't hold
|
|
1328
|
+
* for every launch path (e.g. a host attaching this server to an already-running session whose
|
|
1329
|
+
* cwd is unrelated to the project). Set DUCTAPE_PROJECT_DIR explicitly in the server's env
|
|
1330
|
+
* (e.g. in .mcp.json) to pin it; falls back to this process's own cwd otherwise.
|
|
1331
|
+
*/
|
|
1332
|
+
function cliCwd() {
|
|
1333
|
+
return process.env.DUCTAPE_PROJECT_DIR || process.cwd();
|
|
1334
|
+
}
|
|
1281
1335
|
function shellArgument(value) {
|
|
1282
1336
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
1283
1337
|
}
|
|
@@ -1376,10 +1430,12 @@ ENVIRONMENTS
|
|
|
1376
1430
|
(production→prd, sandbox→snd, staging→stg) but present uncertain mappings for confirmation.
|
|
1377
1431
|
Before creating any asset, list product environments and require complete per-environment coverage.
|
|
1378
1432
|
Missing environments can be created idempotently through the authenticated standalone CLI:
|
|
1379
|
-
ductape_cli("products environments create <product-tag> -
|
|
1433
|
+
ductape_cli("products environments create <product-tag> --env-file <environment.json> --json")
|
|
1380
1434
|
The JSON requires env_name, description, and a three-character slug. The CLI fetches first, creates only
|
|
1381
|
-
when absent, then fetches again to verify persistence
|
|
1382
|
-
|
|
1435
|
+
when absent, then fetches again to verify persistence (with a short retry on the verification read to
|
|
1436
|
+
absorb replication lag). No linked project is required — the product tag is always the explicit argument.
|
|
1437
|
+
Update and verify with:
|
|
1438
|
+
ductape_cli("products environments update <product-tag> <slug> --env-file <patch.json> --json")
|
|
1383
1439
|
Export authenticated inventory with ductape_cli("products environments list <product-tag> --json"),
|
|
1384
1440
|
save it as evidence, then reconcile locally:
|
|
1385
1441
|
ductape_cli("migration-environments --analysis <analysis.json> --inventory <inventory.json> --strict --json")
|
|
@@ -2751,10 +2807,13 @@ Resilience covers three mechanisms: quotas (rate-limited provider pools), fallba
|
|
|
2751
2807
|
provider switching), and healthchecks (continuous probe monitoring with failure actions).
|
|
2752
2808
|
|
|
2753
2809
|
CONFIGURATION BOUNDARY
|
|
2754
|
-
Quotas, fallbacks, and health checks are administrative product configuration.
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2810
|
+
Quotas, fallbacks, and health checks are administrative product configuration. Manage them with
|
|
2811
|
+
the authenticated CLI:
|
|
2812
|
+
ductape_cli("resources quota ...")
|
|
2813
|
+
ductape_cli("resources fallback ...")
|
|
2814
|
+
ductape_cli("resources health ...")
|
|
2815
|
+
Workbench is also supported. Never route their administrative create/update methods through
|
|
2816
|
+
ductape_execute: its publishable-key runtime proxy will fail.
|
|
2758
2817
|
|
|
2759
2818
|
QUOTAS — rate-limited multi-provider pools:
|
|
2760
2819
|
Workbench definition shape:
|
|
@@ -4294,9 +4353,12 @@ const cliInputSchema = z.object({
|
|
|
4294
4353
|
'Use this tool for administrative operations: creating or updating products, apps, ' +
|
|
4295
4354
|
'resources (databases, storage, caches…), event broker topics, cloud connections, secrets, ' +
|
|
4296
4355
|
'and for apply/migrate workflows.\n\n' +
|
|
4297
|
-
'Note: environments
|
|
4298
|
-
'
|
|
4299
|
-
'
|
|
4356
|
+
'Note: environments have their own CLI commands (products environments list/get/create/update, ' +
|
|
4357
|
+
'no linked project required — the product tag is always an explicit argument). Quotas, ' +
|
|
4358
|
+
'fallbacks, jobs, and healthchecks use resources commands. App actions and auths are ' +
|
|
4359
|
+
'configured in the Workbench UI. Features have no CLI ' +
|
|
4360
|
+
'creation command: define them in application code with features.define so application ' +
|
|
4361
|
+
'boot/runtime registration makes them available.\n\n' +
|
|
4300
4362
|
'The CLI uses the user\'s local logged-in session (ductape login) — no key is required.'),
|
|
4301
4363
|
});
|
|
4302
4364
|
async function loadMcpSdk() {
|
|
@@ -4748,15 +4810,17 @@ async function main() {
|
|
|
4748
4810
|
' type field = "messageBrokers" (not "messagebrokers" or "events").\n' +
|
|
4749
4811
|
' After importing, create topics first with ductape_cli("events topics create -f topic.json") — SQS requires explicit topic creation with queueUrls. For other providers, topics auto-register on first produce but should still be created explicitly before any consumer subscribes.\n' +
|
|
4750
4812
|
' - Listing workspaces, products, focused product components, secrets\n' +
|
|
4751
|
-
' Prefer "products components list --tag <tag> --json" for compact inventory; use\n' +
|
|
4752
|
-
' "products components get --tag <tag> --type notifications|events --json" for focused detail.\n' +
|
|
4813
|
+
' Prefer "products components list --product-tag <tag> --json" for compact inventory; use\n' +
|
|
4814
|
+
' "products components get --product-tag <tag> --type notifications|events|healthchecks|features --json" for focused detail.\n' +
|
|
4753
4815
|
' - Managing notification components and message templates through "resources notifications" and "notifications messages"\n' +
|
|
4754
4816
|
' - Linking a project folder: "link --product <tag> --env <slug>"\n' +
|
|
4755
4817
|
' - Syncing sessions/notifications/events: "apply" or "apply sessions" etc.\n' +
|
|
4756
4818
|
' - Running database migrations: "db migrate", "db schema generate"\n\n' +
|
|
4757
|
-
'NOTE: Environments
|
|
4758
|
-
'in the Workbench UI.
|
|
4759
|
-
'
|
|
4819
|
+
'NOTE: Environments have their own CLI commands (products environments *). App actions ' +
|
|
4820
|
+
'and auths are configured in the Workbench UI. Quotas, fallbacks, jobs, and healthchecks ' +
|
|
4821
|
+
'are managed with resources commands. Features have no ' +
|
|
4822
|
+
'CLI creation command because definitions are code-first through features.define and ' +
|
|
4823
|
+
'registered by the application runtime.\n\n' +
|
|
4760
4824
|
'DO NOT use ductape_execute for admin operations — it uses a publishable key which only ' +
|
|
4761
4825
|
'covers runtime operations. Administrative operations will fail with "Authentication failed".\n\n' +
|
|
4762
4826
|
'The CLI uses the user\'s local logged-in session (ductape login). ' +
|